diff --git a/[refs] b/[refs] index c90baa9c0d11..bb997f8b2c5d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 29bd17af7d8ffc16bb5eb286947495c166ea826e +refs/heads/master: 946fef4e14ebc2f14ab05f54789843621fe87f60 diff --git a/trunk/Documentation/DocBook/videobook.tmpl b/trunk/Documentation/DocBook/videobook.tmpl index b3d93ee27693..b629da33951d 100644 --- a/trunk/Documentation/DocBook/videobook.tmpl +++ b/trunk/Documentation/DocBook/videobook.tmpl @@ -96,6 +96,7 @@ static struct video_device my_radio { "My radio", VID_TYPE_TUNER, + VID_HARDWARE_MYRADIO, radio_open. radio_close, NULL, /* no read */ @@ -117,6 +118,13 @@ static struct video_device my_radio indicates that the device can be tuned. Clearly our radio is going to have some way to change channel so it is tuneable. + + The VID_HARDWARE_ types are unique to each device. Numbers are assigned by + alan@redhat.com when device drivers are going to be released. Until then you + can pull a suitably large number out of your hat and use it. 10000 should be + safe for a very long time even allowing for the huge number of vendors + making new and different radio cards at the moment. + We declare an open and close routine, but we do not need read or write, which are used to read and write video data to or from the card itself. As @@ -836,6 +844,7 @@ static struct video_device my_camera "My Camera", VID_TYPE_OVERLAY|VID_TYPE_SCALES|\ VID_TYPE_CAPTURE|VID_TYPE_CHROMAKEY, + VID_HARDWARE_MYCAMERA, camera_open. camera_close, camera_read, /* no read */ diff --git a/trunk/Documentation/RCU/RTFP.txt b/trunk/Documentation/RCU/RTFP.txt index 39ad8f56783a..6221464d1a7e 100644 --- a/trunk/Documentation/RCU/RTFP.txt +++ b/trunk/Documentation/RCU/RTFP.txt @@ -9,8 +9,8 @@ The first thing resembling RCU was published in 1980, when Kung and Lehman [Kung80] recommended use of a garbage collector to defer destruction of nodes in a parallel binary search tree in order to simplify its implementation. This works well in environments that have garbage -collectors, but most production garbage collectors incur significant -overhead. +collectors, but current production garbage collectors incur significant +read-side overhead. In 1982, Manber and Ladner [Manber82,Manber84] recommended deferring destruction until all threads running at that time have terminated, again @@ -99,25 +99,16 @@ locking, reduces contention, reduces memory latency for readers, and parallelizes pipeline stalls and memory latency for writers. However, these techniques still impose significant read-side overhead in the form of memory barriers. Researchers at Sun worked along similar lines -in the same timeframe [HerlihyLM02]. These techniques can be thought -of as inside-out reference counts, where the count is represented by the -number of hazard pointers referencing a given data structure (rather than -the more conventional counter field within the data structure itself). - -By the same token, RCU can be thought of as a "bulk reference count", -where some form of reference counter covers all reference by a given CPU -or thread during a set timeframe. This timeframe is related to, but -not necessarily exactly the same as, an RCU grace period. In classic -RCU, the reference counter is the per-CPU bit in the "bitmask" field, -and each such bit covers all references that might have been made by -the corresponding CPU during the prior grace period. Of course, RCU -can be thought of in other terms as well. +in the same timeframe [HerlihyLM02,HerlihyLMS03]. These techniques +can be thought of as inside-out reference counts, where the count is +represented by the number of hazard pointers referencing a given data +structure (rather than the more conventional counter field within the +data structure itself). In 2003, the K42 group described how RCU could be used to create -hot-pluggable implementations of operating-system functions [Appavoo03a]. -Later that year saw a paper describing an RCU implementation of System -V IPC [Arcangeli03], and an introduction to RCU in Linux Journal -[McKenney03a]. +hot-pluggable implementations of operating-system functions. Later that +year saw a paper describing an RCU implementation of System V IPC +[Arcangeli03], and an introduction to RCU in Linux Journal [McKenney03a]. 2004 has seen a Linux-Journal article on use of RCU in dcache [McKenney04a], a performance comparison of locking to RCU on several @@ -126,19 +117,10 @@ number of operating-system kernels [PaulEdwardMcKenneyPhD], a paper describing how to make RCU safe for soft-realtime applications [Sarma04c], and a paper describing SELinux performance with RCU [JamesMorris04b]. -2005 brought further adaptation of RCU to realtime use, permitting +2005 has seen further adaptation of RCU to realtime use, permitting preemption of RCU realtime critical sections [PaulMcKenney05a, PaulMcKenney05b]. -2006 saw the first best-paper award for an RCU paper [ThomasEHart2006a], -as well as further work on efficient implementations of preemptible -RCU [PaulEMcKenney2006b], but priority-boosting of RCU read-side critical -sections proved elusive. An RCU implementation permitting general -blocking in read-side critical sections appeared [PaulEMcKenney2006c], -Robert Olsson described an RCU-protected trie-hash combination -[RobertOlsson2006a]. - - Bibtex Entries @article{Kung80 @@ -221,41 +203,6 @@ Bibtex Entries ,Address="New Orleans, LA" } -@conference{Pu95a, -Author = "Calton Pu and Tito Autrey and Andrew Black and Charles Consel and -Crispin Cowan and Jon Inouye and Lakshmi Kethana and Jonathan Walpole and -Ke Zhang", -Title = "Optimistic Incremental Specialization: Streamlining a Commercial -Operating System", -Booktitle = "15\textsuperscript{th} ACM Symposium on -Operating Systems Principles (SOSP'95)", -address = "Copper Mountain, CO", -month="December", -year="1995", -pages="314-321", -annotation=" - Uses a replugger, but with a flag to signal when people are - using the resource at hand. Only one reader at a time. -" -} - -@conference{Cowan96a, -Author = "Crispin Cowan and Tito Autrey and Charles Krasic and -Calton Pu and Jonathan Walpole", -Title = "Fast Concurrent Dynamic Linking for an Adaptive Operating System", -Booktitle = "International Conference on Configurable Distributed Systems -(ICCDS'96)", -address = "Annapolis, MD", -month="May", -year="1996", -pages="108", -isbn="0-8186-7395-8", -annotation=" - Uses a replugger, but with a counter to signal when people are - using the resource at hand. Allows multiple readers. -" -} - @techreport{Slingwine95 ,author="John D. Slingwine and Paul E. McKenney" ,title="Apparatus and Method for Achieving Reduced Overhead Mutual @@ -365,49 +312,6 @@ Andrea Arcangeli and Andi Kleen and Orran Krieger and Rusty Russell" [Viewed June 23, 2004]" } -@conference{Michael02a -,author="Maged M. Michael" -,title="Safe Memory Reclamation for Dynamic Lock-Free Objects Using Atomic -Reads and Writes" -,Year="2002" -,Month="August" -,booktitle="{Proceedings of the 21\textsuperscript{st} Annual ACM -Symposium on Principles of Distributed Computing}" -,pages="21-30" -,annotation=" - Each thread keeps an array of pointers to items that it is - currently referencing. Sort of an inside-out garbage collection - mechanism, but one that requires the accessing code to explicitly - state its needs. Also requires read-side memory barriers on - most architectures. -" -} - -@conference{Michael02b -,author="Maged M. Michael" -,title="High Performance Dynamic Lock-Free Hash Tables and List-Based Sets" -,Year="2002" -,Month="August" -,booktitle="{Proceedings of the 14\textsuperscript{th} Annual ACM -Symposium on Parallel -Algorithms and Architecture}" -,pages="73-82" -,annotation=" - Like the title says... -" -} - -@InProceedings{HerlihyLM02 -,author={Maurice Herlihy and Victor Luchangco and Mark Moir} -,title="The Repeat Offender Problem: A Mechanism for Supporting Dynamic-Sized, -Lock-Free Data Structures" -,booktitle={Proceedings of 16\textsuperscript{th} International -Symposium on Distributed Computing} -,year=2002 -,month="October" -,pages="339-353" -} - @article{Appavoo03a ,author="J. Appavoo and K. Hui and C. A. N. Soules and R. W. Wisniewski and D. M. {Da Silva} and O. Krieger and M. A. Auslander and D. J. Edelsohn and @@ -543,95 +447,3 @@ Oregon Health and Sciences University" Realtime turns into making RCU yet more realtime friendly. " } - -@conference{ThomasEHart2006a -,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown" -,Title="Making Lockless Synchronization Fast: Performance Implications -of Memory Reclamation" -,Booktitle="20\textsuperscript{th} {IEEE} International Parallel and -Distributed Processing Symposium" -,month="April" -,year="2006" -,day="25-29" -,address="Rhodes, Greece" -,annotation=" - Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free - reference counting. -" -} - -@Conference{PaulEMcKenney2006b -,Author="Paul E. McKenney and Dipankar Sarma and Ingo Molnar and -Suparna Bhattacharya" -,Title="Extending RCU for Realtime and Embedded Workloads" -,Booktitle="{Ottawa Linux Symposium}" -,Month="July" -,Year="2006" -,pages="v2 123-138" -,note="Available: -\url{http://www.linuxsymposium.org/2006/view_abstract.php?content_key=184} -\url{http://www.rdrop.com/users/paulmck/RCU/OLSrtRCU.2006.08.11a.pdf} -[Viewed January 1, 2007]" -,annotation=" - Described how to improve the -rt implementation of realtime RCU. -" -} - -@unpublished{PaulEMcKenney2006c -,Author="Paul E. McKenney" -,Title="Sleepable {RCU}" -,month="October" -,day="9" -,year="2006" -,note="Available: -\url{http://lwn.net/Articles/202847/} -Revised: -\url{http://www.rdrop.com/users/paulmck/RCU/srcu.2007.01.14a.pdf} -[Viewed August 21, 2006]" -,annotation=" - LWN article introducing SRCU. -" -} - -@unpublished{RobertOlsson2006a -,Author="Robert Olsson and Stefan Nilsson" -,Title="{TRASH}: A dynamic {LC}-trie and hash data structure" -,month="August" -,day="18" -,year="2006" -,note="Available: -\url{http://www.nada.kth.se/~snilsson/public/papers/trash/trash.pdf} -[Viewed February 24, 2007]" -,annotation=" - RCU-protected dynamic trie-hash combination. -" -} - -@unpublished{ThomasEHart2007a -,Author="Thomas E. Hart and Paul E. McKenney and Angela Demke Brown and Jonathan Walpole" -,Title="Performance of memory reclamation for lockless synchronization" -,journal="J. Parallel Distrib. Comput." -,year="2007" -,note="To appear in J. Parallel Distrib. Comput. - \url{doi=10.1016/j.jpdc.2007.04.010}" -,annotation={ - Compares QSBR (AKA "classic RCU"), HPBR, EBR, and lock-free - reference counting. Journal version of ThomasEHart2006a. -} -} - -@unpublished{PaulEMcKenney2007QRCUspin -,Author="Paul E. McKenney" -,Title="Using Promela and Spin to verify parallel algorithms" -,month="August" -,day="1" -,year="2007" -,note="Available: -\url{http://lwn.net/Articles/243851/} -[Viewed September 8, 2007]" -,annotation=" - LWN article describing Promela and spin, and also using Oleg - Nesterov's QRCU as an example (with Paul McKenney's fastpath). -" -} - diff --git a/trunk/Documentation/RCU/rcu.txt b/trunk/Documentation/RCU/rcu.txt index 95821a29ae41..f84407cba816 100644 --- a/trunk/Documentation/RCU/rcu.txt +++ b/trunk/Documentation/RCU/rcu.txt @@ -36,14 +36,6 @@ o How can the updater tell when a grace period has completed executed in user mode, or executed in the idle loop, we can safely free up that item. - Preemptible variants of RCU (CONFIG_PREEMPT_RCU) get the - same effect, but require that the readers manipulate CPU-local - counters. These counters allow limited types of blocking - within RCU read-side critical sections. SRCU also uses - CPU-local counters, and permits general blocking within - RCU read-side critical sections. These two variants of - RCU detect grace periods by sampling these counters. - o If I am running on a uniprocessor kernel, which can only do one thing at a time, why should I wait for a grace period? @@ -54,10 +46,7 @@ o How can I see where RCU is currently used in the Linux kernel? Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu", "rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh", "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu", - "synchronize_net", "synchronize_srcu", and the other RCU - primitives. Or grab one of the cscope databases from: - - http://www.rdrop.com/users/paulmck/RCU/linuxusage/rculocktab.html + "synchronize_net", and "synchronize_srcu". o What guidelines should I follow when writing code that uses RCU? @@ -78,11 +67,7 @@ o I hear that RCU is patented? What is with that? o I hear that RCU needs work in order to support realtime kernels? - This work is largely completed. Realtime-friendly RCU can be - enabled via the CONFIG_PREEMPT_RCU kernel configuration parameter. - However, work is in progress for enabling priority boosting of - preempted RCU read-side critical sections.This is needed if you - have CPU-bound realtime threads. + Yes, work in progress. o Where can I find more information on RCU? diff --git a/trunk/Documentation/RCU/torture.txt b/trunk/Documentation/RCU/torture.txt index 2967a65269d8..25a3c3f7d378 100644 --- a/trunk/Documentation/RCU/torture.txt +++ b/trunk/Documentation/RCU/torture.txt @@ -46,13 +46,12 @@ stat_interval The number of seconds between output of torture shuffle_interval The number of seconds to keep the test threads affinitied - to a particular subset of the CPUs, defaults to 5 seconds. - Used in conjunction with test_no_idle_hz. + to a particular subset of the CPUs. Used in conjunction + with test_no_idle_hz. test_no_idle_hz Whether or not to test the ability of RCU to operate in a kernel that disables the scheduling-clock interrupt to idle CPUs. Boolean parameter, "1" to test, "0" otherwise. - Defaults to omitting this test. torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API, "rcu_sync" for rcu_read_lock() with synchronous reclamation, @@ -83,6 +82,8 @@ be evident. ;-) The entries are as follows: +o "ggp": The number of counter flips (or batches) since boot. + o "rtc": The hexadecimal address of the structure currently visible to readers. @@ -116,8 +117,8 @@ o "Reader Pipe": Histogram of "ages" of structures seen by readers. o "Reader Batch": Another histogram of "ages" of structures seen by readers, but in terms of counter flips (or batches) rather than in terms of grace periods. The legal number of non-zero - entries is again two. The reason for this separate view is that - it is sometimes easier to get the third entry to show up in the + entries is again two. The reason for this separate view is + that it is easier to get the third entry to show up in the "Reader Batch" list than in the "Reader Pipe" list. o "Free-Block Circulation": Shows the number of torture structures diff --git a/trunk/Documentation/cpu-hotplug.txt b/trunk/Documentation/cpu-hotplug.txt index fb94f5a71b68..a741f658a3c9 100644 --- a/trunk/Documentation/cpu-hotplug.txt +++ b/trunk/Documentation/cpu-hotplug.txt @@ -109,13 +109,12 @@ Never use anything other than cpumask_t to represent bitmap of CPUs. for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask. #include - get_online_cpus() and put_online_cpus(): + lock_cpu_hotplug() and unlock_cpu_hotplug(): -The above calls are used to inhibit cpu hotplug operations. While the -cpu_hotplug.refcount is non zero, the cpu_online_map will not change. -If you merely need to avoid cpus going away, you could also use -preempt_disable() and preempt_enable() for those sections. -Just remember the critical section cannot call any +The above calls are used to inhibit cpu hotplug operations. While holding the +cpucontrol mutex, cpu_online_map will not change. If you merely need to avoid +cpus going away, you could also use preempt_disable() and preempt_enable() +for those sections. Just remember the critical section cannot call any function that can sleep or schedule this process away. The preempt_disable() will work as long as stop_machine_run() is used to take a cpu down. diff --git a/trunk/Documentation/dvb/bt8xx.txt b/trunk/Documentation/dvb/bt8xx.txt index b7b1d1b1da46..ecb47adda063 100644 --- a/trunk/Documentation/dvb/bt8xx.txt +++ b/trunk/Documentation/dvb/bt8xx.txt @@ -78,18 +78,6 @@ Example: For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv. In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org. -2c) Probing the cards with broken PCI subsystem ID --------------------------------------------------- -There are some TwinHan cards that the EEPROM has become corrupted for some -reason. The cards do not have correct PCI subsystem ID. But we can force -probing the cards with broken PCI subsystem ID - - $ echo 109e 0878 $subvendor $subdevice > \ - /sys/bus/pci/drivers/bt878/new_id - -109e: PCI_VENDOR_ID_BROOKTREE -0878: PCI_DEVICE_ID_BROOKTREE_878 - Authors: Richard Walker, Jamie Honan, Michael Hunold, diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index 9b8291f4c211..20c4c8bac9d7 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -295,6 +295,16 @@ Who: linuxppc-dev@ozlabs.org --------------------------- +What: mthca driver's MSI support +When: January 2008 +Files: drivers/infiniband/hw/mthca/*.[ch] +Why: All mthca hardware also supports MSI-X, which provides + strictly more functionality than MSI. So there is no point in + having both MSI-X and MSI support in the driver. +Who: Roland Dreier + +--------------------------- + What: sk98lin network driver When: Feburary 2008 Why: In kernel tree version of driver is unmaintained. Sk98lin driver diff --git a/trunk/Documentation/filesystems/ocfs2.txt b/trunk/Documentation/filesystems/ocfs2.txt index c318a8bbb1ef..ed55238023a9 100644 --- a/trunk/Documentation/filesystems/ocfs2.txt +++ b/trunk/Documentation/filesystems/ocfs2.txt @@ -35,6 +35,7 @@ Features which OCFS2 does not support yet: - Directory change notification (F_NOTIFY) - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease) - POSIX ACLs + - readpages / writepages (not user visible) Mount options ============= @@ -61,18 +62,3 @@ data=writeback Data ordering is not preserved, data may be written preferred_slot=0(*) During mount, try to use this filesystem slot first. If it is in use by another node, the first empty one found will be chosen. Invalid values will be ignored. -commit=nrsec (*) Ocfs2 can be told to sync all its data and metadata - every 'nrsec' seconds. The default value is 5 seconds. - This means that if you lose your power, you will lose - as much as the latest 5 seconds of work (your - filesystem will not be damaged though, thanks to the - journaling). This default value (or any low value) - will hurt performance, but it's good for data-safety. - Setting it to 0 will have the same effect as leaving - it at the default (5 seconds). - Setting it to very large values will improve - performance. -localalloc=8(*) Allows custom localalloc size in MB. If the value is too - large, the fs will silently revert it to the default. - Localalloc is not enabled for local mounts. -localflocks This disables cluster aware flock. diff --git a/trunk/Documentation/ioctl-number.txt b/trunk/Documentation/ioctl-number.txt index c18363bd8d11..5c7fbf9d96b4 100644 --- a/trunk/Documentation/ioctl-number.txt +++ b/trunk/Documentation/ioctl-number.txt @@ -138,7 +138,6 @@ Code Seq# Include File Comments 'm' 00-1F net/irda/irmod.h conflict! 'n' 00-7F linux/ncp_fs.h 'n' E0-FF video/matrox.h matroxfb -'o' 00-1F fs/ocfs2/ocfs2_fs.h OCFS2 'p' 00-0F linux/phantom.h conflict! (OpenHaptics needs this) 'p' 00-3F linux/mc146818rtc.h conflict! 'p' 40-7F linux/nvram.h diff --git a/trunk/Documentation/video4linux/CARDLIST.cx23885 b/trunk/Documentation/video4linux/CARDLIST.cx23885 index 0924e6e142c4..00cb646a4bde 100644 --- a/trunk/Documentation/video4linux/CARDLIST.cx23885 +++ b/trunk/Documentation/video4linux/CARDLIST.cx23885 @@ -1,7 +1,5 @@ 0 -> UNKNOWN/GENERIC [0070:3400] 1 -> Hauppauge WinTV-HVR1800lp [0070:7600] - 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801,0070:7809] + 2 -> Hauppauge WinTV-HVR1800 [0070:7800,0070:7801] 3 -> Hauppauge WinTV-HVR1250 [0070:7911] 4 -> DViCO FusionHDTV5 Express [18ac:d500] - 5 -> Hauppauge WinTV-HVR1500Q [0070:7790,0070:7797] - 6 -> Hauppauge WinTV-HVR1500 [0070:7710,0070:7717] diff --git a/trunk/Documentation/video4linux/CARDLIST.cx88 b/trunk/Documentation/video4linux/CARDLIST.cx88 index bc5593bd9704..82ac8250e978 100644 --- a/trunk/Documentation/video4linux/CARDLIST.cx88 +++ b/trunk/Documentation/video4linux/CARDLIST.cx88 @@ -56,4 +56,3 @@ 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980] 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602] 57 -> ADS Tech Instant Video PCI [1421:0390] - 58 -> Pinnacle PCTV HD 800i [11bd:0051] diff --git a/trunk/Documentation/video4linux/CARDLIST.em28xx b/trunk/Documentation/video4linux/CARDLIST.em28xx index 6a8469f2bcae..37f0e3cedf43 100644 --- a/trunk/Documentation/video4linux/CARDLIST.em28xx +++ b/trunk/Documentation/video4linux/CARDLIST.em28xx @@ -1,17 +1,14 @@ 0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800] - 1 -> Unknown EM2750/28xx video grabber (em2820/em2840) [eb1a:2750,eb1a:2820,eb1a:2821,eb1a:2860,eb1a:2861,eb1a:2870,eb1a:2881,eb1a:2883] + 1 -> Unknown EM2820/2840 video grabber (em2820/em2840) 2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036] 3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208] - 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200,2040:4201] - 5 -> MSI VOX USB 2.0 (em2820/em2840) + 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200] + 5 -> MSI VOX USB 2.0 (em2820/em2840) [eb1a:2820] 6 -> Terratec Cinergy 200 USB (em2800) 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) - 9 -> Pinnacle Dazzle DVC 90/DVC 100 (em2820/em2840) [2304:0207,2304:021a] - 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500] - 11 -> Terratec Hybrid XS (em2880) [0ccd:0042] + 9 -> Pinnacle Dazzle DVC 90 (em2820/em2840) [2304:0207] + 10 -> Hauppauge WinTV HVR 900 (em2880) + 11 -> Terratec Hybrid XS (em2880) 12 -> Kworld PVR TV 2800 RF (em2820/em2840) - 13 -> Terratec Prodigy XS (em2880) [0ccd:0047] - 14 -> Pixelview Prolink PlayTV USB 2.0 (em2820/em2840) - 15 -> V-Gear PocketTV (em2800) - 16 -> Hauppauge WinTV HVR 950 (em2880) [2040:6513] + 13 -> Terratec Prodigy XS (em2880) diff --git a/trunk/Documentation/video4linux/CARDLIST.ivtv b/trunk/Documentation/video4linux/CARDLIST.ivtv index a019e27e42b3..ddd76a0eb100 100644 --- a/trunk/Documentation/video4linux/CARDLIST.ivtv +++ b/trunk/Documentation/video4linux/CARDLIST.ivtv @@ -16,9 +16,3 @@ 16 -> GOTVIEW PCI DVD2 Deluxe [ffac:0600] 17 -> Yuan MPC622 [ff01:d998] 18 -> Digital Cowboy DCT-MTVP1 [1461:bfff] -19 -> Yuan PG600V2/GotView PCI DVD Lite [ffab:0600,ffad:0600] -20 -> Club3D ZAP-TV1x01 [ffab:0600] -21 -> AverTV MCE 116 Plus [1461:c439] -22 -> ASUS Falcon2 [1043:4b66,1043:462e,1043:4b2e] -23 -> AverMedia PVR-150 Plus [1461:c035] -24 -> AverMedia EZMaker PCI Deluxe [1461:c03f] diff --git a/trunk/Documentation/video4linux/CARDLIST.saa7134 b/trunk/Documentation/video4linux/CARDLIST.saa7134 index 5d3b6b4d2515..a14545300e4c 100644 --- a/trunk/Documentation/video4linux/CARDLIST.saa7134 +++ b/trunk/Documentation/video4linux/CARDLIST.saa7134 @@ -80,7 +80,7 @@ 79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B) 80 -> ASUS Digimatrix TV [1043:0210] 81 -> Philips Tiger reference design [1131:2018] - 82 -> MSI TV@Anywhere plus [1462:6231,1462:8624] + 82 -> MSI TV@Anywhere plus [1462:6231] 83 -> Terratec Cinergy 250 PCI TV [153b:1160] 84 -> LifeView FlyDVB Trio [5168:0319] 85 -> AverTV DVB-T 777 [1461:2c05,1461:2c05] @@ -102,7 +102,7 @@ 101 -> Pinnacle PCTV 310i [11bd:002f] 102 -> Avermedia AVerTV Studio 507 [1461:9715] 103 -> Compro Videomate DVB-T200A -104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6700,0070:6701,0070:6702,0070:6703,0070:6704,0070:6705] +104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6701] 105 -> Terratec Cinergy HT PCMCIA [153b:1172] 106 -> Encore ENLTV [1131:2342,1131:2341,3016:2344] 107 -> Encore ENLTV-FM [1131:230f] @@ -116,16 +116,3 @@ 115 -> Sabrent PCMCIA TV-PCB05 [0919:2003] 116 -> 10MOONS TM300 TV Card [1131:2304] 117 -> Avermedia Super 007 [1461:f01d] -118 -> Beholder BeholdTV 401 [0000:4016] -119 -> Beholder BeholdTV 403 [0000:4036] -120 -> Beholder BeholdTV 403 FM [0000:4037] -121 -> Beholder BeholdTV 405 [0000:4050] -122 -> Beholder BeholdTV 405 FM [0000:4051] -123 -> Beholder BeholdTV 407 [0000:4070] -124 -> Beholder BeholdTV 407 FM [0000:4071] -125 -> Beholder BeholdTV 409 [0000:4090] -126 -> Beholder BeholdTV 505 FM/RDS [0000:5051,0000:505B,5ace:5050] -127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090] -128 -> Beholder BeholdTV Columbus TVFM [0000:5201] -129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093] -130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193] diff --git a/trunk/Documentation/video4linux/CARDLIST.tuner b/trunk/Documentation/video4linux/CARDLIST.tuner index 0e2394695bb8..a88c02d23805 100644 --- a/trunk/Documentation/video4linux/CARDLIST.tuner +++ b/trunk/Documentation/video4linux/CARDLIST.tuner @@ -52,7 +52,7 @@ tuner=50 - TCL 2002N tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3) tuner=52 - Thomson DTT 7610 (ATSC/NTSC) tuner=53 - Philips FQ1286 -tuner=54 - Philips/NXP TDA 8290/8295 + 8275/8275A/18271 +tuner=54 - tda8290+75 tuner=55 - TCL 2002MB tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4) tuner=57 - Philips FQ1236A MK4 @@ -69,8 +69,7 @@ tuner=67 - Philips TD1316 Hybrid Tuner tuner=68 - Philips TUV1236D ATSC/NTSC dual in tuner=69 - Tena TNF 5335 and similar models tuner=70 - Samsung TCPN 2121P30A -tuner=71 - Xceive xc2028/xc3028 tuner +tuner=71 - Xceive xc3028 tuner=72 - Thomson FE6600 tuner=73 - Samsung TCPG 6121P30A tuner=75 - Philips TEA5761 FM Radio -tuner=76 - Xceive 5000 tuner diff --git a/trunk/Documentation/video4linux/CARDLIST.usbvision b/trunk/Documentation/video4linux/CARDLIST.usbvision index 0b72d3fee17e..3d6850ef0245 100644 --- a/trunk/Documentation/video4linux/CARDLIST.usbvision +++ b/trunk/Documentation/video4linux/CARDLIST.usbvision @@ -62,4 +62,3 @@ 61 -> Pinnacle Studio Linx Video input cable (PAL) [2304:0301] 62 -> Pinnacle PCTV Bungee USB (PAL) FM [2304:0419] 63 -> Hauppauge WinTv-USB [2400:4200] - 64 -> Pinnacle Studio PCTV USB (NTSC) FM V3 [2304:0113] diff --git a/trunk/Documentation/video4linux/extract_xc3028.pl b/trunk/Documentation/video4linux/extract_xc3028.pl deleted file mode 100644 index cced8ac5c543..000000000000 --- a/trunk/Documentation/video4linux/extract_xc3028.pl +++ /dev/null @@ -1,926 +0,0 @@ -#!/usr/bin/perl - -# Copyright (c) Mauro Carvalho Chehab -# Released under GPLv2 -# -# In order to use, you need to: -# 1) Download the windows driver with something like: -# wget http://www.steventoth.net/linux/xc5000/HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip -# 2) Extract the file hcw85bda.sys from the zip into the current dir: -# unzip -j HVR-12x0-14x0-17x0_1_25_25271_WHQL.zip Driver85/hcw85bda.sys -# 3) run the script: -# ./extract_xc3028.pl -# 4) copy the generated file: -# cp xc3028-v27.fw /lib/firmware - -#use strict; -use IO::Handle; - -my $debug=0; - -sub verify ($$) -{ - my ($filename, $hash) = @_; - my ($testhash); - - if (system("which md5sum > /dev/null 2>&1")) { - die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n"; - } - - open(CMD, "md5sum ".$filename."|"); - $testhash = ; - $testhash =~ /([a-zA-Z0-9]*)/; - $testhash = $1; - close CMD; - die "Hash of extracted file does not match (found $testhash, expected $hash!\n" if ($testhash ne $hash); -} - -sub get_hunk ($$) -{ - my ($offset, $length) = @_; - my ($chunklength, $buf, $rcount, $out); - - sysseek(INFILE, $offset, SEEK_SET); - while ($length > 0) { - # Calc chunk size - $chunklength = 2048; - $chunklength = $length if ($chunklength > $length); - - $rcount = sysread(INFILE, $buf, $chunklength); - die "Ran out of data\n" if ($rcount != $chunklength); - $out .= $buf; - $length -= $rcount; - } - return $out; -} - -sub write_le16($) -{ - my $val = shift; - my $msb = ($val >> 8) &0xff; - my $lsb = $val & 0xff; - - syswrite(OUTFILE, chr($lsb).chr($msb)); -} - -sub write_le32($) -{ - my $val = shift; - my $l3 = ($val >> 24) & 0xff; - my $l2 = ($val >> 16) & 0xff; - my $l1 = ($val >> 8) & 0xff; - my $l0 = $val & 0xff; - - syswrite(OUTFILE, chr($l0).chr($l1).chr($l2).chr($l3)); -} - -sub write_le64($$) -{ - my $msb_val = shift; - my $lsb_val = shift; - my $l7 = ($msb_val >> 24) & 0xff; - my $l6 = ($msb_val >> 16) & 0xff; - my $l5 = ($msb_val >> 8) & 0xff; - my $l4 = $msb_val & 0xff; - - my $l3 = ($lsb_val >> 24) & 0xff; - my $l2 = ($lsb_val >> 16) & 0xff; - my $l1 = ($lsb_val >> 8) & 0xff; - my $l0 = $lsb_val & 0xff; - - syswrite(OUTFILE, - chr($l0).chr($l1).chr($l2).chr($l3). - chr($l4).chr($l5).chr($l6).chr($l7)); -} - -sub write_hunk($$) -{ - my ($offset, $length) = @_; - my $out = get_hunk($offset, $length); - - printf "(len %d) ",$length if ($debug); - - for (my $i=0;$i<$length;$i++) { - printf "%02x ",ord(substr($out,$i,1)) if ($debug); - } - printf "\n" if ($debug); - - syswrite(OUTFILE, $out); -} - -sub write_hunk_fix_endian($$) -{ - my ($offset, $length) = @_; - my $out = get_hunk($offset, $length); - - printf "(len_fix %d) ",$length if ($debug); - - for (my $i=0;$i<$length;$i++) { - printf "%02x ",ord(substr($out,$i,1)) if ($debug); - } - printf "\n" if ($debug); - - my $i=0; - while ($i<$length) { - my $size = ord(substr($out,$i,1))*256+ord(substr($out,$i+1,1)); - syswrite(OUTFILE, substr($out,$i+1,1)); - syswrite(OUTFILE, substr($out,$i,1)); - $i+=2; - if ($size>0 && $size <0x8000) { - for (my $j=0;$j<$size;$j++) { - syswrite(OUTFILE, substr($out,$j+$i,1)); - } - $i+=$size; - } - } -} - -sub main_firmware($$$$) -{ - my $out; - my $j=0; - my $outfile = shift; - my $name = shift; - my $version = shift; - my $nr_desc = shift; - - for ($j = length($name); $j <32; $j++) { - $name = $name.chr(0); -} - - open OUTFILE, ">$outfile"; - syswrite(OUTFILE, $name); - write_le16($version); - write_le16($nr_desc); - - # - # Firmware 0, type: BASE FW F8MHZ (0x00000003), id: (0000000000000000), size: 8718 - # - - write_le32(0x00000003); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(8718); # Size - write_hunk_fix_endian(813432, 8718); - - # - # Firmware 1, type: BASE FW F8MHZ MTS (0x00000007), id: (0000000000000000), size: 8712 - # - - write_le32(0x00000007); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(8712); # Size - write_hunk_fix_endian(822152, 8712); - - # - # Firmware 2, type: BASE FW FM (0x00000401), id: (0000000000000000), size: 8562 - # - - write_le32(0x00000401); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(8562); # Size - write_hunk_fix_endian(830872, 8562); - - # - # Firmware 3, type: BASE FW FM INPUT1 (0x00000c01), id: (0000000000000000), size: 8576 - # - - write_le32(0x00000c01); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(8576); # Size - write_hunk_fix_endian(839440, 8576); - - # - # Firmware 4, type: BASE FW (0x00000001), id: (0000000000000000), size: 8706 - # - - write_le32(0x00000001); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(8706); # Size - write_hunk_fix_endian(848024, 8706); - - # - # Firmware 5, type: BASE FW MTS (0x00000005), id: (0000000000000000), size: 8682 - # - - write_le32(0x00000005); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(8682); # Size - write_hunk_fix_endian(856736, 8682); - - # - # Firmware 6, type: STD FW (0x00000000), id: PAL/BG A2/A (0000000100000007), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000001, 0x00000007); # ID - write_le32(161); # Size - write_hunk_fix_endian(865424, 161); - - # - # Firmware 7, type: STD FW MTS (0x00000004), id: PAL/BG A2/A (0000000100000007), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000001, 0x00000007); # ID - write_le32(169); # Size - write_hunk_fix_endian(865592, 169); - - # - # Firmware 8, type: STD FW (0x00000000), id: PAL/BG A2/B (0000000200000007), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000002, 0x00000007); # ID - write_le32(161); # Size - write_hunk_fix_endian(865424, 161); - - # - # Firmware 9, type: STD FW MTS (0x00000004), id: PAL/BG A2/B (0000000200000007), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000002, 0x00000007); # ID - write_le32(169); # Size - write_hunk_fix_endian(865592, 169); - - # - # Firmware 10, type: STD FW (0x00000000), id: PAL/BG NICAM/A (0000000400000007), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000004, 0x00000007); # ID - write_le32(161); # Size - write_hunk_fix_endian(866112, 161); - - # - # Firmware 11, type: STD FW MTS (0x00000004), id: PAL/BG NICAM/A (0000000400000007), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000004, 0x00000007); # ID - write_le32(169); # Size - write_hunk_fix_endian(866280, 169); - - # - # Firmware 12, type: STD FW (0x00000000), id: PAL/BG NICAM/B (0000000800000007), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000008, 0x00000007); # ID - write_le32(161); # Size - write_hunk_fix_endian(866112, 161); - - # - # Firmware 13, type: STD FW MTS (0x00000004), id: PAL/BG NICAM/B (0000000800000007), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000008, 0x00000007); # ID - write_le32(169); # Size - write_hunk_fix_endian(866280, 169); - - # - # Firmware 14, type: STD FW (0x00000000), id: PAL/DK A2 (00000003000000e0), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000003, 0x000000e0); # ID - write_le32(161); # Size - write_hunk_fix_endian(866800, 161); - - # - # Firmware 15, type: STD FW MTS (0x00000004), id: PAL/DK A2 (00000003000000e0), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000003, 0x000000e0); # ID - write_le32(169); # Size - write_hunk_fix_endian(866968, 169); - - # - # Firmware 16, type: STD FW (0x00000000), id: PAL/DK NICAM (0000000c000000e0), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x0000000c, 0x000000e0); # ID - write_le32(161); # Size - write_hunk_fix_endian(867144, 161); - - # - # Firmware 17, type: STD FW MTS (0x00000004), id: PAL/DK NICAM (0000000c000000e0), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x0000000c, 0x000000e0); # ID - write_le32(169); # Size - write_hunk_fix_endian(867312, 169); - - # - # Firmware 18, type: STD FW (0x00000000), id: SECAM/K1 (0000000000200000), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000000, 0x00200000); # ID - write_le32(161); # Size - write_hunk_fix_endian(867488, 161); - - # - # Firmware 19, type: STD FW MTS (0x00000004), id: SECAM/K1 (0000000000200000), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000000, 0x00200000); # ID - write_le32(169); # Size - write_hunk_fix_endian(867656, 169); - - # - # Firmware 20, type: STD FW (0x00000000), id: SECAM/K3 (0000000004000000), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000000, 0x04000000); # ID - write_le32(161); # Size - write_hunk_fix_endian(867832, 161); - - # - # Firmware 21, type: STD FW MTS (0x00000004), id: SECAM/K3 (0000000004000000), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000000, 0x04000000); # ID - write_le32(169); # Size - write_hunk_fix_endian(868000, 169); - - # - # Firmware 22, type: STD FW D2633 DTV6 ATSC (0x00010030), id: (0000000000000000), size: 149 - # - - write_le32(0x00010030); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868176, 149); - - # - # Firmware 23, type: STD FW D2620 DTV6 QAM (0x00000068), id: (0000000000000000), size: 149 - # - - write_le32(0x00000068); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868336, 149); - - # - # Firmware 24, type: STD FW D2633 DTV6 QAM (0x00000070), id: (0000000000000000), size: 149 - # - - write_le32(0x00000070); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868488, 149); - - # - # Firmware 25, type: STD FW D2620 DTV7 (0x00000088), id: (0000000000000000), size: 149 - # - - write_le32(0x00000088); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868648, 149); - - # - # Firmware 26, type: STD FW D2633 DTV7 (0x00000090), id: (0000000000000000), size: 149 - # - - write_le32(0x00000090); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868800, 149); - - # - # Firmware 27, type: STD FW D2620 DTV78 (0x00000108), id: (0000000000000000), size: 149 - # - - write_le32(0x00000108); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868960, 149); - - # - # Firmware 28, type: STD FW D2633 DTV78 (0x00000110), id: (0000000000000000), size: 149 - # - - write_le32(0x00000110); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(869112, 149); - - # - # Firmware 29, type: STD FW D2620 DTV8 (0x00000208), id: (0000000000000000), size: 149 - # - - write_le32(0x00000208); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868648, 149); - - # - # Firmware 30, type: STD FW D2633 DTV8 (0x00000210), id: (0000000000000000), size: 149 - # - - write_le32(0x00000210); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(149); # Size - write_hunk_fix_endian(868800, 149); - - # - # Firmware 31, type: STD FW FM (0x00000400), id: (0000000000000000), size: 135 - # - - write_le32(0x00000400); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le32(135); # Size - write_hunk_fix_endian(869584, 135); - - # - # Firmware 32, type: STD FW (0x00000000), id: PAL/I (0000000000000010), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000000, 0x00000010); # ID - write_le32(161); # Size - write_hunk_fix_endian(869728, 161); - - # - # Firmware 33, type: STD FW MTS (0x00000004), id: PAL/I (0000000000000010), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000000, 0x00000010); # ID - write_le32(169); # Size - write_hunk_fix_endian(869896, 169); - - # - # Firmware 34, type: STD FW (0x00000000), id: SECAM/L AM (0000001000400000), size: 169 - # - - write_le32(0x00000000); # Type - write_le64(0x00000010, 0x00400000); # ID - write_le32(169); # Size - write_hunk_fix_endian(870072, 169); - - # - # Firmware 35, type: STD FW (0x00000000), id: SECAM/L NICAM (0000000c00400000), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x0000000c, 0x00400000); # ID - write_le32(161); # Size - write_hunk_fix_endian(870248, 161); - - # - # Firmware 36, type: STD FW (0x00000000), id: SECAM/Lc (0000000000800000), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000000, 0x00800000); # ID - write_le32(161); # Size - write_hunk_fix_endian(870416, 161); - - # - # Firmware 37, type: STD FW (0x00000000), id: NTSC/M Kr (0000000000008000), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000000, 0x00008000); # ID - write_le32(161); # Size - write_hunk_fix_endian(870584, 161); - - # - # Firmware 38, type: STD FW LCD (0x00001000), id: NTSC/M Kr (0000000000008000), size: 161 - # - - write_le32(0x00001000); # Type - write_le64(0x00000000, 0x00008000); # ID - write_le32(161); # Size - write_hunk_fix_endian(870752, 161); - - # - # Firmware 39, type: STD FW LCD NOGD (0x00003000), id: NTSC/M Kr (0000000000008000), size: 161 - # - - write_le32(0x00003000); # Type - write_le64(0x00000000, 0x00008000); # ID - write_le32(161); # Size - write_hunk_fix_endian(870920, 161); - - # - # Firmware 40, type: STD FW MTS (0x00000004), id: NTSC/M Kr (0000000000008000), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000000, 0x00008000); # ID - write_le32(169); # Size - write_hunk_fix_endian(871088, 169); - - # - # Firmware 41, type: STD FW (0x00000000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000000, 0x0000b700); # ID - write_le32(161); # Size - write_hunk_fix_endian(871264, 161); - - # - # Firmware 42, type: STD FW LCD (0x00001000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161 - # - - write_le32(0x00001000); # Type - write_le64(0x00000000, 0x0000b700); # ID - write_le32(161); # Size - write_hunk_fix_endian(871432, 161); - - # - # Firmware 43, type: STD FW LCD NOGD (0x00003000), id: NTSC PAL/M PAL/N (000000000000b700), size: 161 - # - - write_le32(0x00003000); # Type - write_le64(0x00000000, 0x0000b700); # ID - write_le32(161); # Size - write_hunk_fix_endian(871600, 161); - - # - # Firmware 44, type: STD FW (0x00000000), id: NTSC/M Jp (0000000000002000), size: 161 - # - - write_le32(0x00000000); # Type - write_le64(0x00000000, 0x00002000); # ID - write_le32(161); # Size - write_hunk_fix_endian(871264, 161); - - # - # Firmware 45, type: STD FW MTS (0x00000004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169 - # - - write_le32(0x00000004); # Type - write_le64(0x00000000, 0x0000b700); # ID - write_le32(169); # Size - write_hunk_fix_endian(871936, 169); - - # - # Firmware 46, type: STD FW MTS LCD (0x00001004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169 - # - - write_le32(0x00001004); # Type - write_le64(0x00000000, 0x0000b700); # ID - write_le32(169); # Size - write_hunk_fix_endian(872112, 169); - - # - # Firmware 47, type: STD FW MTS LCD NOGD (0x00003004), id: NTSC PAL/M PAL/N (000000000000b700), size: 169 - # - - write_le32(0x00003004); # Type - write_le64(0x00000000, 0x0000b700); # ID - write_le32(169); # Size - write_hunk_fix_endian(872288, 169); - - # - # Firmware 48, type: SCODE FW HAS IF (0x60000000), IF = 3.28 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(3280); # IF - write_le32(192); # Size - write_hunk(811896, 192); - - # - # Firmware 49, type: SCODE FW HAS IF (0x60000000), IF = 3.30 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(3300); # IF - write_le32(192); # Size - write_hunk(813048, 192); - - # - # Firmware 50, type: SCODE FW HAS IF (0x60000000), IF = 3.44 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(3440); # IF - write_le32(192); # Size - write_hunk(812280, 192); - - # - # Firmware 51, type: SCODE FW HAS IF (0x60000000), IF = 3.46 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(3460); # IF - write_le32(192); # Size - write_hunk(812472, 192); - - # - # Firmware 52, type: SCODE FW DTV6 ATSC OREN36 HAS IF (0x60210020), IF = 3.80 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60210020); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(3800); # IF - write_le32(192); # Size - write_hunk(809784, 192); - - # - # Firmware 53, type: SCODE FW HAS IF (0x60000000), IF = 4.00 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(4000); # IF - write_le32(192); # Size - write_hunk(812088, 192); - - # - # Firmware 54, type: SCODE FW DTV6 ATSC TOYOTA388 HAS IF (0x60410020), IF = 4.08 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60410020); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(4080); # IF - write_le32(192); # Size - write_hunk(809976, 192); - - # - # Firmware 55, type: SCODE FW HAS IF (0x60000000), IF = 4.20 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(4200); # IF - write_le32(192); # Size - write_hunk(811704, 192); - - # - # Firmware 56, type: SCODE FW MONO HAS IF (0x60008000), IF = 4.32 MHz id: NTSC/M Kr (0000000000008000), size: 192 - # - - write_le32(0x60008000); # Type - write_le64(0x00000000, 0x00008000); # ID - write_le16(4320); # IF - write_le32(192); # Size - write_hunk(808056, 192); - - # - # Firmware 57, type: SCODE FW HAS IF (0x60000000), IF = 4.45 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(4450); # IF - write_le32(192); # Size - write_hunk(812664, 192); - - # - # Firmware 58, type: SCODE FW HAS IF (0x60000000), IF = 4.50 MHz id: NTSC/M Jp (0000000000002000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00002000); # ID - write_le16(4500); # IF - write_le32(192); # Size - write_hunk(807672, 192); - - # - # Firmware 59, type: SCODE FW LCD NOGD IF HAS IF (0x60023000), IF = 4.60 MHz id: NTSC/M Kr (0000000000008000), size: 192 - # - - write_le32(0x60023000); # Type - write_le64(0x00000000, 0x00008000); # ID - write_le16(4600); # IF - write_le32(192); # Size - write_hunk(807864, 192); - - # - # Firmware 60, type: SCODE FW DTV78 ZARLINK456 HAS IF (0x62000100), IF = 4.76 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x62000100); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(4760); # IF - write_le32(192); # Size - write_hunk(807288, 192); - - # - # Firmware 61, type: SCODE FW HAS IF (0x60000000), IF = 4.94 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(4940); # IF - write_le32(192); # Size - write_hunk(811512, 192); - - # - # Firmware 62, type: SCODE FW DTV7 ZARLINK456 HAS IF (0x62000080), IF = 5.26 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x62000080); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(5260); # IF - write_le32(192); # Size - write_hunk(810552, 192); - - # - # Firmware 63, type: SCODE FW MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192 - # - - write_le32(0x60008000); # Type - write_le64(0x00000008, 0x00000007); # ID - write_le16(5320); # IF - write_le32(192); # Size - write_hunk(810744, 192); - - # - # Firmware 64, type: SCODE FW DTV8 CHINA HAS IF (0x64000200), IF = 5.40 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x64000200); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(5400); # IF - write_le32(192); # Size - write_hunk(807096, 192); - - # - # Firmware 65, type: SCODE FW DTV6 ATSC OREN538 HAS IF (0x60110020), IF = 5.58 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60110020); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(5580); # IF - write_le32(192); # Size - write_hunk(809592, 192); - - # - # Firmware 66, type: SCODE FW HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2/B (0000000200000007), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000002, 0x00000007); # ID - write_le16(5640); # IF - write_le32(192); # Size - write_hunk(808440, 192); - - # - # Firmware 67, type: SCODE FW HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000008, 0x00000007); # ID - write_le16(5740); # IF - write_le32(192); # Size - write_hunk(808632, 192); - - # - # Firmware 68, type: SCODE FW DTV7 DIBCOM52 HAS IF (0x61000080), IF = 5.90 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x61000080); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(5900); # IF - write_le32(192); # Size - write_hunk(810360, 192); - - # - # Firmware 69, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/I (0000000000000010), size: 192 - # - - write_le32(0x60008000); # Type - write_le64(0x00000000, 0x00000010); # ID - write_le16(6000); # IF - write_le32(192); # Size - write_hunk(808824, 192); - - # - # Firmware 70, type: SCODE FW DTV6 QAM F6MHZ HAS IF (0x68000060), IF = 6.20 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x68000060); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(6200); # IF - write_le32(192); # Size - write_hunk(809400, 192); - - # - # Firmware 71, type: SCODE FW HAS IF (0x60000000), IF = 6.24 MHz id: PAL/I (0000000000000010), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000010); # ID - write_le16(6240); # IF - write_le32(192); # Size - write_hunk(808248, 192); - - # - # Firmware 72, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.32 MHz id: SECAM/K1 (0000000000200000), size: 192 - # - - write_le32(0x60008000); # Type - write_le64(0x00000000, 0x00200000); # ID - write_le16(6320); # IF - write_le32(192); # Size - write_hunk(811320, 192); - - # - # Firmware 73, type: SCODE FW HAS IF (0x60000000), IF = 6.34 MHz id: SECAM/K1 (0000000000200000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00200000); # ID - write_le16(6340); # IF - write_le32(192); # Size - write_hunk(809208, 192); - - # - # Firmware 74, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.50 MHz id: SECAM/K3 (0000000004000000), size: 192 - # - - write_le32(0x60008000); # Type - write_le64(0x00000000, 0x04000000); # ID - write_le16(6500); # IF - write_le32(192); # Size - write_hunk(811128, 192); - - # - # Firmware 75, type: SCODE FW DTV6 ATSC ATI638 HAS IF (0x60090020), IF = 6.58 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60090020); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(6580); # IF - write_le32(192); # Size - write_hunk(807480, 192); - - # - # Firmware 76, type: SCODE FW HAS IF (0x60000000), IF = 6.60 MHz id: PAL/DK A2 (00000003000000e0), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000003, 0x000000e0); # ID - write_le16(6600); # IF - write_le32(192); # Size - write_hunk(809016, 192); - - # - # Firmware 77, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.68 MHz id: PAL/DK A2 (00000003000000e0), size: 192 - # - - write_le32(0x60008000); # Type - write_le64(0x00000003, 0x000000e0); # ID - write_le16(6680); # IF - write_le32(192); # Size - write_hunk(810936, 192); - - # - # Firmware 78, type: SCODE FW DTV6 ATSC TOYOTA794 HAS IF (0x60810020), IF = 8.14 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60810020); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(8140); # IF - write_le32(192); # Size - write_hunk(810168, 192); - - # - # Firmware 79, type: SCODE FW HAS IF (0x60000000), IF = 8.20 MHz id: (0000000000000000), size: 192 - # - - write_le32(0x60000000); # Type - write_le64(0x00000000, 0x00000000); # ID - write_le16(8200); # IF - write_le32(192); # Size - write_hunk(812856, 192); -} - -sub extract_firmware { - my $sourcefile = "hcw85bda.sys"; - my $hash = "0e44dbf63bb0169d57446aec21881ff2"; - my $outfile = "xc3028-v27.fw"; - my $name = "xc2028 firmware"; - my $version = 519; - my $nr_desc = 80; - my $out; - - verify($sourcefile, $hash); - - open INFILE, "<$sourcefile"; - main_firmware($outfile, $name, $version, $nr_desc); - close INFILE; -} - -extract_firmware; -printf "Firmwares generated.\n"; diff --git a/trunk/Documentation/video4linux/sn9c102.txt b/trunk/Documentation/video4linux/sn9c102.txt index b26f5195af51..1ffad19ce891 100644 --- a/trunk/Documentation/video4linux/sn9c102.txt +++ b/trunk/Documentation/video4linux/sn9c102.txt @@ -568,7 +568,6 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4'. Many thanks to following persons for their contribute (listed in alphabetical order): -- David Anderson for the donation of a webcam; - Luca Capello for the donation of a webcam; - Philippe Coval for having helped testing the PAS202BCA image sensor; - Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 17524afa7475..2340cfb1e25d 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2141,15 +2141,6 @@ L: isdn4linux@listserv.isdn4linux.de W: http://www.melware.de S: Maintained -IVTV VIDEO4LINUX DRIVER -P: Hans Verkuil -M: hverkuil@xs4all.nl -L: ivtv-devel@ivtvdriver.org -L: ivtv-users@ivtvdriver.org -L: video4linux-list@redhat.com -W: http://www.ivtvdriver.org -S: Maintained - JOURNALLING FLASH FILE SYSTEM V2 (JFFS2) P: David Woodhouse M: dwmw2@infradead.org diff --git a/trunk/arch/arm/kernel/time.c b/trunk/arch/arm/kernel/time.c index e59b5b84168d..f6f3689a86ee 100644 --- a/trunk/arch/arm/kernel/time.c +++ b/trunk/arch/arm/kernel/time.c @@ -79,6 +79,17 @@ static unsigned long dummy_gettimeoffset(void) } #endif +/* + * An implementation of printk_clock() independent from + * sched_clock(). This avoids non-bootable kernels when + * printk_clock is enabled. + */ +unsigned long long printk_clock(void) +{ + return (unsigned long long)(jiffies - INITIAL_JIFFIES) * + (1000000000 / HZ); +} + static unsigned long next_rtc_update; /* diff --git a/trunk/arch/ia64/kernel/setup.c b/trunk/arch/ia64/kernel/setup.c index 86028c69861e..4ac2b1f1bd3b 100644 --- a/trunk/arch/ia64/kernel/setup.c +++ b/trunk/arch/ia64/kernel/setup.c @@ -71,6 +71,8 @@ unsigned long __per_cpu_offset[NR_CPUS]; EXPORT_SYMBOL(__per_cpu_offset); #endif +extern void ia64_setup_printk_clock(void); + DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info); DEFINE_PER_CPU(unsigned long, local_per_cpu_offset); unsigned long ia64_cycles_per_usec; @@ -505,6 +507,8 @@ setup_arch (char **cmdline_p) /* process SAL system table: */ ia64_sal_init(__va(efi.sal_systab)); + ia64_setup_printk_clock(); + #ifdef CONFIG_SMP cpu_physical_id(0) = hard_smp_processor_id(); #endif diff --git a/trunk/arch/ia64/kernel/time.c b/trunk/arch/ia64/kernel/time.c index 3ab042720970..2bb84214e5f1 100644 --- a/trunk/arch/ia64/kernel/time.c +++ b/trunk/arch/ia64/kernel/time.c @@ -344,6 +344,33 @@ udelay (unsigned long usecs) } EXPORT_SYMBOL(udelay); +static unsigned long long ia64_itc_printk_clock(void) +{ + if (ia64_get_kr(IA64_KR_PER_CPU_DATA)) + return sched_clock(); + return 0; +} + +static unsigned long long ia64_default_printk_clock(void) +{ + return (unsigned long long)(jiffies_64 - INITIAL_JIFFIES) * + (1000000000/HZ); +} + +unsigned long long (*ia64_printk_clock)(void) = &ia64_default_printk_clock; + +unsigned long long printk_clock(void) +{ + return ia64_printk_clock(); +} + +void __init +ia64_setup_printk_clock(void) +{ + if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) + ia64_printk_clock = ia64_itc_printk_clock; +} + /* IA64 doesn't cache the timezone */ void update_vsyscall_tz(void) { diff --git a/trunk/arch/ia64/sn/kernel/setup.c b/trunk/arch/ia64/sn/kernel/setup.c index bb1d24929640..1f38a3a68390 100644 --- a/trunk/arch/ia64/sn/kernel/setup.c +++ b/trunk/arch/ia64/sn/kernel/setup.c @@ -64,6 +64,7 @@ extern void sn_timer_init(void); extern unsigned long last_time_offset; extern void (*ia64_mark_idle) (int); extern void snidle(int); +extern unsigned long long (*ia64_printk_clock)(void); unsigned long sn_rtc_cycles_per_second; EXPORT_SYMBOL(sn_rtc_cycles_per_second); @@ -359,6 +360,14 @@ sn_scan_pcdp(void) static unsigned long sn2_rtc_initial; +static unsigned long long ia64_sn2_printk_clock(void) +{ + unsigned long rtc_now = rtc_time(); + + return (rtc_now - sn2_rtc_initial) * + (1000000000 / sn_rtc_cycles_per_second); +} + /** * sn_setup - SN platform setup routine * @cmdline_p: kernel command line @@ -459,6 +468,8 @@ void __init sn_setup(char **cmdline_p) platform_intr_list[ACPI_INTERRUPT_CPEI] = IA64_CPE_VECTOR; + ia64_printk_clock = ia64_sn2_printk_clock; + printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF); /* diff --git a/trunk/arch/mips/kernel/mips-mt-fpaff.c b/trunk/arch/mips/kernel/mips-mt-fpaff.c index bb4f00c0cbe9..892665bb12b1 100644 --- a/trunk/arch/mips/kernel/mips-mt-fpaff.c +++ b/trunk/arch/mips/kernel/mips-mt-fpaff.c @@ -58,13 +58,13 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) return -EFAULT; - get_online_cpus(); + lock_cpu_hotplug(); read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (!p) { read_unlock(&tasklist_lock); - put_online_cpus(); + unlock_cpu_hotplug(); return -ESRCH; } @@ -106,7 +106,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, out_unlock: put_task_struct(p); - put_online_cpus(); + unlock_cpu_hotplug(); return retval; } @@ -125,7 +125,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, if (len < real_len) return -EINVAL; - get_online_cpus(); + lock_cpu_hotplug(); read_lock(&tasklist_lock); retval = -ESRCH; @@ -140,7 +140,7 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, out_unlock: read_unlock(&tasklist_lock); - put_online_cpus(); + unlock_cpu_hotplug(); if (retval) return retval; if (copy_to_user(user_mask_ptr, &mask, real_len)) diff --git a/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c b/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c index c4ad54e0f288..412e6b42986f 100644 --- a/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/trunk/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -153,7 +153,7 @@ static int pseries_add_processor(struct device_node *np) for (i = 0; i < nthreads; i++) cpu_set(i, tmp); - cpu_maps_update_begin(); + lock_cpu_hotplug(); BUG_ON(!cpus_subset(cpu_present_map, cpu_possible_map)); @@ -190,7 +190,7 @@ static int pseries_add_processor(struct device_node *np) } err = 0; out_unlock: - cpu_maps_update_done(); + unlock_cpu_hotplug(); return err; } @@ -211,7 +211,7 @@ static void pseries_remove_processor(struct device_node *np) nthreads = len / sizeof(u32); - cpu_maps_update_begin(); + lock_cpu_hotplug(); for (i = 0; i < nthreads; i++) { for_each_present_cpu(cpu) { if (get_hard_smp_processor_id(cpu) != intserv[i]) @@ -225,7 +225,7 @@ static void pseries_remove_processor(struct device_node *np) printk(KERN_WARNING "Could not find cpu to remove " "with physical id 0x%x\n", intserv[i]); } - cpu_maps_update_done(); + unlock_cpu_hotplug(); } static int pseries_smp_notifier(struct notifier_block *nb, diff --git a/trunk/arch/powerpc/platforms/pseries/rtasd.c b/trunk/arch/powerpc/platforms/pseries/rtasd.c index e3078ce41518..73401c820110 100644 --- a/trunk/arch/powerpc/platforms/pseries/rtasd.c +++ b/trunk/arch/powerpc/platforms/pseries/rtasd.c @@ -382,7 +382,7 @@ static void do_event_scan_all_cpus(long delay) { int cpu; - get_online_cpus(); + lock_cpu_hotplug(); cpu = first_cpu(cpu_online_map); for (;;) { set_cpus_allowed(current, cpumask_of_cpu(cpu)); @@ -390,15 +390,15 @@ static void do_event_scan_all_cpus(long delay) set_cpus_allowed(current, CPU_MASK_ALL); /* Drop hotplug lock, and sleep for the specified delay */ - put_online_cpus(); + unlock_cpu_hotplug(); msleep_interruptible(delay); - get_online_cpus(); + lock_cpu_hotplug(); cpu = next_cpu(cpu, cpu_online_map); if (cpu == NR_CPUS) break; } - put_online_cpus(); + unlock_cpu_hotplug(); } static int rtasd(void *unused) diff --git a/trunk/arch/x86/kernel/cpu/mtrr/main.c b/trunk/arch/x86/kernel/cpu/mtrr/main.c index beb45c9c0835..3b20613325dc 100644 --- a/trunk/arch/x86/kernel/cpu/mtrr/main.c +++ b/trunk/arch/x86/kernel/cpu/mtrr/main.c @@ -349,7 +349,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, replace = -1; /* No CPU hotplug when we change MTRR entries */ - get_online_cpus(); + lock_cpu_hotplug(); /* Search for existing MTRR */ mutex_lock(&mtrr_mutex); for (i = 0; i < num_var_ranges; ++i) { @@ -405,7 +405,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, error = i; out: mutex_unlock(&mtrr_mutex); - put_online_cpus(); + unlock_cpu_hotplug(); return error; } @@ -495,7 +495,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 */ - get_online_cpus(); + lock_cpu_hotplug(); mutex_lock(&mtrr_mutex); if (reg < 0) { /* Search for existing MTRR */ @@ -536,7 +536,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) error = reg; out: mutex_unlock(&mtrr_mutex); - put_online_cpus(); + unlock_cpu_hotplug(); return error; } /** diff --git a/trunk/arch/x86/kernel/entry_64.S b/trunk/arch/x86/kernel/entry_64.S index e70f3881d7e4..3a058bb16409 100644 --- a/trunk/arch/x86/kernel/entry_64.S +++ b/trunk/arch/x86/kernel/entry_64.S @@ -283,7 +283,7 @@ sysret_careful: sysret_signal: TRACE_IRQS_ON sti - testl $_TIF_DO_NOTIFY_MASK,%edx + testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx jz 1f /* Really a signal */ @@ -377,7 +377,7 @@ int_very_careful: jmp int_restore_rest int_signal: - testl $_TIF_DO_NOTIFY_MASK,%edx + testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx jz 1f movq %rsp,%rdi # &ptregs -> arg1 xorl %esi,%esi # oldset -> arg2 @@ -603,7 +603,7 @@ retint_careful: jmp retint_check retint_signal: - testl $_TIF_DO_NOTIFY_MASK,%edx + testl $(_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx jz retint_swapgs TRACE_IRQS_ON sti diff --git a/trunk/arch/x86/kernel/microcode.c b/trunk/arch/x86/kernel/microcode.c index 40cfd5488719..09c315214a5e 100644 --- a/trunk/arch/x86/kernel/microcode.c +++ b/trunk/arch/x86/kernel/microcode.c @@ -436,7 +436,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ return -EINVAL; } - get_online_cpus(); + lock_cpu_hotplug(); mutex_lock(µcode_mutex); user_buffer = (void __user *) buf; @@ -447,7 +447,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_ ret = (ssize_t)len; mutex_unlock(µcode_mutex); - put_online_cpus(); + unlock_cpu_hotplug(); return ret; } @@ -658,14 +658,14 @@ static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz) old = current->cpus_allowed; - get_online_cpus(); + lock_cpu_hotplug(); set_cpus_allowed(current, cpumask_of_cpu(cpu)); mutex_lock(µcode_mutex); if (uci->valid) err = cpu_request_microcode(cpu); mutex_unlock(µcode_mutex); - put_online_cpus(); + unlock_cpu_hotplug(); set_cpus_allowed(current, old); } if (err) @@ -817,9 +817,9 @@ static int __init microcode_init (void) return PTR_ERR(microcode_pdev); } - get_online_cpus(); + lock_cpu_hotplug(); error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver); - put_online_cpus(); + unlock_cpu_hotplug(); if (error) { microcode_dev_exit(); platform_device_unregister(microcode_pdev); @@ -839,9 +839,9 @@ static void __exit microcode_exit (void) unregister_hotcpu_notifier(&mc_cpu_notifier); - get_online_cpus(); + lock_cpu_hotplug(); sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver); - put_online_cpus(); + unlock_cpu_hotplug(); platform_device_unregister(microcode_pdev); } diff --git a/trunk/arch/x86/kernel/signal_32.c b/trunk/arch/x86/kernel/signal_32.c index 20f29e4c1d33..9bdd83022f5f 100644 --- a/trunk/arch/x86/kernel/signal_32.c +++ b/trunk/arch/x86/kernel/signal_32.c @@ -658,9 +658,6 @@ void do_notify_resume(struct pt_regs *regs, void *_unused, /* deal with pending signal delivery */ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) do_signal(regs); - - if (thread_info_flags & _TIF_HRTICK_RESCHED) - hrtick_resched(); clear_thread_flag(TIF_IRET); } diff --git a/trunk/arch/x86/kernel/signal_64.c b/trunk/arch/x86/kernel/signal_64.c index 38d806467c0f..ab086b0357fc 100644 --- a/trunk/arch/x86/kernel/signal_64.c +++ b/trunk/arch/x86/kernel/signal_64.c @@ -480,9 +480,6 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) /* deal with pending signal delivery */ if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK)) do_signal(regs); - - if (thread_info_flags & _TIF_HRTICK_RESCHED) - hrtick_resched(); } void signal_fault(struct pt_regs *regs, void __user *frame, char *where) diff --git a/trunk/arch/x86/kernel/stacktrace.c b/trunk/arch/x86/kernel/stacktrace.c index 55771fd7e545..6fa6cf036c70 100644 --- a/trunk/arch/x86/kernel/stacktrace.c +++ b/trunk/arch/x86/kernel/stacktrace.c @@ -33,19 +33,6 @@ static void save_stack_address(void *data, unsigned long addr) trace->entries[trace->nr_entries++] = addr; } -static void save_stack_address_nosched(void *data, unsigned long addr) -{ - struct stack_trace *trace = (struct stack_trace *)data; - if (in_sched_functions(addr)) - return; - if (trace->skip > 0) { - trace->skip--; - return; - } - if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = addr; -} - static const struct stacktrace_ops save_stack_ops = { .warning = save_stack_warning, .warning_symbol = save_stack_warning_symbol, @@ -53,13 +40,6 @@ static const struct stacktrace_ops save_stack_ops = { .address = save_stack_address, }; -static const struct stacktrace_ops save_stack_ops_nosched = { - .warning = save_stack_warning, - .warning_symbol = save_stack_warning_symbol, - .stack = save_stack_stack, - .address = save_stack_address_nosched, -}; - /* * Save stack-backtrace addresses into a stack_trace buffer. */ @@ -70,10 +50,3 @@ void save_stack_trace(struct stack_trace *trace) trace->entries[trace->nr_entries++] = ULONG_MAX; } EXPORT_SYMBOL(save_stack_trace); - -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) -{ - dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace); - if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = ULONG_MAX; -} diff --git a/trunk/drivers/ata/Kconfig b/trunk/drivers/ata/Kconfig index 2478cca653de..ba63619ae5df 100644 --- a/trunk/drivers/ata/Kconfig +++ b/trunk/drivers/ata/Kconfig @@ -459,15 +459,6 @@ config PATA_NETCELL If unsure, say N. -config PATA_NINJA32 - tristate "Ninja32/Delkin Cardbus ATA support (Experimental)" - depends on PCI && EXPERIMENTAL - help - This option enables support for the Ninja32, Delkin and - possibly other brands of Cardbus ATA adapter - - If unsure, say N. - config PATA_NS87410 tristate "Nat Semi NS87410 PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/trunk/drivers/ata/Makefile b/trunk/drivers/ata/Makefile index 82550c16818c..b13feb2c5dae 100644 --- a/trunk/drivers/ata/Makefile +++ b/trunk/drivers/ata/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_PATA_IT821X) += pata_it821x.o obj-$(CONFIG_PATA_IT8213) += pata_it8213.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o -obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o diff --git a/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c index 6f089b899a1a..54f38c21dd95 100644 --- a/trunk/drivers/ata/ahci.c +++ b/trunk/drivers/ata/ahci.c @@ -198,18 +198,18 @@ enum { }; struct ahci_cmd_hdr { - __le32 opts; - __le32 status; - __le32 tbl_addr; - __le32 tbl_addr_hi; - __le32 reserved[4]; + u32 opts; + u32 status; + u32 tbl_addr; + u32 tbl_addr_hi; + u32 reserved[4]; }; struct ahci_sg { - __le32 addr; - __le32 addr_hi; - __le32 reserved; - __le32 flags_size; + u32 addr; + u32 addr_hi; + u32 reserved; + u32 flags_size; }; struct ahci_host_priv { @@ -597,20 +597,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) return __ahci_port_base(ap->host, ap->port_no); } -static void ahci_enable_ahci(void __iomem *mmio) -{ - u32 tmp; - - /* turn on AHCI_EN */ - tmp = readl(mmio + HOST_CTL); - if (!(tmp & HOST_AHCI_EN)) { - tmp |= HOST_AHCI_EN; - writel(tmp, mmio + HOST_CTL); - tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ - WARN_ON(!(tmp & HOST_AHCI_EN)); - } -} - /** * ahci_save_initial_config - Save and fixup initial config values * @pdev: target PCI device @@ -633,9 +619,6 @@ static void ahci_save_initial_config(struct pci_dev *pdev, u32 cap, port_map; int i; - /* make sure AHCI mode is enabled before accessing CAP */ - ahci_enable_ahci(mmio); - /* Values prefixed with saved_ are written back to host after * reset. Values without are used for driver operation. */ @@ -1053,17 +1036,19 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg) static int ahci_reset_controller(struct ata_host *host) { struct pci_dev *pdev = to_pci_dev(host->dev); - struct ahci_host_priv *hpriv = host->private_data; void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 tmp; /* we must be in AHCI mode, before using anything * AHCI-specific, such as HOST_RESET. */ - ahci_enable_ahci(mmio); + tmp = readl(mmio + HOST_CTL); + if (!(tmp & HOST_AHCI_EN)) { + tmp |= HOST_AHCI_EN; + writel(tmp, mmio + HOST_CTL); + } /* global controller reset */ - tmp = readl(mmio + HOST_CTL); if ((tmp & HOST_RESET) == 0) { writel(tmp | HOST_RESET, mmio + HOST_CTL); readl(mmio + HOST_CTL); /* flush */ @@ -1082,7 +1067,8 @@ static int ahci_reset_controller(struct ata_host *host) } /* turn on AHCI mode */ - ahci_enable_ahci(mmio); + writel(HOST_AHCI_EN, mmio + HOST_CTL); + (void) readl(mmio + HOST_CTL); /* flush */ /* some registers might be cleared on reset. restore initial values */ ahci_restore_initial_config(host); @@ -1092,10 +1078,8 @@ static int ahci_reset_controller(struct ata_host *host) /* configure PCS */ pci_read_config_word(pdev, 0x92, &tmp16); - if ((tmp16 & hpriv->port_map) != hpriv->port_map) { - tmp16 |= hpriv->port_map; - pci_write_config_word(pdev, 0x92, tmp16); - } + tmp16 |= 0xf; + pci_write_config_word(pdev, 0x92, tmp16); } return 0; @@ -1496,31 +1480,35 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) { struct scatterlist *sg; - struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; - unsigned int si; + struct ahci_sg *ahci_sg; + unsigned int n_sg = 0; VPRINTK("ENTER\n"); /* * Next, the S/G list. */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; + ata_for_each_sg(sg, qc) { dma_addr_t addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); - ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff); - ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); - ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1); + ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); + ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); + ahci_sg->flags_size = cpu_to_le32(sg_len - 1); + + ahci_sg++; + n_sg++; } - return si; + return n_sg; } static void ahci_qc_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ahci_port_priv *pp = ap->private_data; - int is_atapi = ata_is_atapi(qc->tf.protocol); + int is_atapi = is_atapi_taskfile(&qc->tf); void *cmd_tbl; u32 opts; const u32 cmd_fis_len = 5; /* five dwords */ diff --git a/trunk/drivers/ata/ata_generic.c b/trunk/drivers/ata/ata_generic.c index 20534202fc79..90329982bef7 100644 --- a/trunk/drivers/ata/ata_generic.c +++ b/trunk/drivers/ata/ata_generic.c @@ -26,7 +26,7 @@ #include #define DRV_NAME "ata_generic" -#define DRV_VERSION "0.2.15" +#define DRV_VERSION "0.2.13" /* * A generic parallel ATA driver using libata @@ -48,47 +48,27 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused) struct ata_port *ap = link->ap; int dma_enabled = 0; struct ata_device *dev; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Bits 5 and 6 indicate if DMA is active on master/slave */ if (ap->ioaddr.bmdma_addr) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); - if (pdev->vendor == PCI_VENDOR_ID_CENATEK) - dma_enabled = 0xFF; - ata_link_for_each_dev(dev, link) { - if (!ata_dev_enabled(dev)) - continue; - - /* We don't really care */ - dev->pio_mode = XFER_PIO_0; - dev->dma_mode = XFER_MW_DMA_0; - /* We do need the right mode information for DMA or PIO - and this comes from the current configuration flags */ - if (dma_enabled & (1 << (5 + dev->devno))) { - unsigned int xfer_mask = ata_id_xfermask(dev->id); - const char *name; - - if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA)) - name = ata_mode_string(xfer_mask); - else { - /* SWDMA perhaps? */ - name = "DMA"; - xfer_mask |= ata_xfer_mode2mask(XFER_MW_DMA_0); + if (ata_dev_enabled(dev)) { + /* We don't really care */ + dev->pio_mode = XFER_PIO_0; + dev->dma_mode = XFER_MW_DMA_0; + /* We do need the right mode information for DMA or PIO + and this comes from the current configuration flags */ + if (dma_enabled & (1 << (5 + dev->devno))) { + ata_id_to_dma_mode(dev, XFER_MW_DMA_0); + dev->flags &= ~ATA_DFLAG_PIO; + } else { + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); + dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; } - - ata_dev_printk(dev, KERN_INFO, "configured for %s\n", - name); - - dev->xfer_mode = ata_xfer_mask2mode(xfer_mask); - dev->xfer_shift = ata_xfer_mode2shift(dev->xfer_mode); - dev->flags &= ~ATA_DFLAG_PIO; - } else { - ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); - dev->xfer_mode = XFER_PIO_0; - dev->xfer_shift = ATA_SHIFT_PIO; - dev->flags |= ATA_DFLAG_PIO; } } return 0; @@ -205,7 +185,6 @@ static struct pci_device_id ata_generic[] = { { PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), }, { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), }, - { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), }, diff --git a/trunk/drivers/ata/ata_piix.c b/trunk/drivers/ata/ata_piix.c index a65c8ae5c461..b406b39b878e 100644 --- a/trunk/drivers/ata/ata_piix.c +++ b/trunk/drivers/ata/ata_piix.c @@ -101,21 +101,39 @@ enum { ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ PIIX_SCC = 0x0A, /* sub-class code register */ - PIIX_SIDPR_BAR = 5, - PIIX_SIDPR_LEN = 16, - PIIX_SIDPR_IDX = 0, - PIIX_SIDPR_DATA = 4, + PIIX_FLAG_SCR = (1 << 26), /* SCR available */ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ - PIIX_FLAG_SIDPR = (1 << 29), /* SATA idx/data pair regs */ PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, + /* combined mode. if set, PATA is channel 0. + * if clear, PATA is channel 1. + */ + PIIX_PORT_ENABLED = (1 << 0), + PIIX_PORT_PRESENT = (1 << 4), + PIIX_80C_PRI = (1 << 5) | (1 << 4), PIIX_80C_SEC = (1 << 7) | (1 << 6), + /* controller IDs */ + piix_pata_mwdma = 0, /* PIIX3 MWDMA only */ + piix_pata_33, /* PIIX4 at 33Mhz */ + ich_pata_33, /* ICH up to UDMA 33 only */ + ich_pata_66, /* ICH up to 66 Mhz */ + ich_pata_100, /* ICH up to UDMA 100 */ + ich5_sata, + ich6_sata, + ich6_sata_ahci, + ich6m_sata_ahci, + ich8_sata_ahci, + ich8_2port_sata, + ich8m_apple_sata_ahci, /* locks up on second port enable */ + tolapai_sata_ahci, + piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */ + /* constants for mapping table */ P0 = 0, /* port 0 */ P1 = 1, /* port 1 */ @@ -131,24 +149,6 @@ enum { PIIX_HOST_BROKEN_SUSPEND = (1 << 24), }; -enum piix_controller_ids { - /* controller IDs */ - piix_pata_mwdma, /* PIIX3 MWDMA only */ - piix_pata_33, /* PIIX4 at 33Mhz */ - ich_pata_33, /* ICH up to UDMA 33 only */ - ich_pata_66, /* ICH up to 66 Mhz */ - ich_pata_100, /* ICH up to UDMA 100 */ - ich5_sata, - ich6_sata, - ich6_sata_ahci, - ich6m_sata_ahci, - ich8_sata_ahci, - ich8_2port_sata, - ich8m_apple_sata_ahci, /* locks up on second port enable */ - tolapai_sata_ahci, - piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */ -}; - struct piix_map_db { const u32 mask; const u16 port_enable; @@ -157,7 +157,6 @@ struct piix_map_db { struct piix_host_priv { const int *map; - void __iomem *sidpr; }; static int piix_init_one(struct pci_dev *pdev, @@ -168,9 +167,6 @@ static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int ich_pata_cable_detect(struct ata_port *ap); static u8 piix_vmw_bmdma_status(struct ata_port *ap); -static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val); -static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val); -static void piix_sidpr_error_handler(struct ata_port *ap); #ifdef CONFIG_PM static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int piix_pci_device_resume(struct pci_dev *pdev); @@ -325,6 +321,7 @@ static const struct ata_port_operations piix_pata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ata_cable_40wire, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, @@ -356,6 +353,7 @@ static const struct ata_port_operations ich_pata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ich_pata_cable_detect, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, @@ -382,6 +380,7 @@ static const struct ata_port_operations piix_sata_ops = { .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, + .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, @@ -420,35 +419,6 @@ static const struct ata_port_operations piix_vmw_ops = { .port_start = ata_port_start, }; -static const struct ata_port_operations piix_sidpr_sata_ops = { - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, - - .scr_read = piix_sidpr_scr_read, - .scr_write = piix_sidpr_scr_write, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = piix_sidpr_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_port_start, -}; - static const struct piix_map_db ich5_map_db = { .mask = 0x7, .port_enable = 0x3, @@ -556,6 +526,7 @@ static const struct piix_map_db *piix_map_db_table[] = { static struct ata_port_info piix_port_info[] = { [piix_pata_mwdma] = /* PIIX3 MWDMA only */ { + .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ @@ -564,6 +535,7 @@ static struct ata_port_info piix_port_info[] = { [piix_pata_33] = /* PIIX4 at 33MHz */ { + .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ @@ -573,6 +545,7 @@ static struct ata_port_info piix_port_info[] = { [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/ { + .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ @@ -582,6 +555,7 @@ static struct ata_port_info piix_port_info[] = { [ich_pata_66] = /* ICH controllers up to 66MHz */ { + .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ @@ -591,6 +565,7 @@ static struct ata_port_info piix_port_info[] = { [ich_pata_100] = { + .sht = &piix_sht, .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 */ @@ -600,6 +575,7 @@ static struct ata_port_info piix_port_info[] = { [ich5_sata] = { + .sht = &piix_sht, .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -609,7 +585,8 @@ static struct ata_port_info piix_port_info[] = { [ich6_sata] = { - .flags = PIIX_SATA_FLAGS, + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -618,7 +595,9 @@ static struct ata_port_info piix_port_info[] = { [ich6_sata_ahci] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -627,7 +606,9 @@ static struct ata_port_info piix_port_info[] = { [ich6m_sata_ahci] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -636,8 +617,9 @@ static struct ata_port_info piix_port_info[] = { [ich8_sata_ahci] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | - PIIX_FLAG_SIDPR, + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -646,8 +628,9 @@ static struct ata_port_info piix_port_info[] = { [ich8_2port_sata] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | - PIIX_FLAG_SIDPR, + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -656,7 +639,9 @@ static struct ata_port_info piix_port_info[] = { [tolapai_sata_ahci] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -665,8 +650,9 @@ static struct ata_port_info piix_port_info[] = { [ich8m_apple_sata_ahci] = { - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | - PIIX_FLAG_SIDPR, + .sht = &piix_sht, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -1015,180 +1001,6 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev) do_pata_set_dmamode(ap, adev, 1); } -/* - * Serial ATA Index/Data Pair Superset Registers access - * - * Beginning from ICH8, there's a sane way to access SCRs using index - * and data register pair located at BAR5. This creates an - * interesting problem of mapping two SCRs to one port. - * - * Although they have separate SCRs, the master and slave aren't - * independent enough to be treated as separate links - e.g. softreset - * resets both. Also, there's no protocol defined for hard resetting - * singled device sharing the virtual port (no defined way to acquire - * device signature). This is worked around by merging the SCR values - * into one sensible value and requesting follow-up SRST after - * hardreset. - * - * SCR merging is perfomed in nibbles which is the unit contents in - * SCRs are organized. If two values are equal, the value is used. - * When they differ, merge table which lists precedence of possible - * values is consulted and the first match or the last entry when - * nothing matches is used. When there's no merge table for the - * specific nibble, value from the first port is used. - */ -static const int piix_sidx_map[] = { - [SCR_STATUS] = 0, - [SCR_ERROR] = 2, - [SCR_CONTROL] = 1, -}; - -static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg) -{ - struct ata_port *ap = dev->link->ap; - struct piix_host_priv *hpriv = ap->host->private_data; - - iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg], - hpriv->sidpr + PIIX_SIDPR_IDX); -} - -static int piix_sidpr_read(struct ata_device *dev, unsigned int reg) -{ - struct piix_host_priv *hpriv = dev->link->ap->host->private_data; - - piix_sidpr_sel(dev, reg); - return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); -} - -static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val) -{ - struct piix_host_priv *hpriv = dev->link->ap->host->private_data; - - piix_sidpr_sel(dev, reg); - iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); -} - -u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl) -{ - u32 val = 0; - int i, mi; - - for (i = 0, mi = 0; i < 32 / 4; i++) { - u8 c0 = (val0 >> (i * 4)) & 0xf; - u8 c1 = (val1 >> (i * 4)) & 0xf; - u8 merged = c0; - const int *cur; - - /* if no merge preference, assume the first value */ - cur = merge_tbl[mi]; - if (!cur) - goto done; - mi++; - - /* if two values equal, use it */ - if (c0 == c1) - goto done; - - /* choose the first match or the last from the merge table */ - while (*cur != -1) { - if (c0 == *cur || c1 == *cur) - break; - cur++; - } - if (*cur == -1) - cur--; - merged = *cur; - done: - val |= merged << (i * 4); - } - - return val; -} - -static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val) -{ - const int * const sstatus_merge_tbl[] = { - /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 }, - /* SPD */ (const int []){ 2, 1, 0, -1 }, - /* IPM */ (const int []){ 6, 2, 1, 0, -1 }, - NULL, - }; - const int * const scontrol_merge_tbl[] = { - /* DET */ (const int []){ 1, 0, 4, 0, -1 }, - /* SPD */ (const int []){ 0, 2, 1, 0, -1 }, - /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 }, - NULL, - }; - u32 v0, v1; - - if (reg >= ARRAY_SIZE(piix_sidx_map)) - return -EINVAL; - - if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) { - *val = piix_sidpr_read(&ap->link.device[0], reg); - return 0; - } - - v0 = piix_sidpr_read(&ap->link.device[0], reg); - v1 = piix_sidpr_read(&ap->link.device[1], reg); - - switch (reg) { - case SCR_STATUS: - *val = piix_merge_scr(v0, v1, sstatus_merge_tbl); - break; - case SCR_ERROR: - *val = v0 | v1; - break; - case SCR_CONTROL: - *val = piix_merge_scr(v0, v1, scontrol_merge_tbl); - break; - } - - return 0; -} - -static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val) -{ - if (reg >= ARRAY_SIZE(piix_sidx_map)) - return -EINVAL; - - piix_sidpr_write(&ap->link.device[0], reg, val); - - if (ap->flags & ATA_FLAG_SLAVE_POSS) - piix_sidpr_write(&ap->link.device[1], reg, val); - - return 0; -} - -static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); - int rc; - - /* do hardreset */ - rc = sata_link_hardreset(link, timing, deadline); - if (rc) { - ata_link_printk(link, KERN_ERR, - "COMRESET failed (errno=%d)\n", rc); - return rc; - } - - /* TODO: phy layer with polling, timeouts, etc. */ - if (ata_link_offline(link)) { - *class = ATA_DEV_NONE; - return 0; - } - - return -EAGAIN; -} - -static void piix_sidpr_error_handler(struct ata_port *ap) -{ - ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, - piix_sidpr_hardreset, ata_std_postreset); -} - #ifdef CONFIG_PM static int piix_broken_suspend(void) { @@ -1221,13 +1033,6 @@ static int piix_broken_suspend(void) DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"), }, }, - { - .ident = "TECRA M6", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M6"), - }, - }, { .ident = "TECRA M7", .matches = { @@ -1242,13 +1047,6 @@ static int piix_broken_suspend(void) DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A8"), }, }, - { - .ident = "Satellite R20", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R20"), - }, - }, { .ident = "Satellite R25", .matches = { @@ -1455,10 +1253,10 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) return no_piix_dma; } -static void __devinit piix_init_pcs(struct ata_host *host, +static void __devinit piix_init_pcs(struct pci_dev *pdev, + struct ata_port_info *pinfo, const struct piix_map_db *map_db) { - struct pci_dev *pdev = to_pci_dev(host->dev); u16 pcs, new_pcs; pci_read_config_word(pdev, ICH5_PCS, &pcs); @@ -1472,10 +1270,11 @@ static void __devinit piix_init_pcs(struct ata_host *host, } } -static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, - struct ata_port_info *pinfo, - const struct piix_map_db *map_db) +static void __devinit piix_init_sata_map(struct pci_dev *pdev, + struct ata_port_info *pinfo, + const struct piix_map_db *map_db) { + struct piix_host_priv *hpriv = pinfo[0].private_data; const int *map; int i, invalid_map = 0; u8 map_value; @@ -1499,6 +1298,7 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, case IDE: WARN_ON((i & 1) || map[i + 1] != IDE); pinfo[i / 2] = piix_port_info[ich_pata_100]; + pinfo[i / 2].private_data = hpriv; i++; printk(" IDE IDE"); break; @@ -1516,33 +1316,7 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, dev_printk(KERN_ERR, &pdev->dev, "invalid MAP value %u\n", map_value); - return map; -} - -static void __devinit piix_init_sidpr(struct ata_host *host) -{ - struct pci_dev *pdev = to_pci_dev(host->dev); - struct piix_host_priv *hpriv = host->private_data; - int i; - - /* check for availability */ - for (i = 0; i < 4; i++) - if (hpriv->map[i] == IDE) - return; - - if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR)) - return; - - if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 || - pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN) - return; - - if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME)) - return; - - hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR]; - host->ports[0]->ops = &piix_sidpr_sata_ops; - host->ports[1]->ops = &piix_sidpr_sata_ops; + hpriv->map = map; } static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) @@ -1601,10 +1375,8 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct device *dev = &pdev->dev; struct ata_port_info port_info[2]; const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; - unsigned long port_flags; - struct ata_host *host; struct piix_host_priv *hpriv; - int rc; + unsigned long port_flags; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, @@ -1614,31 +1386,17 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!in_module_init) return -ENODEV; - port_info[0] = piix_port_info[ent->driver_data]; - port_info[1] = piix_port_info[ent->driver_data]; - - port_flags = port_info[0].flags; - - /* enable device and prepare host */ - rc = pcim_enable_device(pdev); - if (rc) - return rc; - - /* SATA map init can change port_info, do it before prepping host */ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - if (port_flags & ATA_FLAG_SATA) - hpriv->map = piix_init_sata_map(pdev, port_info, - piix_map_db_table[ent->driver_data]); + port_info[0] = piix_port_info[ent->driver_data]; + port_info[1] = piix_port_info[ent->driver_data]; + port_info[0].private_data = hpriv; + port_info[1].private_data = hpriv; - rc = ata_pci_prepare_sff_host(pdev, ppi, &host); - if (rc) - return rc; - host->private_data = hpriv; + port_flags = port_info[0].flags; - /* initialize controller */ if (port_flags & PIIX_FLAG_AHCI) { u8 tmp; pci_read_config_byte(pdev, PIIX_SCC, &tmp); @@ -1649,9 +1407,12 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } } + /* Initialize SATA map */ if (port_flags & ATA_FLAG_SATA) { - piix_init_pcs(host, piix_map_db_table[ent->driver_data]); - piix_init_sidpr(host); + piix_init_sata_map(pdev, port_info, + piix_map_db_table[ent->driver_data]); + piix_init_pcs(pdev, port_info, + piix_map_db_table[ent->driver_data]); } /* apply IOCFG bit18 quirk */ @@ -1670,14 +1431,12 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* This writes into the master table but it does not really matter for this errata as we will apply it to all the PIIX devices on the board */ - host->ports[0]->mwdma_mask = 0; - host->ports[0]->udma_mask = 0; - host->ports[1]->mwdma_mask = 0; - host->ports[1]->udma_mask = 0; + port_info[0].mwdma_mask = 0; + port_info[0].udma_mask = 0; + port_info[1].mwdma_mask = 0; + port_info[1].udma_mask = 0; } - - pci_set_master(pdev); - return ata_pci_activate_sff_host(host, ata_interrupt, &piix_sht); + return ata_pci_init_one(pdev, ppi); } static int __init piix_init(void) diff --git a/trunk/drivers/ata/libata-acpi.c b/trunk/drivers/ata/libata-acpi.c index 9e8ec19260af..7bf4befd96bc 100644 --- a/trunk/drivers/ata/libata-acpi.c +++ b/trunk/drivers/ata/libata-acpi.c @@ -441,78 +441,41 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) return rc; } -/** - * ata_acpi_gtm_xfermode - determine xfermode from GTM parameter - * @dev: target device - * @gtm: GTM parameter to use - * - * Determine xfermask for @dev from @gtm. - * - * LOCKING: - * None. - * - * RETURNS: - * Determined xfermask. - */ -unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev, - const struct ata_acpi_gtm *gtm) -{ - unsigned long xfer_mask = 0; - unsigned int type; - int unit; - u8 mode; - - /* we always use the 0 slot for crap hardware */ - unit = dev->devno; - if (!(gtm->flags & 0x10)) - unit = 0; - - /* PIO */ - mode = ata_timing_cycle2mode(ATA_SHIFT_PIO, gtm->drive[unit].pio); - xfer_mask |= ata_xfer_mode2mask(mode); - - /* See if we have MWDMA or UDMA data. We don't bother with - * MWDMA if UDMA is available as this means the BIOS set UDMA - * and our error changedown if it works is UDMA to PIO anyway. - */ - if (!(gtm->flags & (1 << (2 * unit)))) - type = ATA_SHIFT_MWDMA; - else - type = ATA_SHIFT_UDMA; - - mode = ata_timing_cycle2mode(type, gtm->drive[unit].dma); - xfer_mask |= ata_xfer_mode2mask(mode); - - return xfer_mask; -} -EXPORT_SYMBOL_GPL(ata_acpi_gtm_xfermask); - /** * ata_acpi_cbl_80wire - Check for 80 wire cable * @ap: Port to check - * @gtm: GTM data to use * - * Return 1 if the @gtm indicates the BIOS selected an 80wire mode. + * Return 1 if the ACPI mode data for this port indicates the BIOS selected + * an 80wire mode. */ -int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm) -{ - struct ata_device *dev; - - ata_link_for_each_dev(dev, &ap->link) { - unsigned long xfer_mask, udma_mask; - if (!ata_dev_enabled(dev)) - continue; - - xfer_mask = ata_acpi_gtm_xfermask(dev, gtm); - ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask); +int ata_acpi_cbl_80wire(struct ata_port *ap) +{ + const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); + int valid = 0; - if (udma_mask & ~ATA_UDMA_MASK_40C) - return 1; - } + if (!gtm) + return 0; + /* Split timing, DMA enabled */ + if ((gtm->flags & 0x11) == 0x11 && gtm->drive[0].dma < 55) + valid |= 1; + if ((gtm->flags & 0x14) == 0x14 && gtm->drive[1].dma < 55) + valid |= 2; + /* Shared timing, DMA enabled */ + if ((gtm->flags & 0x11) == 0x01 && gtm->drive[0].dma < 55) + valid |= 1; + if ((gtm->flags & 0x14) == 0x04 && gtm->drive[0].dma < 55) + valid |= 2; + + /* Drive check */ + if ((valid & 1) && ata_dev_enabled(&ap->link.device[0])) + return 1; + if ((valid & 2) && ata_dev_enabled(&ap->link.device[1])) + return 1; return 0; } + EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); static void ata_acpi_gtf_to_tf(struct ata_device *dev, @@ -812,36 +775,6 @@ void ata_acpi_on_resume(struct ata_port *ap) } } -/** - * ata_acpi_set_state - set the port power state - * @ap: target ATA port - * @state: state, on/off - * - * This function executes the _PS0/_PS3 ACPI method to set the power state. - * ACPI spec requires _PS0 when IDE power on and _PS3 when power off - */ -void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) -{ - struct ata_device *dev; - - if (!ap->acpi_handle || (ap->flags & ATA_FLAG_ACPI_SATA)) - return; - - /* channel first and then drives for power on and vica versa - for power off */ - if (state.event == PM_EVENT_ON) - acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0); - - ata_link_for_each_dev(dev, &ap->link) { - if (dev->acpi_handle && ata_dev_enabled(dev)) - acpi_bus_set_power(dev->acpi_handle, - state.event == PM_EVENT_ON ? - ACPI_STATE_D0 : ACPI_STATE_D3); - } - if (state.event != PM_EVENT_ON) - acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D3); -} - /** * ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration * @dev: target ATA device diff --git a/trunk/drivers/ata/libata-core.c b/trunk/drivers/ata/libata-core.c index ce803d18e96a..6380726f7538 100644 --- a/trunk/drivers/ata/libata-core.c +++ b/trunk/drivers/ata/libata-core.c @@ -119,10 +119,6 @@ int libata_noacpi = 0; module_param_named(noacpi, libata_noacpi, int, 0444); MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set"); -int libata_allow_tpm = 0; -module_param_named(allow_tpm, libata_allow_tpm, int, 0444); -MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands"); - MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); @@ -454,9 +450,9 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, * RETURNS: * Packed xfer_mask. */ -unsigned long ata_pack_xfermask(unsigned long pio_mask, - unsigned long mwdma_mask, - unsigned long udma_mask) +static unsigned int ata_pack_xfermask(unsigned int pio_mask, + unsigned int mwdma_mask, + unsigned int udma_mask) { return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) | @@ -473,8 +469,10 @@ unsigned long ata_pack_xfermask(unsigned long pio_mask, * Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask. * Any NULL distination masks will be ignored. */ -void ata_unpack_xfermask(unsigned long xfer_mask, unsigned long *pio_mask, - unsigned long *mwdma_mask, unsigned long *udma_mask) +static void ata_unpack_xfermask(unsigned int xfer_mask, + unsigned int *pio_mask, + unsigned int *mwdma_mask, + unsigned int *udma_mask) { if (pio_mask) *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO; @@ -488,9 +486,9 @@ static const struct ata_xfer_ent { int shift, bits; u8 base; } ata_xfer_tbl[] = { - { ATA_SHIFT_PIO, ATA_NR_PIO_MODES, XFER_PIO_0 }, - { ATA_SHIFT_MWDMA, ATA_NR_MWDMA_MODES, XFER_MW_DMA_0 }, - { ATA_SHIFT_UDMA, ATA_NR_UDMA_MODES, XFER_UDMA_0 }, + { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 }, + { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 }, + { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 }, { -1, }, }; @@ -505,9 +503,9 @@ static const struct ata_xfer_ent { * None. * * RETURNS: - * Matching XFER_* value, 0xff if no match found. + * Matching XFER_* value, 0 if no match found. */ -u8 ata_xfer_mask2mode(unsigned long xfer_mask) +static u8 ata_xfer_mask2mode(unsigned int xfer_mask) { int highbit = fls(xfer_mask) - 1; const struct ata_xfer_ent *ent; @@ -515,7 +513,7 @@ u8 ata_xfer_mask2mode(unsigned long xfer_mask) for (ent = ata_xfer_tbl; ent->shift >= 0; ent++) if (highbit >= ent->shift && highbit < ent->shift + ent->bits) return ent->base + highbit - ent->shift; - return 0xff; + return 0; } /** @@ -530,14 +528,13 @@ u8 ata_xfer_mask2mode(unsigned long xfer_mask) * RETURNS: * Matching xfer_mask, 0 if no match found. */ -unsigned long ata_xfer_mode2mask(u8 xfer_mode) +static unsigned int ata_xfer_mode2mask(u8 xfer_mode) { const struct ata_xfer_ent *ent; for (ent = ata_xfer_tbl; ent->shift >= 0; ent++) if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits) - return ((2 << (ent->shift + xfer_mode - ent->base)) - 1) - & ~((1 << ent->shift) - 1); + return 1 << (ent->shift + xfer_mode - ent->base); return 0; } @@ -553,7 +550,7 @@ unsigned long ata_xfer_mode2mask(u8 xfer_mode) * RETURNS: * Matching xfer_shift, -1 if no match found. */ -int ata_xfer_mode2shift(unsigned long xfer_mode) +static int ata_xfer_mode2shift(unsigned int xfer_mode) { const struct ata_xfer_ent *ent; @@ -577,7 +574,7 @@ int ata_xfer_mode2shift(unsigned long xfer_mode) * Constant C string representing highest speed listed in * @mode_mask, or the constant C string "". */ -const char *ata_mode_string(unsigned long xfer_mask) +static const char *ata_mode_string(unsigned int xfer_mask) { static const char * const xfer_mode_str[] = { "PIO0", @@ -950,8 +947,8 @@ unsigned int ata_dev_try_classify(struct ata_device *dev, int present, if (r_err) *r_err = err; - /* see if device passed diags: continue and warn later */ - if (err == 0) + /* see if device passed diags: if master then continue and warn later */ + if (err == 0 && dev->devno == 0) /* diagnostic fail : do nothing _YET_ */ dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) @@ -1288,6 +1285,48 @@ static int ata_hpa_resize(struct ata_device *dev) return 0; } +/** + * ata_id_to_dma_mode - Identify DMA mode from id block + * @dev: device to identify + * @unknown: mode to assume if we cannot tell + * + * Set up the timing values for the device based upon the identify + * reported values for the DMA mode. This function is used by drivers + * which rely upon firmware configured modes, but wish to report the + * mode correctly when possible. + * + * In addition we emit similarly formatted messages to the default + * ata_dev_set_mode handler, in order to provide consistency of + * presentation. + */ + +void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown) +{ + unsigned int mask; + u8 mode; + + /* Pack the DMA modes */ + mask = ((dev->id[63] >> 8) << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA; + if (dev->id[53] & 0x04) + mask |= ((dev->id[88] >> 8) << ATA_SHIFT_UDMA) & ATA_MASK_UDMA; + + /* Select the mode in use */ + mode = ata_xfer_mask2mode(mask); + + if (mode != 0) { + ata_dev_printk(dev, KERN_INFO, "configured for %s\n", + ata_mode_string(mask)); + } else { + /* SWDMA perhaps ? */ + mode = unknown; + ata_dev_printk(dev, KERN_INFO, "configured for DMA\n"); + } + + /* Configure the device reporting */ + dev->xfer_mode = mode; + dev->xfer_shift = ata_xfer_mode2shift(mode); +} + /** * ata_noop_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate @@ -1425,9 +1464,9 @@ static inline void ata_dump_id(const u16 *id) * RETURNS: * Computed xfermask */ -unsigned long ata_id_xfermask(const u16 *id) +static unsigned int ata_id_xfermask(const u16 *id) { - unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned int pio_mask, mwdma_mask, udma_mask; /* Usual case. Word 53 indicates word 64 is valid */ if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { @@ -1480,7 +1519,7 @@ unsigned long ata_id_xfermask(const u16 *id) } /** - * ata_pio_queue_task - Queue port_task + * ata_port_queue_task - Queue port_task * @ap: The ata_port to queue port_task for * @fn: workqueue function to be scheduled * @data: data for @fn to use @@ -1492,15 +1531,16 @@ unsigned long ata_id_xfermask(const u16 *id) * one task is active at any given time. * * libata core layer takes care of synchronization between - * port_task and EH. ata_pio_queue_task() may be ignored for EH + * port_task and EH. ata_port_queue_task() may be ignored for EH * synchronization. * * LOCKING: * Inherited from caller. */ -static void ata_pio_queue_task(struct ata_port *ap, void *data, - unsigned long delay) +void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, + unsigned long delay) { + PREPARE_DELAYED_WORK(&ap->port_task, fn); ap->port_task_data = data; /* may fail if ata_port_flush_task() in progress */ @@ -2050,7 +2090,7 @@ int ata_dev_configure(struct ata_device *dev) struct ata_eh_context *ehc = &dev->link->eh_context; int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; - unsigned long xfer_mask; + unsigned int xfer_mask; char revbuf[7]; /* XYZ-99\0 */ char fwrevbuf[ATA_ID_FW_REV_LEN+1]; char modelbuf[ATA_ID_PROD_LEN+1]; @@ -2121,14 +2161,8 @@ int ata_dev_configure(struct ata_device *dev) "supports DRM functions and may " "not be fully accessable.\n"); snprintf(revbuf, 7, "CFA"); - } else { + } else snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); - /* Warn the user if the device has TPM extensions */ - if (ata_id_has_tpm(id)) - ata_dev_printk(dev, KERN_WARNING, - "supports DRM functions and may " - "not be fully accessable.\n"); - } dev->n_sectors = ata_id_n_sectors(id); @@ -2261,8 +2295,19 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_DIPM; } - /* Limit PATA drive on SATA cable bridge transfers to udma5, - 200 sectors */ + if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + /* Let the user know. We don't want to disallow opens for + rescue purposes, or in case the vendor is just a blithering + idiot */ + if (print_info) { + ata_dev_printk(dev, KERN_WARNING, +"Drive reports diagnostics failure. This may indicate a drive\n"); + ata_dev_printk(dev, KERN_WARNING, +"fault or invalid emulation. Contact drive vendor for information.\n"); + } + } + + /* limit bridge transfers to udma5, 200 sectors */ if (ata_dev_knobble(dev)) { if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, @@ -2291,21 +2336,6 @@ int ata_dev_configure(struct ata_device *dev) if (ap->ops->dev_config) ap->ops->dev_config(dev); - if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { - /* Let the user know. We don't want to disallow opens for - rescue purposes, or in case the vendor is just a blithering - idiot. Do this after the dev_config call as some controllers - with buggy firmware may want to avoid reporting false device - bugs */ - - if (print_info) { - ata_dev_printk(dev, KERN_WARNING, -"Drive reports diagnostics failure. This may indicate a drive\n"); - ata_dev_printk(dev, KERN_WARNING, -"fault or invalid emulation. Contact drive vendor for information.\n"); - } - } - if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n", __FUNCTION__, ata_chk_status(ap)); @@ -2356,18 +2386,6 @@ int ata_cable_unknown(struct ata_port *ap) return ATA_CBL_PATA_UNK; } -/** - * ata_cable_ignore - return ignored PATA cable. - * @ap: port - * - * Helper method for drivers which don't use cable type to limit - * transfer mode. - */ -int ata_cable_ignore(struct ata_port *ap) -{ - return ATA_CBL_PATA_IGN; -} - /** * ata_cable_sata - return SATA cable type * @ap: port @@ -2763,33 +2781,38 @@ int sata_set_spd(struct ata_link *link) */ static const struct ata_timing ata_timing[] = { -/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ - { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, - { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, - { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, - { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, - { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, - { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 }, - { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 }, - { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, - { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, - { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, - { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, - { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, - { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, - { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 }, { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 }, + { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 }, + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, /* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */ - { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, - { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, - { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, - { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, - { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, - { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, - { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, + + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + + { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 }, + { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 }, + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + +/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ { 0xFF } }; @@ -2822,16 +2845,14 @@ void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b, if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma); } -const struct ata_timing *ata_timing_find_mode(u8 xfer_mode) +static const struct ata_timing *ata_timing_find_mode(unsigned short speed) { - const struct ata_timing *t = ata_timing; - - while (xfer_mode > t->mode) - t++; + const struct ata_timing *t; - if (xfer_mode == t->mode) - return t; - return NULL; + for (t = ata_timing; t->mode != speed; t++) + if (t->mode == 0xFF) + return NULL; + return t; } int ata_timing_compute(struct ata_device *adev, unsigned short speed, @@ -2905,57 +2926,6 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, return 0; } -/** - * ata_timing_cycle2mode - find xfer mode for the specified cycle duration - * @xfer_shift: ATA_SHIFT_* value for transfer type to examine. - * @cycle: cycle duration in ns - * - * Return matching xfer mode for @cycle. The returned mode is of - * the transfer type specified by @xfer_shift. If @cycle is too - * slow for @xfer_shift, 0xff is returned. If @cycle is faster - * than the fastest known mode, the fasted mode is returned. - * - * LOCKING: - * None. - * - * RETURNS: - * Matching xfer_mode, 0xff if no match found. - */ -u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle) -{ - u8 base_mode = 0xff, last_mode = 0xff; - const struct ata_xfer_ent *ent; - const struct ata_timing *t; - - for (ent = ata_xfer_tbl; ent->shift >= 0; ent++) - if (ent->shift == xfer_shift) - base_mode = ent->base; - - for (t = ata_timing_find_mode(base_mode); - t && ata_xfer_mode2shift(t->mode) == xfer_shift; t++) { - unsigned short this_cycle; - - switch (xfer_shift) { - case ATA_SHIFT_PIO: - case ATA_SHIFT_MWDMA: - this_cycle = t->cycle; - break; - case ATA_SHIFT_UDMA: - this_cycle = t->udma; - break; - default: - return 0xff; - } - - if (cycle > this_cycle) - break; - - last_mode = t->mode; - } - - return last_mode; -} - /** * ata_down_xfermask_limit - adjust dev xfer masks downward * @dev: Device to adjust xfer masks @@ -2974,8 +2944,8 @@ u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle) int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) { char buf[32]; - unsigned long orig_mask, xfer_mask; - unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned int orig_mask, xfer_mask; + unsigned int pio_mask, mwdma_mask, udma_mask; int quiet, highbit; quiet = !!(sel & ATA_DNXFER_QUIET); @@ -3069,7 +3039,7 @@ static int ata_dev_set_mode(struct ata_device *dev) /* Early MWDMA devices do DMA but don't allow DMA mode setting. Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */ - if (dev->xfer_shift == ATA_SHIFT_MWDMA && + if (dev->xfer_shift == ATA_SHIFT_MWDMA && dev->dma_mode == XFER_MW_DMA_0 && (dev->id[63] >> 8) & 1) err_mask &= ~AC_ERR_DEV; @@ -3119,7 +3089,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 1: calculate xfer_mask */ ata_link_for_each_dev(dev, link) { - unsigned long pio_mask, dma_mask; + unsigned int pio_mask, dma_mask; unsigned int mode_mask; if (!ata_dev_enabled(dev)) @@ -3145,7 +3115,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) dev->dma_mode = ata_xfer_mask2mode(dma_mask); found = 1; - if (dev->dma_mode != 0xff) + if (dev->dma_mode) used_dma = 1; } if (!found) @@ -3156,7 +3126,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) if (!ata_dev_enabled(dev)) continue; - if (dev->pio_mode == 0xff) { + if (!dev->pio_mode) { ata_dev_printk(dev, KERN_WARNING, "no PIO support\n"); rc = -EINVAL; goto out; @@ -3170,7 +3140,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 3: set host DMA timings */ ata_link_for_each_dev(dev, link) { - if (!ata_dev_enabled(dev) || dev->dma_mode == 0xff) + if (!ata_dev_enabled(dev) || !dev->dma_mode) continue; dev->xfer_mode = dev->dma_mode; @@ -3202,6 +3172,31 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) return rc; } +/** + * ata_set_mode - Program timings and issue SET FEATURES - XFER + * @link: link on which timings will be programmed + * @r_failed_dev: out paramter for failed device + * + * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If + * ata_set_mode() fails, pointer to the failing device is + * returned in @r_failed_dev. + * + * LOCKING: + * PCI/etc. bus probe sem. + * + * RETURNS: + * 0 on success, negative errno otherwise + */ +int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) +{ + struct ata_port *ap = link->ap; + + /* has private set_mode? */ + if (ap->ops->set_mode) + return ap->ops->set_mode(link, r_failed_dev); + return ata_do_set_mode(link, r_failed_dev); +} + /** * ata_tf_to_host - issue ATA taskfile to host controller * @ap: port to which command is being issued @@ -4368,14 +4363,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) tf.feature = SETFEATURES_XFER; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_POLLING; tf.protocol = ATA_PROT_NODATA; - /* If we are using IORDY we must send the mode setting command */ - if (ata_pio_need_iordy(dev)) - tf.nsect = dev->xfer_mode; - /* If the device has IORDY and the controller does not - turn it off */ - else if (ata_id_has_iordy(dev->id)) - tf.nsect = 0x01; - else /* In the ancient relic department - skip all of this */ - return 0; + tf.nsect = dev->xfer_mode; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); @@ -4474,13 +4462,17 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, void ata_sg_clean(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scatterlist *sg = qc->sg; + struct scatterlist *sg = qc->__sg; int dir = qc->dma_dir; void *pad_buf = NULL; + WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP)); WARN_ON(sg == NULL); - VPRINTK("unmapping %u sg elements\n", qc->mapped_n_elem); + if (qc->flags & ATA_QCFLAG_SINGLE) + WARN_ON(qc->n_elem > 1); + + VPRINTK("unmapping %u sg elements\n", qc->n_elem); /* if we padded the buffer out to 32-bit bound, and data * xfer direction is from-device, we must copy from the @@ -4489,20 +4481,31 @@ void ata_sg_clean(struct ata_queued_cmd *qc) if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE)) pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); - if (qc->mapped_n_elem) - dma_unmap_sg(ap->dev, sg, qc->mapped_n_elem, dir); - /* restore last sg */ - if (qc->last_sg) - *qc->last_sg = qc->saved_last_sg; - if (pad_buf) { - struct scatterlist *psg = &qc->extra_sg[1]; - void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); - memcpy(addr + psg->offset, pad_buf, qc->pad_len); - kunmap_atomic(addr, KM_IRQ0); + if (qc->flags & ATA_QCFLAG_SG) { + if (qc->n_elem) + dma_unmap_sg(ap->dev, sg, qc->n_elem, dir); + /* restore last sg */ + sg_last(sg, qc->orig_n_elem)->length += qc->pad_len; + if (pad_buf) { + struct scatterlist *psg = &qc->pad_sgent; + void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); + memcpy(addr + psg->offset, pad_buf, qc->pad_len); + kunmap_atomic(addr, KM_IRQ0); + } + } else { + if (qc->n_elem) + dma_unmap_single(ap->dev, + sg_dma_address(&sg[0]), sg_dma_len(&sg[0]), + dir); + /* restore sg */ + sg->length += qc->pad_len; + if (pad_buf) + memcpy(qc->buf_virt + sg->length - qc->pad_len, + pad_buf, qc->pad_len); } qc->flags &= ~ATA_QCFLAG_DMAMAP; - qc->sg = NULL; + qc->__sg = NULL; } /** @@ -4520,10 +4523,13 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; - unsigned int si, pi; + unsigned int idx; - pi = 0; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + WARN_ON(qc->__sg == NULL); + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); + + idx = 0; + ata_for_each_sg(sg, qc) { u32 addr, offset; u32 sg_len, len; @@ -4540,17 +4546,18 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) if ((offset + sg_len) > 0x10000) len = 0x10000 - offset; - ap->prd[pi].addr = cpu_to_le32(addr); - ap->prd[pi].flags_len = cpu_to_le32(len & 0xffff); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); + ap->prd[idx].addr = cpu_to_le32(addr); + ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); - pi++; + idx++; sg_len -= len; addr += len; } } - ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + if (idx) + ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } /** @@ -4570,10 +4577,13 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; - unsigned int si, pi; + unsigned int idx; + + WARN_ON(qc->__sg == NULL); + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); - pi = 0; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + idx = 0; + ata_for_each_sg(sg, qc) { u32 addr, offset; u32 sg_len, len, blen; @@ -4591,24 +4601,25 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) len = 0x10000 - offset; blen = len & 0xffff; - ap->prd[pi].addr = cpu_to_le32(addr); + ap->prd[idx].addr = cpu_to_le32(addr); if (blen == 0) { /* Some PATA chipsets like the CS5530 can't cope with 0x0000 meaning 64K as the spec says */ - ap->prd[pi].flags_len = cpu_to_le32(0x8000); + ap->prd[idx].flags_len = cpu_to_le32(0x8000); blen = 0x8000; - ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000); + ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000); } - ap->prd[pi].flags_len = cpu_to_le32(blen); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); + ap->prd[idx].flags_len = cpu_to_le32(blen); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); - pi++; + idx++; sg_len -= len; addr += len; } } - ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + if (idx) + ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } /** @@ -4658,8 +4669,8 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) */ static int atapi_qc_may_overflow(struct ata_queued_cmd *qc) { - if (qc->tf.protocol != ATAPI_PROT_PIO && - qc->tf.protocol != ATAPI_PROT_DMA) + if (qc->tf.protocol != ATA_PROT_ATAPI && + qc->tf.protocol != ATA_PROT_ATAPI_DMA) return 0; if (qc->tf.flags & ATA_TFLAG_WRITE) @@ -4744,6 +4755,33 @@ void ata_dumb_qc_prep(struct ata_queued_cmd *qc) void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } +/** + * ata_sg_init_one - Associate command with memory buffer + * @qc: Command to be associated + * @buf: Memory buffer + * @buflen: Length of memory buffer, in bytes. + * + * Initialize the data-related elements of queued_cmd @qc + * to point to a single memory buffer, @buf of byte length @buflen. + * + * LOCKING: + * spin_lock_irqsave(host lock) + */ + +void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) +{ + qc->flags |= ATA_QCFLAG_SINGLE; + + qc->__sg = &qc->sgent; + qc->n_elem = 1; + qc->orig_n_elem = 1; + qc->buf_virt = buf; + qc->nbytes = buflen; + qc->cursg = qc->__sg; + + sg_init_one(&qc->sgent, buf, buflen); +} + /** * ata_sg_init - Associate command with scatter-gather table. * @qc: Command to be associated @@ -4757,103 +4795,84 @@ void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } * LOCKING: * spin_lock_irqsave(host lock) */ + void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem) { - qc->sg = sg; + qc->flags |= ATA_QCFLAG_SG; + qc->__sg = sg; qc->n_elem = n_elem; - qc->cursg = qc->sg; + qc->orig_n_elem = n_elem; + qc->cursg = qc->__sg; } -static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc, - unsigned int *n_elem_extra, - unsigned int *nbytes_extra) +/** + * ata_sg_setup_one - DMA-map the memory buffer associated with a command. + * @qc: Command with memory buffer to be mapped. + * + * DMA-map the memory buffer associated with queued_cmd @qc. + * + * LOCKING: + * spin_lock_irqsave(host lock) + * + * RETURNS: + * Zero on success, negative on error. + */ + +static int ata_sg_setup_one(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - unsigned int n_elem = qc->n_elem; - struct scatterlist *lsg, *copy_lsg = NULL, *tsg = NULL, *esg = NULL; - - *n_elem_extra = 0; - *nbytes_extra = 0; - - /* needs padding? */ - qc->pad_len = qc->nbytes & 3; - - if (likely(!qc->pad_len)) - return n_elem; - - /* locate last sg and save it */ - lsg = sg_last(qc->sg, n_elem); - qc->last_sg = lsg; - qc->saved_last_sg = *lsg; - - sg_init_table(qc->extra_sg, ARRAY_SIZE(qc->extra_sg)); + int dir = qc->dma_dir; + struct scatterlist *sg = qc->__sg; + dma_addr_t dma_address; + int trim_sg = 0; + /* we must lengthen transfers to end on a 32-bit boundary */ + qc->pad_len = sg->length & 3; if (qc->pad_len) { - struct scatterlist *psg = &qc->extra_sg[1]; void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); - unsigned int offset; + struct scatterlist *psg = &qc->pad_sgent; WARN_ON(qc->dev->class != ATA_DEV_ATAPI); memset(pad_buf, 0, ATA_DMA_PAD_SZ); - /* psg->page/offset are used to copy to-be-written - * data in this function or read data in ata_sg_clean. - */ - offset = lsg->offset + lsg->length - qc->pad_len; - sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT), - qc->pad_len, offset_in_page(offset)); - - if (qc->tf.flags & ATA_TFLAG_WRITE) { - void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); - memcpy(pad_buf, addr + psg->offset, qc->pad_len); - kunmap_atomic(addr, KM_IRQ0); - } + if (qc->tf.flags & ATA_TFLAG_WRITE) + memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len, + qc->pad_len); sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ); sg_dma_len(psg) = ATA_DMA_PAD_SZ; + /* trim sg */ + sg->length -= qc->pad_len; + if (sg->length == 0) + trim_sg = 1; - /* Trim the last sg entry and chain the original and - * padding sg lists. - * - * Because chaining consumes one sg entry, one extra - * sg entry is allocated and the last sg entry is - * copied to it if the length isn't zero after padded - * amount is removed. - * - * If the last sg entry is completely replaced by - * padding sg entry, the first sg entry is skipped - * while chaining. - */ - lsg->length -= qc->pad_len; - if (lsg->length) { - copy_lsg = &qc->extra_sg[0]; - tsg = &qc->extra_sg[0]; - } else { - n_elem--; - tsg = &qc->extra_sg[1]; - } - - esg = &qc->extra_sg[1]; + DPRINTK("padding done, sg->length=%u pad_len=%u\n", + sg->length, qc->pad_len); + } - (*n_elem_extra)++; - (*nbytes_extra) += 4 - qc->pad_len; + if (trim_sg) { + qc->n_elem--; + goto skip_map; } - if (copy_lsg) - sg_set_page(copy_lsg, sg_page(lsg), lsg->length, lsg->offset); + dma_address = dma_map_single(ap->dev, qc->buf_virt, + sg->length, dir); + if (dma_mapping_error(dma_address)) { + /* restore sg */ + sg->length += qc->pad_len; + return -1; + } - sg_chain(lsg, 1, tsg); - sg_mark_end(esg); + sg_dma_address(sg) = dma_address; + sg_dma_len(sg) = sg->length; - /* sglist can't start with chaining sg entry, fast forward */ - if (qc->sg == lsg) { - qc->sg = tsg; - qc->cursg = tsg; - } +skip_map: + DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg), + qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); - return n_elem; + return 0; } /** @@ -4869,30 +4888,75 @@ static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc, * Zero on success, negative on error. * */ + static int ata_sg_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - unsigned int n_elem, n_elem_extra, nbytes_extra; + struct scatterlist *sg = qc->__sg; + struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem); + int n_elem, pre_n_elem, dir, trim_sg = 0; VPRINTK("ENTER, ata%u\n", ap->print_id); + WARN_ON(!(qc->flags & ATA_QCFLAG_SG)); - n_elem = ata_sg_setup_extra(qc, &n_elem_extra, &nbytes_extra); + /* we must lengthen transfers to end on a 32-bit boundary */ + qc->pad_len = lsg->length & 3; + if (qc->pad_len) { + void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); + struct scatterlist *psg = &qc->pad_sgent; + unsigned int offset; - if (n_elem) { - n_elem = dma_map_sg(ap->dev, qc->sg, n_elem, qc->dma_dir); - if (n_elem < 1) { - /* restore last sg */ - if (qc->last_sg) - *qc->last_sg = qc->saved_last_sg; - return -1; + WARN_ON(qc->dev->class != ATA_DEV_ATAPI); + + memset(pad_buf, 0, ATA_DMA_PAD_SZ); + + /* + * psg->page/offset are used to copy to-be-written + * data in this function or read data in ata_sg_clean. + */ + offset = lsg->offset + lsg->length - qc->pad_len; + sg_init_table(psg, 1); + sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT), + qc->pad_len, offset_in_page(offset)); + + if (qc->tf.flags & ATA_TFLAG_WRITE) { + void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); + memcpy(pad_buf, addr + psg->offset, qc->pad_len); + kunmap_atomic(addr, KM_IRQ0); } - DPRINTK("%d sg elements mapped\n", n_elem); + + sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ); + sg_dma_len(psg) = ATA_DMA_PAD_SZ; + /* trim last sg */ + lsg->length -= qc->pad_len; + if (lsg->length == 0) + trim_sg = 1; + + DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n", + qc->n_elem - 1, lsg->length, qc->pad_len); + } + + pre_n_elem = qc->n_elem; + if (trim_sg && pre_n_elem) + pre_n_elem--; + + if (!pre_n_elem) { + n_elem = 0; + goto skip_map; + } + + dir = qc->dma_dir; + n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir); + if (n_elem < 1) { + /* restore last sg */ + lsg->length += qc->pad_len; + return -1; } - qc->n_elem = qc->mapped_n_elem = n_elem; - qc->n_elem += n_elem_extra; - qc->nbytes += nbytes_extra; - qc->flags |= ATA_QCFLAG_DMAMAP; + DPRINTK("%d sg elements mapped\n", n_elem); + +skip_map: + qc->n_elem = n_elem; return 0; } @@ -4921,7 +4985,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) /** * ata_data_xfer - Transfer data by PIO - * @dev: device to target + * @adev: device to target * @buf: data buffer * @buflen: buffer length * @write_data: read/write @@ -4930,44 +4994,37 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) * * LOCKING: * Inherited from caller. - * - * RETURNS: - * Bytes consumed. */ -unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) +void ata_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { - struct ata_port *ap = dev->link->ap; - void __iomem *data_addr = ap->ioaddr.data_addr; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; /* Transfer multiple of 2 bytes */ - if (rw == READ) - ioread16_rep(data_addr, buf, words); + if (write_data) + iowrite16_rep(ap->ioaddr.data_addr, buf, words); else - iowrite16_rep(data_addr, buf, words); + ioread16_rep(ap->ioaddr.data_addr, buf, words); /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { - __le16 align_buf[1] = { 0 }; + u16 align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (rw == READ) { - align_buf[0] = cpu_to_le16(ioread16(data_addr)); - memcpy(trailing_buf, align_buf, 1); - } else { + if (write_data) { memcpy(align_buf, trailing_buf, 1); - iowrite16(le16_to_cpu(align_buf[0]), data_addr); + iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); + } else { + align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr)); + memcpy(trailing_buf, align_buf, 1); } - words++; } - - return words << 1; } /** * ata_data_xfer_noirq - Transfer data by PIO - * @dev: device to target + * @adev: device to target * @buf: data buffer * @buflen: buffer length * @write_data: read/write @@ -4977,21 +5034,14 @@ unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, * * LOCKING: * Inherited from caller. - * - * RETURNS: - * Bytes consumed. */ -unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) +void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { unsigned long flags; - unsigned int consumed; - local_irq_save(flags); - consumed = ata_data_xfer(dev, buf, buflen, rw); + ata_data_xfer(adev, buf, buflen, write_data); local_irq_restore(flags); - - return consumed; } @@ -5102,13 +5152,13 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) ata_altstatus(ap); /* flush */ switch (qc->tf.protocol) { - case ATAPI_PROT_PIO: + case ATA_PROT_ATAPI: ap->hsm_task_state = HSM_ST; break; - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI_NODATA: ap->hsm_task_state = HSM_ST_LAST; break; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: ap->hsm_task_state = HSM_ST_LAST; /* initiate bmdma */ ap->ops->bmdma_start(qc); @@ -5250,15 +5300,12 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) bytes = (bc_hi << 8) | bc_lo; /* shall be cleared to zero, indicating xfer of data */ - if (unlikely(ireason & (1 << 0))) + if (ireason & (1 << 0)) goto err_out; /* make sure transfer direction matches expected */ i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0; - if (unlikely(do_write != i_write)) - goto err_out; - - if (unlikely(!bytes)) + if (do_write != i_write) goto err_out; VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); @@ -5294,7 +5341,7 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *q (qc->tf.flags & ATA_TFLAG_WRITE)) return 1; - if (ata_is_atapi(qc->tf.protocol) && + if (is_atapi_taskfile(&qc->tf) && !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) return 1; } @@ -5459,7 +5506,7 @@ int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, case HSM_ST: /* complete command or read/write the data register */ - if (qc->tf.protocol == ATAPI_PROT_PIO) { + if (qc->tf.protocol == ATA_PROT_ATAPI) { /* ATAPI PIO protocol */ if ((status & ATA_DRQ) == 0) { /* No more data to transfer or device error. @@ -5617,7 +5664,7 @@ static void ata_pio_task(struct work_struct *work) msleep(2); status = ata_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { - ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE); return; } } @@ -5758,22 +5805,6 @@ static void fill_result_tf(struct ata_queued_cmd *qc) ap->ops->tf_read(ap, &qc->result_tf); } -static void ata_verify_xfer(struct ata_queued_cmd *qc) -{ - struct ata_device *dev = qc->dev; - - if (ata_tag_internal(qc->tag)) - return; - - if (ata_is_nodata(qc->tf.protocol)) - return; - - if ((dev->mwdma_mask || dev->udma_mask) && ata_is_pio(qc->tf.protocol)) - return; - - dev->flags &= ~ATA_DFLAG_DUBIOUS_XFER; -} - /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -5845,9 +5876,6 @@ void ata_qc_complete(struct ata_queued_cmd *qc) break; } - if (unlikely(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) - ata_verify_xfer(qc); - __ata_qc_complete(qc); } else { if (qc->flags & ATA_QCFLAG_EH_SCHEDULED) @@ -5910,6 +5938,30 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, return nr_done; } +static inline int ata_should_dma_map(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + switch (qc->tf.protocol) { + case ATA_PROT_NCQ: + case ATA_PROT_DMA: + case ATA_PROT_ATAPI_DMA: + return 1; + + case ATA_PROT_ATAPI: + case ATA_PROT_PIO: + if (ap->flags & ATA_FLAG_PIO_DMA) + return 1; + + /* fall through */ + + default: + return 0; + } + + /* never reached */ +} + /** * ata_qc_issue - issue taskfile to device * @qc: command to issue to device @@ -5926,7 +5978,6 @@ void ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_link *link = qc->dev->link; - u8 prot = qc->tf.protocol; /* Make sure only one non-NCQ command is outstanding. The * check is skipped for old EH because it reuses active qc to @@ -5934,7 +5985,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) */ WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag)); - if (ata_is_ncq(prot)) { + if (qc->tf.protocol == ATA_PROT_NCQ) { WARN_ON(link->sactive & (1 << qc->tag)); if (!link->sactive) @@ -5950,18 +6001,17 @@ void ata_qc_issue(struct ata_queued_cmd *qc) qc->flags |= ATA_QCFLAG_ACTIVE; ap->qc_active |= 1 << qc->tag; - /* We guarantee to LLDs that they will have at least one - * non-zero sg if the command is a data command. - */ - BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes)); - - /* ata_sg_setup() may update nbytes */ - qc->raw_nbytes = qc->nbytes; - - if (ata_is_dma(prot) || (ata_is_pio(prot) && - (ap->flags & ATA_FLAG_PIO_DMA))) - if (ata_sg_setup(qc)) - goto sg_err; + if (ata_should_dma_map(qc)) { + if (qc->flags & ATA_QCFLAG_SG) { + if (ata_sg_setup(qc)) + goto sg_err; + } else if (qc->flags & ATA_QCFLAG_SINGLE) { + if (ata_sg_setup_one(qc)) + goto sg_err; + } + } else { + qc->flags &= ~ATA_QCFLAG_DMAMAP; + } /* if device is sleeping, schedule softreset and abort the link */ if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) { @@ -5979,6 +6029,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) return; sg_err: + qc->flags &= ~ATA_QCFLAG_DMAMAP; qc->err_mask |= AC_ERR_SYSTEM; err: ata_qc_complete(qc); @@ -6013,11 +6064,11 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATA_PROT_PIO: case ATA_PROT_NODATA: - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_NODATA: qc->tf.flags |= ATA_TFLAG_POLLING; break; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: if (qc->dev->flags & ATA_DFLAG_CDB_INTR) /* see ata_dma_blacklisted() */ BUG(); @@ -6040,7 +6091,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_LAST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_pio_queue_task(ap, qc, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); break; @@ -6062,7 +6113,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - ata_pio_queue_task(ap, qc, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); /* always send first data block using * the ata_pio_task() codepath. @@ -6072,7 +6123,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_pio_queue_task(ap, qc, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); /* if polling, ata_pio_task() handles the rest. * otherwise, interrupt handler takes over from here. @@ -6081,8 +6132,8 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_NODATA: if (qc->tf.flags & ATA_TFLAG_POLLING) ata_qc_set_polling(qc); @@ -6093,10 +6144,10 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - ata_pio_queue_task(ap, qc, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); break; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ @@ -6105,7 +6156,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - ata_pio_queue_task(ap, qc, 0); + ata_port_queue_task(ap, ata_pio_task, qc, 0); break; default: @@ -6149,15 +6200,15 @@ inline unsigned int ata_host_intr(struct ata_port *ap, */ /* Check the ATA_DFLAG_CDB_INTR flag is enough here. - * The flag was turned on only for atapi devices. No - * need to check ata_is_atapi(qc->tf.protocol) again. + * The flag was turned on only for atapi devices. + * No need to check is_atapi_taskfile(&qc->tf) again. */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) goto idle_irq; break; case HSM_ST_LAST: if (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATAPI_PROT_DMA) { + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { /* check status of DMA engine */ host_stat = ap->ops->bmdma_status(ap); VPRINTK("ata%u: host_stat 0x%X\n", @@ -6199,7 +6250,7 @@ inline unsigned int ata_host_intr(struct ata_port *ap, ata_hsm_move(ap, qc, status, 0); if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATAPI_PROT_DMA)) + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); return 1; /* irq handled */ @@ -6721,7 +6772,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; #endif - INIT_DELAYED_WORK(&ap->port_task, ata_pio_task); + INIT_DELAYED_WORK(&ap->port_task, NULL); INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); @@ -7538,6 +7589,7 @@ EXPORT_SYMBOL_GPL(ata_host_register); EXPORT_SYMBOL_GPL(ata_host_activate); EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_sg_init); +EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_hsm_move); EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); @@ -7549,13 +7601,6 @@ EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(sata_print_link_status); EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); -EXPORT_SYMBOL_GPL(ata_pack_xfermask); -EXPORT_SYMBOL_GPL(ata_unpack_xfermask); -EXPORT_SYMBOL_GPL(ata_xfer_mask2mode); -EXPORT_SYMBOL_GPL(ata_xfer_mode2mask); -EXPORT_SYMBOL_GPL(ata_xfer_mode2shift); -EXPORT_SYMBOL_GPL(ata_mode_string); -EXPORT_SYMBOL_GPL(ata_id_xfermask); EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); EXPORT_SYMBOL_GPL(ata_exec_command); @@ -7598,6 +7643,7 @@ EXPORT_SYMBOL_GPL(ata_wait_register); EXPORT_SYMBOL_GPL(ata_busy_sleep); EXPORT_SYMBOL_GPL(ata_wait_after_reset); EXPORT_SYMBOL_GPL(ata_wait_ready); +EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); @@ -7616,20 +7662,18 @@ EXPORT_SYMBOL_GPL(ata_host_resume); #endif /* CONFIG_PM */ EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); +EXPORT_SYMBOL_GPL(ata_id_to_dma_mode); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); -EXPORT_SYMBOL_GPL(ata_timing_find_mode); EXPORT_SYMBOL_GPL(ata_timing_compute); EXPORT_SYMBOL_GPL(ata_timing_merge); -EXPORT_SYMBOL_GPL(ata_timing_cycle2mode); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); -EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); #ifdef CONFIG_PM @@ -7671,5 +7715,4 @@ EXPORT_SYMBOL_GPL(ata_dev_try_classify); EXPORT_SYMBOL_GPL(ata_cable_40wire); EXPORT_SYMBOL_GPL(ata_cable_80wire); EXPORT_SYMBOL_GPL(ata_cable_unknown); -EXPORT_SYMBOL_GPL(ata_cable_ignore); EXPORT_SYMBOL_GPL(ata_cable_sata); diff --git a/trunk/drivers/ata/libata-eh.c b/trunk/drivers/ata/libata-eh.c index 4e31071acc02..21a81cd148e4 100644 --- a/trunk/drivers/ata/libata-eh.c +++ b/trunk/drivers/ata/libata-eh.c @@ -46,26 +46,9 @@ #include "libata.h" enum { - /* speed down verdicts */ ATA_EH_SPDN_NCQ_OFF = (1 << 0), ATA_EH_SPDN_SPEED_DOWN = (1 << 1), ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2), - ATA_EH_SPDN_KEEP_ERRORS = (1 << 3), - - /* error flags */ - ATA_EFLAG_IS_IO = (1 << 0), - ATA_EFLAG_DUBIOUS_XFER = (1 << 1), - - /* error categories */ - ATA_ECAT_NONE = 0, - ATA_ECAT_ATA_BUS = 1, - ATA_ECAT_TOUT_HSM = 2, - ATA_ECAT_UNK_DEV = 3, - ATA_ECAT_DUBIOUS_NONE = 4, - ATA_ECAT_DUBIOUS_ATA_BUS = 5, - ATA_ECAT_DUBIOUS_TOUT_HSM = 6, - ATA_ECAT_DUBIOUS_UNK_DEV = 7, - ATA_ECAT_NR = 8, }; /* Waiting in ->prereset can never be reliable. It's sometimes nice @@ -230,13 +213,12 @@ void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, if (offset < 0) ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start); else - ata_port_desc(ap, "%s 0x%llx", name, - start + (unsigned long long)offset); + ata_port_desc(ap, "%s 0x%llx", name, start + offset); } #endif /* CONFIG_PCI */ -static void ata_ering_record(struct ata_ering *ering, unsigned int eflags, +static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) { struct ata_ering_entry *ent; @@ -247,20 +229,11 @@ static void ata_ering_record(struct ata_ering *ering, unsigned int eflags, ering->cursor %= ATA_ERING_SIZE; ent = &ering->ring[ering->cursor]; - ent->eflags = eflags; + ent->is_io = is_io; ent->err_mask = err_mask; ent->timestamp = get_jiffies_64(); } -static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering) -{ - struct ata_ering_entry *ent = &ering->ring[ering->cursor]; - - if (ent->err_mask) - return ent; - return NULL; -} - static void ata_ering_clear(struct ata_ering *ering) { memset(ering, 0, sizeof(*ering)); @@ -472,20 +445,9 @@ void ata_scsi_error(struct Scsi_Host *host) spin_lock_irqsave(ap->lock, flags); __ata_port_for_each_link(link, ap) { - struct ata_eh_context *ehc = &link->eh_context; - struct ata_device *dev; - memset(&link->eh_context, 0, sizeof(link->eh_context)); link->eh_context.i = link->eh_info; memset(&link->eh_info, 0, sizeof(link->eh_info)); - - ata_link_for_each_dev(dev, link) { - int devno = dev->devno; - - ehc->saved_xfer_mode[devno] = dev->xfer_mode; - if (ata_ncq_enabled(dev)) - ehc->saved_ncq_enabled |= 1 << devno; - } } ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; @@ -1298,10 +1260,10 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) /* is it pointless to prefer PIO for "safety reasons"? */ if (ap->flags & ATA_FLAG_PIO_DMA) { - tf.protocol = ATAPI_PROT_DMA; + tf.protocol = ATA_PROT_ATAPI_DMA; tf.feature |= ATAPI_PKT_DMA; } else { - tf.protocol = ATAPI_PROT_PIO; + tf.protocol = ATA_PROT_ATAPI; tf.lbam = SCSI_SENSE_BUFFERSIZE; tf.lbah = 0; } @@ -1489,29 +1451,20 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return action; } -static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask, - int *xfer_ok) +static int ata_eh_categorize_error(int is_io, unsigned int err_mask) { - int base = 0; - - if (!(eflags & ATA_EFLAG_DUBIOUS_XFER)) - *xfer_ok = 1; - - if (!*xfer_ok) - base = ATA_ECAT_DUBIOUS_NONE; - if (err_mask & AC_ERR_ATA_BUS) - return base + ATA_ECAT_ATA_BUS; + return 1; if (err_mask & AC_ERR_TIMEOUT) - return base + ATA_ECAT_TOUT_HSM; + return 2; - if (eflags & ATA_EFLAG_IS_IO) { + if (is_io) { if (err_mask & AC_ERR_HSM) - return base + ATA_ECAT_TOUT_HSM; + return 2; if ((err_mask & (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV) - return base + ATA_ECAT_UNK_DEV; + return 3; } return 0; @@ -1519,22 +1472,18 @@ static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask, struct speed_down_verdict_arg { u64 since; - int xfer_ok; - int nr_errors[ATA_ECAT_NR]; + int nr_errors[4]; }; static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) { struct speed_down_verdict_arg *arg = void_arg; - int cat; + int cat = ata_eh_categorize_error(ent->is_io, ent->err_mask); if (ent->timestamp < arg->since) return -1; - cat = ata_eh_categorize_error(ent->eflags, ent->err_mask, - &arg->xfer_ok); arg->nr_errors[cat]++; - return 0; } @@ -1546,48 +1495,22 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) * whether NCQ needs to be turned off, transfer speed should be * stepped down, or falling back to PIO is necessary. * - * ECAT_ATA_BUS : ATA_BUS error for any command - * - * ECAT_TOUT_HSM : TIMEOUT for any command or HSM violation for - * IO commands - * - * ECAT_UNK_DEV : Unknown DEV error for IO commands - * - * ECAT_DUBIOUS_* : Identical to above three but occurred while - * data transfer hasn't been verified. - * - * Verdicts are - * - * NCQ_OFF : Turn off NCQ. - * - * SPEED_DOWN : Speed down transfer speed but don't fall back - * to PIO. - * - * FALLBACK_TO_PIO : Fall back to PIO. - * - * Even if multiple verdicts are returned, only one action is - * taken per error. An action triggered by non-DUBIOUS errors - * clears ering, while one triggered by DUBIOUS_* errors doesn't. - * This is to expedite speed down decisions right after device is - * initially configured. + * Cat-1 is ATA_BUS error for any command. * - * The followings are speed down rules. #1 and #2 deal with - * DUBIOUS errors. + * Cat-2 is TIMEOUT for any command or HSM violation for known + * supported commands. * - * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors - * occurred during last 5 mins, SPEED_DOWN and FALLBACK_TO_PIO. + * Cat-3 is is unclassified DEV error for known supported + * command. * - * 2. If more than one DUBIOUS_TOUT_HSM or DUBIOUS_UNK_DEV errors - * occurred during last 5 mins, NCQ_OFF. + * NCQ needs to be turned off if there have been more than 3 + * Cat-2 + Cat-3 errors during last 10 minutes. * - * 3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors - * ocurred during last 5 mins, FALLBACK_TO_PIO + * Speed down is necessary if there have been more than 3 Cat-1 + + * Cat-2 errors or 10 Cat-3 errors during last 10 minutes. * - * 4. If more than 3 TOUT_HSM or UNK_DEV errors occurred - * during last 10 mins, NCQ_OFF. - * - * 5. If more than 3 ATA_BUS or TOUT_HSM errors, or more than 6 - * UNK_DEV errors occurred during last 10 mins, SPEED_DOWN. + * Falling back to PIO mode is necessary if there have been more + * than 10 Cat-1 + Cat-2 + Cat-3 errors during last 5 minutes. * * LOCKING: * Inherited from caller. @@ -1602,46 +1525,31 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev) struct speed_down_verdict_arg arg; unsigned int verdict = 0; - /* scan past 5 mins of error history */ - memset(&arg, 0, sizeof(arg)); - arg.since = j64 - min(j64, j5mins); - ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); - - if (arg.nr_errors[ATA_ECAT_DUBIOUS_ATA_BUS] + - arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] > 1) - verdict |= ATA_EH_SPDN_SPEED_DOWN | - ATA_EH_SPDN_FALLBACK_TO_PIO | ATA_EH_SPDN_KEEP_ERRORS; - - if (arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] + - arg.nr_errors[ATA_ECAT_DUBIOUS_UNK_DEV] > 1) - verdict |= ATA_EH_SPDN_NCQ_OFF | ATA_EH_SPDN_KEEP_ERRORS; - - if (arg.nr_errors[ATA_ECAT_ATA_BUS] + - arg.nr_errors[ATA_ECAT_TOUT_HSM] + - arg.nr_errors[ATA_ECAT_UNK_DEV] > 6) - verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO; - /* scan past 10 mins of error history */ memset(&arg, 0, sizeof(arg)); arg.since = j64 - min(j64, j10mins); ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); - if (arg.nr_errors[ATA_ECAT_TOUT_HSM] + - arg.nr_errors[ATA_ECAT_UNK_DEV] > 3) + if (arg.nr_errors[2] + arg.nr_errors[3] > 3) verdict |= ATA_EH_SPDN_NCQ_OFF; - - if (arg.nr_errors[ATA_ECAT_ATA_BUS] + - arg.nr_errors[ATA_ECAT_TOUT_HSM] > 3 || - arg.nr_errors[ATA_ECAT_UNK_DEV] > 6) + if (arg.nr_errors[1] + arg.nr_errors[2] > 3 || arg.nr_errors[3] > 10) verdict |= ATA_EH_SPDN_SPEED_DOWN; + /* scan past 3 mins of error history */ + memset(&arg, 0, sizeof(arg)); + arg.since = j64 - min(j64, j5mins); + ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); + + if (arg.nr_errors[1] + arg.nr_errors[2] + arg.nr_errors[3] > 10) + verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO; + return verdict; } /** * ata_eh_speed_down - record error and speed down if necessary * @dev: Failed device - * @eflags: mask of ATA_EFLAG_* flags + * @is_io: Did the device fail during normal IO? * @err_mask: err_mask of the error * * Record error and examine error history to determine whether @@ -1655,20 +1563,18 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev) * RETURNS: * Determined recovery action. */ -static unsigned int ata_eh_speed_down(struct ata_device *dev, - unsigned int eflags, unsigned int err_mask) +static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, + unsigned int err_mask) { - struct ata_link *link = dev->link; - int xfer_ok = 0; unsigned int verdict; unsigned int action = 0; /* don't bother if Cat-0 error */ - if (ata_eh_categorize_error(eflags, err_mask, &xfer_ok) == 0) + if (ata_eh_categorize_error(is_io, err_mask) == 0) return 0; /* record error and determine whether speed down is necessary */ - ata_ering_record(&dev->ering, eflags, err_mask); + ata_ering_record(&dev->ering, is_io, err_mask); verdict = ata_eh_speed_down_verdict(dev); /* turn off NCQ? */ @@ -1684,7 +1590,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, /* speed down? */ if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(link) == 0) { + if (sata_down_spd_limit(dev->link) == 0) { action |= ATA_EH_HARDRESET; goto done; } @@ -1712,10 +1618,10 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, } /* Fall back to PIO? Slowing down to PIO is meaningless for - * SATA ATA devices. Consider it only for PATA and SATAPI. + * SATA. Consider it only for PATA. */ if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) && - (link->ap->cbl != ATA_CBL_SATA || dev->class == ATA_DEV_ATAPI) && + (dev->link->ap->cbl != ATA_CBL_SATA) && (dev->xfer_shift != ATA_SHIFT_PIO)) { if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { dev->spdn_cnt = 0; @@ -1727,8 +1633,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, return 0; done: /* device has been slowed down, blow error history */ - if (!(verdict & ATA_EH_SPDN_KEEP_ERRORS)) - ata_ering_clear(&dev->ering); + ata_ering_clear(&dev->ering); return action; } @@ -1748,8 +1653,8 @@ static void ata_eh_link_autopsy(struct ata_link *link) struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; - unsigned int all_err_mask = 0, eflags = 0; - int tag; + unsigned int all_err_mask = 0; + int tag, is_io = 0; u32 serror; int rc; @@ -1808,15 +1713,15 @@ static void ata_eh_link_autopsy(struct ata_link *link) ehc->i.dev = qc->dev; all_err_mask |= qc->err_mask; if (qc->flags & ATA_QCFLAG_IO) - eflags |= ATA_EFLAG_IS_IO; + is_io = 1; } /* enforce default EH actions */ if (ap->pflags & ATA_PFLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) ehc->i.action |= ATA_EH_SOFTRESET; - else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) || - (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV))) + else if ((is_io && all_err_mask) || + (!is_io && (all_err_mask & ~AC_ERR_DEV))) ehc->i.action |= ATA_EH_REVALIDATE; /* If we have offending qcs and the associated failed device, @@ -1838,11 +1743,8 @@ static void ata_eh_link_autopsy(struct ata_link *link) ata_dev_enabled(link->device)))) dev = link->device; - if (dev) { - if (dev->flags & ATA_DFLAG_DUBIOUS_XFER) - eflags |= ATA_EFLAG_DUBIOUS_XFER; - ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); - } + if (dev) + ehc->i.action |= ata_eh_speed_down(dev, is_io, all_err_mask); DPRINTK("EXIT\n"); } @@ -1978,8 +1880,8 @@ static void ata_eh_link_report(struct ata_link *link) [ATA_PROT_PIO] = "pio", [ATA_PROT_DMA] = "dma", [ATA_PROT_NCQ] = "ncq", - [ATAPI_PROT_PIO] = "pio", - [ATAPI_PROT_DMA] = "dma", + [ATA_PROT_ATAPI] = "pio", + [ATA_PROT_ATAPI_DMA] = "dma", }; snprintf(data_buf, sizeof(data_buf), " %s %u %s", @@ -1987,7 +1889,7 @@ static void ata_eh_link_report(struct ata_link *link) dma_str[qc->dma_dir]); } - if (ata_is_atapi(qc->tf.protocol)) + if (is_atapi_taskfile(&qc->tf)) snprintf(cdb_buf, sizeof(cdb_buf), "cdb %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n ", @@ -2427,58 +2329,6 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, return rc; } -/** - * ata_set_mode - Program timings and issue SET FEATURES - XFER - * @link: link on which timings will be programmed - * @r_failed_dev: out paramter for failed device - * - * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If - * ata_set_mode() fails, pointer to the failing device is - * returned in @r_failed_dev. - * - * LOCKING: - * PCI/etc. bus probe sem. - * - * RETURNS: - * 0 on success, negative errno otherwise - */ -int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) -{ - struct ata_port *ap = link->ap; - struct ata_device *dev; - int rc; - - /* if data transfer is verified, clear DUBIOUS_XFER on ering top */ - ata_link_for_each_dev(dev, link) { - if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) { - struct ata_ering_entry *ent; - - ent = ata_ering_top(&dev->ering); - if (ent) - ent->eflags &= ~ATA_EFLAG_DUBIOUS_XFER; - } - } - - /* has private set_mode? */ - if (ap->ops->set_mode) - rc = ap->ops->set_mode(link, r_failed_dev); - else - rc = ata_do_set_mode(link, r_failed_dev); - - /* if transfer mode has changed, set DUBIOUS_XFER on device */ - ata_link_for_each_dev(dev, link) { - struct ata_eh_context *ehc = &link->eh_context; - u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno]; - u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno)); - - if (dev->xfer_mode != saved_xfer_mode || - ata_ncq_enabled(dev) != saved_ncq) - dev->flags |= ATA_DFLAG_DUBIOUS_XFER; - } - - return rc; -} - static int ata_link_nr_enabled(struct ata_link *link) { struct ata_device *dev; @@ -2525,24 +2375,6 @@ static int ata_eh_skip_recovery(struct ata_link *link) return 1; } -static int ata_eh_schedule_probe(struct ata_device *dev) -{ - struct ata_eh_context *ehc = &dev->link->eh_context; - - if (!(ehc->i.probe_mask & (1 << dev->devno)) || - (ehc->did_probe_mask & (1 << dev->devno))) - return 0; - - ata_eh_detach_dev(dev); - ata_dev_init(dev); - ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; - ehc->saved_xfer_mode[dev->devno] = 0; - ehc->saved_ncq_enabled &= ~(1 << dev->devno); - - return 1; -} - static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) { struct ata_eh_context *ehc = &dev->link->eh_context; @@ -2574,9 +2406,16 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) if (ata_link_offline(dev->link)) ata_eh_detach_dev(dev); - /* schedule probe if necessary */ - if (ata_eh_schedule_probe(dev)) + /* probe if requested */ + if ((ehc->i.probe_mask & (1 << dev->devno)) && + !(ehc->did_probe_mask & (1 << dev->devno))) { + ata_eh_detach_dev(dev); + ata_dev_init(dev); + ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + } return 1; } else { @@ -2653,9 +2492,14 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (dev->flags & ATA_DFLAG_DETACH) ata_eh_detach_dev(dev); - /* schedule probe if necessary */ - if (!ata_dev_enabled(dev)) - ata_eh_schedule_probe(dev); + if (!ata_dev_enabled(dev) && + ((ehc->i.probe_mask & (1 << dev->devno)) && + !(ehc->did_probe_mask & (1 << dev->devno)))) { + ata_eh_detach_dev(dev); + ata_dev_init(dev); + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + } } } @@ -2903,7 +2747,6 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) if (ap->ops->port_suspend) rc = ap->ops->port_suspend(ap, ap->pm_mesg); - ata_acpi_set_state(ap, PMSG_SUSPEND); out: /* report result */ spin_lock_irqsave(ap->lock, flags); @@ -2949,8 +2792,6 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED)); - ata_acpi_set_state(ap, PMSG_ON); - if (ap->ops->port_resume) rc = ap->ops->port_resume(ap); diff --git a/trunk/drivers/ata/libata-scsi.c b/trunk/drivers/ata/libata-scsi.c index 3fd08201bef4..14daf4848f09 100644 --- a/trunk/drivers/ata/libata-scsi.c +++ b/trunk/drivers/ata/libata-scsi.c @@ -517,7 +517,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, qc->scsicmd = cmd; qc->scsidone = done; - qc->sg = scsi_sglist(cmd); + qc->__sg = scsi_sglist(cmd); qc->n_elem = scsi_sg_count(cmd); } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); @@ -2210,7 +2210,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, /* sector size */ ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff); + ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE); } else { /* sector count, 64-bit */ ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7)); @@ -2224,7 +2224,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, /* sector size */ ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff); + ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE); } return 0; @@ -2331,7 +2331,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) DPRINTK("ATAPI request sense\n"); /* FIXME: is this needed? */ - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); ap->ops->tf_read(ap, &qc->tf); @@ -2341,9 +2341,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) ata_qc_reinit(qc); - /* setup sg table and init transfer direction */ - sg_init_one(&qc->sgent, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); - ata_sg_init(qc, &qc->sgent, 1); + ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); qc->dma_dir = DMA_FROM_DEVICE; memset(&qc->cdb, 0, qc->dev->cdb_len); @@ -2354,10 +2352,10 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) qc->tf.command = ATA_CMD_PACKET; if (ata_pio_use_silly(ap)) { - qc->tf.protocol = ATAPI_PROT_DMA; + qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; } else { - qc->tf.protocol = ATAPI_PROT_PIO; + qc->tf.protocol = ATA_PROT_ATAPI; qc->tf.lbam = SCSI_SENSE_BUFFERSIZE; qc->tf.lbah = 0; } @@ -2528,12 +2526,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) if (using_pio || nodata) { /* no data, or PIO data xfer */ if (nodata) - qc->tf.protocol = ATAPI_PROT_NODATA; + qc->tf.protocol = ATA_PROT_ATAPI_NODATA; else - qc->tf.protocol = ATAPI_PROT_PIO; + qc->tf.protocol = ATA_PROT_ATAPI; } else { /* DMA data xfer */ - qc->tf.protocol = ATAPI_PROT_DMA; + qc->tf.protocol = ATA_PROT_ATAPI_DMA; qc->tf.feature |= ATAPI_PKT_DMA; if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE)) @@ -2692,24 +2690,6 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) goto invalid_fld; - /* - * Filter TPM commands by default. These provide an - * essentially uncontrolled encrypted "back door" between - * applications and the disk. Set libata.allow_tpm=1 if you - * have a real reason for wanting to use them. This ensures - * that installed software cannot easily mess stuff up without - * user intent. DVR type users will probably ship with this enabled - * for movie content management. - * - * Note that for ATA8 we can issue a DCS change and DCS freeze lock - * for this and should do in future but that it is not sufficient as - * DCS is an optional feature set. Thus we also do the software filter - * so that we comply with the TC consortium stated goal that the user - * can turn off TC features of their system. - */ - if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm) - goto invalid_fld; - /* We may not issue DMA commands if no DMA mode is set */ if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) goto invalid_fld; diff --git a/trunk/drivers/ata/libata-sff.c b/trunk/drivers/ata/libata-sff.c index 60cd4b179766..b7ac80b4b1fb 100644 --- a/trunk/drivers/ata/libata-sff.c +++ b/trunk/drivers/ata/libata-sff.c @@ -147,9 +147,7 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) * @tf: ATA taskfile register set for storing input * * Reads ATA taskfile registers for currently-selected device - * into @tf. Assumes the device has a fully SFF compliant task file - * layout and behaviour. If you device does not (eg has a different - * status method) then you will need to provide a replacement tf_read + * into @tf. * * LOCKING: * Inherited from caller. @@ -158,7 +156,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->command = ata_check_status(ap); + tf->command = ata_chk_status(ap); tf->feature = ioread8(ioaddr->error_addr); tf->nsect = ioread8(ioaddr->nsect_addr); tf->lbal = ioread8(ioaddr->lbal_addr); @@ -417,7 +415,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ap->hsm_task_state = HSM_ST_IDLE; if (qc && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATAPI_PROT_DMA)) { + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { u8 host_stat; host_stat = ap->ops->bmdma_status(ap); @@ -551,7 +549,7 @@ int ata_pci_init_bmdma(struct ata_host *host) return rc; /* request and iomap DMA region */ - rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev)); + rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME); if (rc) { dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n"); return -ENOMEM; @@ -621,8 +619,7 @@ int ata_pci_init_sff_host(struct ata_host *host) continue; } - rc = pcim_iomap_regions(pdev, 0x3 << base, - dev_driver_string(gdev)); + rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME); if (rc) { dev_printk(KERN_WARNING, gdev, "failed to request/iomap BARs for port %d " @@ -713,99 +710,6 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev, return rc; } -/** - * ata_pci_activate_sff_host - start SFF host, request IRQ and register it - * @host: target SFF ATA host - * @irq_handler: irq_handler used when requesting IRQ(s) - * @sht: scsi_host_template to use when registering the host - * - * This is the counterpart of ata_host_activate() for SFF ATA - * hosts. This separate helper is necessary because SFF hosts - * use two separate interrupts in legacy mode. - * - * LOCKING: - * Inherited from calling layer (may sleep). - * - * RETURNS: - * 0 on success, -errno otherwise. - */ -int ata_pci_activate_sff_host(struct ata_host *host, - irq_handler_t irq_handler, - struct scsi_host_template *sht) -{ - struct device *dev = host->dev; - struct pci_dev *pdev = to_pci_dev(dev); - const char *drv_name = dev_driver_string(host->dev); - int legacy_mode = 0, rc; - - rc = ata_host_start(host); - if (rc) - return rc; - - if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - u8 tmp8, mask; - - /* TODO: What if one channel is in native mode ... */ - pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); - mask = (1 << 2) | (1 << 0); - if ((tmp8 & mask) != mask) - legacy_mode = 1; -#if defined(CONFIG_NO_ATA_LEGACY) - /* Some platforms with PCI limits cannot address compat - port space. In that case we punt if their firmware has - left a device in compatibility mode */ - if (legacy_mode) { - printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); - return -EOPNOTSUPP; - } -#endif - } - - if (!devres_open_group(dev, NULL, GFP_KERNEL)) - return -ENOMEM; - - if (!legacy_mode && pdev->irq) { - rc = devm_request_irq(dev, pdev->irq, irq_handler, - IRQF_SHARED, drv_name, host); - if (rc) - goto out; - - ata_port_desc(host->ports[0], "irq %d", pdev->irq); - ata_port_desc(host->ports[1], "irq %d", pdev->irq); - } else if (legacy_mode) { - if (!ata_port_is_dummy(host->ports[0])) { - rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), - irq_handler, IRQF_SHARED, - drv_name, host); - if (rc) - goto out; - - ata_port_desc(host->ports[0], "irq %d", - ATA_PRIMARY_IRQ(pdev)); - } - - if (!ata_port_is_dummy(host->ports[1])) { - rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), - irq_handler, IRQF_SHARED, - drv_name, host); - if (rc) - goto out; - - ata_port_desc(host->ports[1], "irq %d", - ATA_SECONDARY_IRQ(pdev)); - } - } - - rc = ata_host_register(host, sht); - out: - if (rc == 0) - devres_remove_group(dev, NULL); - else - devres_release_group(dev, NULL); - - return rc; -} - /** * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized @@ -835,6 +739,8 @@ int ata_pci_init_one(struct pci_dev *pdev, struct device *dev = &pdev->dev; const struct ata_port_info *pi = NULL; struct ata_host *host = NULL; + u8 mask; + int legacy_mode = 0; int i, rc; DPRINTK("ENTER\n"); @@ -856,24 +762,95 @@ int ata_pci_init_one(struct pci_dev *pdev, if (!devres_open_group(dev, NULL, GFP_KERNEL)) return -ENOMEM; + /* FIXME: Really for ATA it isn't safe because the device may be + multi-purpose and we want to leave it alone if it was already + enabled. Secondly for shared use as Arjan says we want refcounting + + Checking dev->is_enabled is insufficient as this is not set at + boot for the primary video which is BIOS enabled + */ + rc = pcim_enable_device(pdev); if (rc) - goto out; + goto err_out; - /* prepare and activate SFF host */ + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u8 tmp8; + + /* TODO: What if one channel is in native mode ... */ + pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); + mask = (1 << 2) | (1 << 0); + if ((tmp8 & mask) != mask) + legacy_mode = 1; +#if defined(CONFIG_NO_ATA_LEGACY) + /* Some platforms with PCI limits cannot address compat + port space. In that case we punt if their firmware has + left a device in compatibility mode */ + if (legacy_mode) { + printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); + rc = -EOPNOTSUPP; + goto err_out; + } +#endif + } + + /* prepare host */ rc = ata_pci_prepare_sff_host(pdev, ppi, &host); if (rc) - goto out; + goto err_out; pci_set_master(pdev); - rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler, - pi->sht); - out: - if (rc == 0) - devres_remove_group(&pdev->dev, NULL); - else - devres_release_group(&pdev->dev, NULL); + /* start host and request IRQ */ + rc = ata_host_start(host); + if (rc) + goto err_out; + + if (!legacy_mode && pdev->irq) { + /* We may have no IRQ assigned in which case we can poll. This + shouldn't happen on a sane system but robustness is cheap + in this case */ + rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler, + IRQF_SHARED, DRV_NAME, host); + if (rc) + goto err_out; + + ata_port_desc(host->ports[0], "irq %d", pdev->irq); + ata_port_desc(host->ports[1], "irq %d", pdev->irq); + } else if (legacy_mode) { + if (!ata_port_is_dummy(host->ports[0])) { + rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), + pi->port_ops->irq_handler, + IRQF_SHARED, DRV_NAME, host); + if (rc) + goto err_out; + + ata_port_desc(host->ports[0], "irq %d", + ATA_PRIMARY_IRQ(pdev)); + } + + if (!ata_port_is_dummy(host->ports[1])) { + rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), + pi->port_ops->irq_handler, + IRQF_SHARED, DRV_NAME, host); + if (rc) + goto err_out; + + ata_port_desc(host->ports[1], "irq %d", + ATA_SECONDARY_IRQ(pdev)); + } + } + + /* register */ + rc = ata_host_register(host, pi->sht); + if (rc) + goto err_out; + + devres_remove_group(dev, NULL); + return 0; + +err_out: + devres_release_group(dev, NULL); return rc; } diff --git a/trunk/drivers/ata/libata.h b/trunk/drivers/ata/libata.h index 409ffb9af163..bbe59c2fd1e2 100644 --- a/trunk/drivers/ata/libata.h +++ b/trunk/drivers/ata/libata.h @@ -60,7 +60,6 @@ extern int atapi_dmadir; extern int atapi_passthru16; extern int libata_fua; extern int libata_noacpi; -extern int libata_allow_tpm; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, u64 block, u32 n_block, unsigned int tf_flags, @@ -86,6 +85,7 @@ extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link); extern int sata_set_spd_needed(struct ata_link *link); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); +extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); @@ -113,7 +113,6 @@ extern int ata_acpi_on_suspend(struct ata_port *ap); extern void ata_acpi_on_resume(struct ata_port *ap); extern int ata_acpi_on_devcfg(struct ata_device *dev); extern void ata_acpi_on_disable(struct ata_device *dev); -extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state); #else static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { } static inline void ata_acpi_associate(struct ata_host *host) { } @@ -122,8 +121,6 @@ static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } static inline void ata_acpi_on_resume(struct ata_port *ap) { } static inline int ata_acpi_on_devcfg(struct ata_device *dev) { return 0; } static inline void ata_acpi_on_disable(struct ata_device *dev) { } -static inline void ata_acpi_set_state(struct ata_port *ap, - pm_message_t state) { } #endif /* libata-scsi.c */ @@ -186,7 +183,6 @@ extern void ata_eh_report(struct ata_port *ap); extern int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); -extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, diff --git a/trunk/drivers/ata/pata_acpi.c b/trunk/drivers/ata/pata_acpi.c index 244098a80ce4..e4542ab9c7f8 100644 --- a/trunk/drivers/ata/pata_acpi.c +++ b/trunk/drivers/ata/pata_acpi.c @@ -81,6 +81,17 @@ static void pacpi_error_handler(struct ata_port *ap) NULL, ata_std_postreset); } +/* Welcome to ACPI, bring a bucket */ +static const unsigned int pio_cycle[7] = { + 600, 383, 240, 180, 120, 100, 80 +}; +static const unsigned int mwdma_cycle[5] = { + 480, 150, 120, 100, 80 +}; +static const unsigned int udma_cycle[7] = { + 120, 80, 60, 45, 30, 20, 15 +}; + /** * pacpi_discover_modes - filter non ACPI modes * @adev: ATA device @@ -92,20 +103,56 @@ static void pacpi_error_handler(struct ata_port *ap) static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev) { + int unit = adev->devno; struct pata_acpi *acpi = ap->private_data; + int i; + u32 t; + unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO); + struct ata_acpi_gtm probe; - unsigned int xfer_mask; probe = acpi->gtm; + /* We always use the 0 slot for crap hardware */ + if (!(probe.flags & 0x10)) + unit = 0; + ata_acpi_gtm(ap, &probe); - xfer_mask = ata_acpi_gtm_xfermask(adev, &probe); + /* Start by scanning for PIO modes */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].pio; + if (t <= pio_cycle[i]) { + mask |= (2 << (ATA_SHIFT_PIO + i)) - 1; + break; + } + } - if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA)) + /* See if we have MWDMA or UDMA data. We don't bother with MWDMA + if UDMA is availabe as this means the BIOS set UDMA and our + error changedown if it works is UDMA to PIO anyway */ + if (probe.flags & (1 << (2 * unit))) { + /* MWDMA */ + for (i = 0; i < 5; i++) { + t = probe.drive[unit].dma; + if (t <= mwdma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1; + break; + } + } + } else { + /* UDMA */ + for (i = 0; i < 7; i++) { + t = probe.drive[unit].dma; + if (t <= udma_cycle[i]) { + mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1; + break; + } + } + } + if (mask & (0xF8 << ATA_SHIFT_UDMA)) ap->cbl = ATA_CBL_PATA80; - - return xfer_mask; + return mask; } /** @@ -133,14 +180,12 @@ static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev) { int unit = adev->devno; struct pata_acpi *acpi = ap->private_data; - const struct ata_timing *t; if (!(acpi->gtm.flags & 0x10)) unit = 0; /* Now stuff the nS values into the structure */ - t = ata_timing_find_mode(adev->pio_mode); - acpi->gtm.drive[unit].pio = t->cycle; + acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0]; ata_acpi_stm(ap, &acpi->gtm); /* See what mode we actually got */ ata_acpi_gtm(ap, &acpi->gtm); @@ -156,18 +201,16 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) { int unit = adev->devno; struct pata_acpi *acpi = ap->private_data; - const struct ata_timing *t; if (!(acpi->gtm.flags & 0x10)) unit = 0; /* Now stuff the nS values into the structure */ - t = ata_timing_find_mode(adev->dma_mode); if (adev->dma_mode >= XFER_UDMA_0) { - acpi->gtm.drive[unit].dma = t->udma; + acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0]; acpi->gtm.flags |= (1 << (2 * unit)); } else { - acpi->gtm.drive[unit].dma = t->cycle; + acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0]; acpi->gtm.flags &= ~(1 << (2 * unit)); } ata_acpi_stm(ap, &acpi->gtm); diff --git a/trunk/drivers/ata/pata_ali.c b/trunk/drivers/ata/pata_ali.c index 7e68edf3c0f3..8caf9afc8b90 100644 --- a/trunk/drivers/ata/pata_ali.c +++ b/trunk/drivers/ata/pata_ali.c @@ -64,7 +64,7 @@ static int ali_cable_override(struct pci_dev *pdev) if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF) return 1; /* Mitac 8317 (Winbook-A) and relatives */ - if (pdev->subsystem_vendor == 0x1071 && pdev->subsystem_device == 0x8317) + if (pdev->subsystem_vendor == 0x1071 && pdev->subsystem_device == 0x8317) return 1; /* Systems by DMI */ if (dmi_check_system(cable_dmi_table)) diff --git a/trunk/drivers/ata/pata_amd.c b/trunk/drivers/ata/pata_amd.c index 761a66608d7b..3cc27b514654 100644 --- a/trunk/drivers/ata/pata_amd.c +++ b/trunk/drivers/ata/pata_amd.c @@ -220,62 +220,6 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) timing_setup(ap, adev, 0x40, adev->dma_mode, 4); } -/* Both host-side and drive-side detection results are worthless on NV - * PATAs. Ignore them and just follow what BIOS configured. Both the - * current configuration in PCI config reg and ACPI GTM result are - * cached during driver attach and are consulted to select transfer - * mode. - */ -static unsigned long nv_mode_filter(struct ata_device *dev, - unsigned long xfer_mask) -{ - static const unsigned int udma_mask_map[] = - { ATA_UDMA2, ATA_UDMA1, ATA_UDMA0, 0, - ATA_UDMA3, ATA_UDMA4, ATA_UDMA5, ATA_UDMA6 }; - struct ata_port *ap = dev->link->ap; - char acpi_str[32] = ""; - u32 saved_udma, udma; - const struct ata_acpi_gtm *gtm; - unsigned long bios_limit = 0, acpi_limit = 0, limit; - - /* find out what BIOS configured */ - udma = saved_udma = (unsigned long)ap->host->private_data; - - if (ap->port_no == 0) - udma >>= 16; - if (dev->devno == 0) - udma >>= 8; - - if ((udma & 0xc0) == 0xc0) - bios_limit = ata_pack_xfermask(0, 0, udma_mask_map[udma & 0x7]); - - /* consult ACPI GTM too */ - gtm = ata_acpi_init_gtm(ap); - if (gtm) { - acpi_limit = ata_acpi_gtm_xfermask(dev, gtm); - - snprintf(acpi_str, sizeof(acpi_str), " (%u:%u:0x%x)", - gtm->drive[0].dma, gtm->drive[1].dma, gtm->flags); - } - - /* be optimistic, EH can take care of things if something goes wrong */ - limit = bios_limit | acpi_limit; - - /* If PIO or DMA isn't configured at all, don't limit. Let EH - * handle it. - */ - if (!(limit & ATA_MASK_PIO)) - limit |= ATA_MASK_PIO; - if (!(limit & (ATA_MASK_MWDMA | ATA_MASK_UDMA))) - limit |= ATA_MASK_MWDMA | ATA_MASK_UDMA; - - ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, " - "BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n", - xfer_mask, limit, xfer_mask & limit, bios_limit, - saved_udma, acpi_limit, acpi_str); - - return xfer_mask & limit; -} /** * nv_probe_init - cable detection @@ -308,6 +252,31 @@ static void nv_error_handler(struct ata_port *ap) ata_std_postreset); } +static int nv_cable_detect(struct ata_port *ap) +{ + static const u8 bitmask[2] = {0x03, 0x0C}; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u8 ata66; + u16 udma; + int cbl; + + pci_read_config_byte(pdev, 0x52, &ata66); + if (ata66 & bitmask[ap->port_no]) + cbl = ATA_CBL_PATA80; + else + cbl = ATA_CBL_PATA40; + + /* We now have to double check because the Nvidia boxes BIOS + doesn't always set the cable bits but does set mode bits */ + pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma); + if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400) + cbl = ATA_CBL_PATA80; + /* And a triple check across suspend/resume with ACPI around */ + if (ata_acpi_cbl_80wire(ap)) + cbl = ATA_CBL_PATA80; + return cbl; +} + /** * nv100_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -345,14 +314,6 @@ static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev) timing_setup(ap, adev, 0x50, adev->dma_mode, 4); } -static void nv_host_stop(struct ata_host *host) -{ - u32 udma = (unsigned long)host->private_data; - - /* restore PCI config register 0x60 */ - pci_write_config_dword(to_pci_dev(host->dev), 0x60, udma); -} - static struct scsi_host_template amd_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -517,8 +478,7 @@ static struct ata_port_operations nv100_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_ignore, - .mode_filter = nv_mode_filter, + .cable_detect = nv_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -535,7 +495,6 @@ static struct ata_port_operations nv100_port_ops = { .irq_on = ata_irq_on, .port_start = ata_sff_port_start, - .host_stop = nv_host_stop, }; static struct ata_port_operations nv133_port_ops = { @@ -552,8 +511,7 @@ static struct ata_port_operations nv133_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_ignore, - .mode_filter = nv_mode_filter, + .cable_detect = nv_cable_detect, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -570,7 +528,6 @@ static struct ata_port_operations nv133_port_ops = { .irq_on = ata_irq_on, .port_start = ata_sff_port_start, - .host_stop = nv_host_stop, }; static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) @@ -657,8 +614,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd100_port_ops } }; - struct ata_port_info pi; - const struct ata_port_info *ppi[] = { &pi, NULL }; + const struct ata_port_info *ppi[] = { NULL, NULL }; static int printed_version; int type = id->driver_data; u8 fifo; @@ -672,19 +628,6 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (type == 1 && pdev->revision > 0x7) type = 2; - /* Serenade ? */ - if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD && - pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) - type = 6; /* UDMA 100 only */ - - /* - * Okay, type is determined now. Apply type-specific workarounds. - */ - pi = info[type]; - - if (type < 3) - ata_pci_clear_simplex(pdev); - /* Check for AMD7411 */ if (type == 3) /* FIFO is broken */ @@ -692,17 +635,16 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) else pci_write_config_byte(pdev, 0x41, fifo | 0xF0); - /* Cable detection on Nvidia chips doesn't work too well, - * cache BIOS programmed UDMA mode. - */ - if (type == 7 || type == 8) { - u32 udma; + /* Serenade ? */ + if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD && + pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) + type = 6; /* UDMA 100 only */ - pci_read_config_dword(pdev, 0x60, &udma); - pi.private_data = (void *)(unsigned long)udma; - } + if (type < 3) + ata_pci_clear_simplex(pdev); /* And fire it up */ + ppi[0] = &info[type]; return ata_pci_init_one(pdev, ppi); } diff --git a/trunk/drivers/ata/pata_bf54x.c b/trunk/drivers/ata/pata_bf54x.c index a32e3c44a606..7842cc487359 100644 --- a/trunk/drivers/ata/pata_bf54x.c +++ b/trunk/drivers/ata/pata_bf54x.c @@ -832,7 +832,6 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc) { unsigned short config = WDSIZE_16; struct scatterlist *sg; - unsigned int si; pr_debug("in atapi dma setup\n"); /* Program the ATA_CTRL register with dir */ @@ -840,7 +839,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc) /* fill the ATAPI DMA controller */ set_dma_config(CH_ATAPI_TX, config); set_dma_x_modify(CH_ATAPI_TX, 2); - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg)); set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1); } @@ -849,7 +848,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc) /* fill the ATAPI DMA controller */ set_dma_config(CH_ATAPI_RX, config); set_dma_x_modify(CH_ATAPI_RX, 2); - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg)); set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1); } @@ -868,7 +867,6 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; struct scatterlist *sg; - unsigned int si; pr_debug("in atapi dma start\n"); if (!(ap->udma_mask || ap->mwdma_mask)) @@ -883,7 +881,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) * data cache is enabled. Otherwise, this loop * is an empty loop and optimized out. */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { flush_dcache_range(sg_dma_address(sg), sg_dma_address(sg) + sg_dma_len(sg)); } @@ -912,7 +910,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST); /* Set transfer length to buffer len */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); } @@ -934,7 +932,6 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; - unsigned int si; pr_debug("in atapi dma stop\n"); if (!(ap->udma_mask || ap->mwdma_mask)) @@ -953,7 +950,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc) * data cache is enabled. Otherwise, this loop * is an empty loop and optimized out. */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { invalidate_dcache_range( sg_dma_address(sg), sg_dma_address(sg) @@ -1170,36 +1167,34 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap) * Note: Original code is ata_data_xfer(). */ -static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) +static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { - struct ata_port *ap = dev->link->ap; - void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; - unsigned short *buf16 = (u16 *)buf; + unsigned short *buf16 = (u16 *) buf; + void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; /* Transfer multiple of 2 bytes */ - if (rw == READ) - read_atapi_data(base, words, buf16); - else + if (write_data) { write_atapi_data(base, words, buf16); + } else { + read_atapi_data(base, words, buf16); + } /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { unsigned short align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (rw == READ) { - read_atapi_data(base, 1, align_buf); - memcpy(trailing_buf, align_buf, 1); - } else { + if (write_data) { memcpy(align_buf, trailing_buf, 1); write_atapi_data(base, 1, align_buf); + } else { + read_atapi_data(base, 1, align_buf); + memcpy(trailing_buf, align_buf, 1); } - words++; } - - return words << 1; } /** diff --git a/trunk/drivers/ata/pata_cs5520.c b/trunk/drivers/ata/pata_cs5520.c index d4590f546c49..33f7f0843f4f 100644 --- a/trunk/drivers/ata/pata_cs5520.c +++ b/trunk/drivers/ata/pata_cs5520.c @@ -198,7 +198,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi }; const struct ata_port_info *ppi[2]; u8 pcicfg; - void __iomem *iomap[5]; + void *iomap[5]; struct ata_host *host; struct ata_ioports *ioaddr; int i, rc; diff --git a/trunk/drivers/ata/pata_hpt37x.c b/trunk/drivers/ata/pata_hpt37x.c index 68eb34929cec..c79f066c2bc9 100644 --- a/trunk/drivers/ata/pata_hpt37x.c +++ b/trunk/drivers/ata/pata_hpt37x.c @@ -847,16 +847,15 @@ static u32 hpt374_read_freq(struct pci_dev *pdev) u32 freq; unsigned long io_base = pci_resource_start(pdev, 4); if (PCI_FUNC(pdev->devfn) & 1) { - struct pci_dev *pdev_0; - - pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1); + struct pci_dev *pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1); /* Someone hot plugged the controller on us ? */ if (pdev_0 == NULL) return 0; io_base = pci_resource_start(pdev_0, 4); freq = inl(io_base + 0x90); pci_dev_put(pdev_0); - } else + } + else freq = inl(io_base + 0x90); return freq; } diff --git a/trunk/drivers/ata/pata_icside.c b/trunk/drivers/ata/pata_icside.c index 5b8586dac63b..842fe08a3c13 100644 --- a/trunk/drivers/ata/pata_icside.c +++ b/trunk/drivers/ata/pata_icside.c @@ -224,7 +224,6 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) struct pata_icside_state *state = ap->host->private_data; struct scatterlist *sg, *rsg = state->sg; unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE; - unsigned int si; /* * We are simplex; BUG if we try to fiddle with DMA @@ -235,7 +234,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) /* * Copy ATAs scattered sg list into a contiguous array of sg */ - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { memcpy(rsg, sg, sizeof(*sg)); rsg++; } diff --git a/trunk/drivers/ata/pata_it821x.c b/trunk/drivers/ata/pata_it821x.c index 109ddd42c266..ca9aae09daed 100644 --- a/trunk/drivers/ata/pata_it821x.c +++ b/trunk/drivers/ata/pata_it821x.c @@ -430,7 +430,7 @@ static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command); - return AC_ERR_DEV; + return AC_ERR_INVALID; } /** @@ -516,37 +516,6 @@ static void it821x_dev_config(struct ata_device *adev) printk("(%dK stripe)", adev->id[146]); printk(".\n"); } - /* This is a controller firmware triggered funny, don't - report the drive faulty! */ - adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC; -} - -/** - * it821x_ident_hack - Hack identify data up - * @ap: Port - * - * Walk the devices on this firmware driven port and slightly - * mash the identify data to stop us and common tools trying to - * use features not firmware supported. The firmware itself does - * some masking (eg SMART) but not enough. - * - * This is a bit of an abuse of the cable method, but it is the - * only method called at the right time. We could modify the libata - * core specifically for ident hacking but while we have one offender - * it seems better to keep the fallout localised. - */ - -static int it821x_ident_hack(struct ata_port *ap) -{ - struct ata_device *adev; - ata_link_for_each_dev(adev, &ap->link) { - if (ata_dev_enabled(adev)) { - adev->id[84] &= ~(1 << 6); /* No FUA */ - adev->id[85] &= ~(1 << 10); /* No HPA */ - adev->id[76] = 0; /* No NCQ/AN etc */ - } - } - return ata_cable_unknown(ap); } @@ -665,7 +634,7 @@ static struct ata_port_operations it821x_smart_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = it821x_ident_hack, + .cable_detect = ata_cable_unknown, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/trunk/drivers/ata/pata_ixp4xx_cf.c b/trunk/drivers/ata/pata_ixp4xx_cf.c index 030878fedeb5..120b5bfa7ce6 100644 --- a/trunk/drivers/ata/pata_ixp4xx_cf.c +++ b/trunk/drivers/ata/pata_ixp4xx_cf.c @@ -42,13 +42,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) return 0; } -static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw) +static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { unsigned int i; unsigned int words = buflen >> 1; u16 *buf16 = (u16 *) buf; - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = adev->link->ap; void __iomem *mmio = ap->ioaddr.data_addr; struct ixp4xx_pata_data *data = ap->host->dev->platform_data; @@ -59,32 +59,30 @@ static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev, udelay(100); /* Transfer multiple of 2 bytes */ - if (rw == READ) - for (i = 0; i < words; i++) - buf16[i] = readw(mmio); - else + if (write_data) { for (i = 0; i < words; i++) writew(buf16[i], mmio); + } else { + for (i = 0; i < words; i++) + buf16[i] = readw(mmio); + } /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { u16 align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (rw == READ) { - align_buf[0] = readw(mmio); - memcpy(trailing_buf, align_buf, 1); - } else { + if (write_data) { memcpy(align_buf, trailing_buf, 1); writew(align_buf[0], mmio); + } else { + align_buf[0] = readw(mmio); + memcpy(trailing_buf, align_buf, 1); } - words++; } udelay(100); *data->cs0_cfg |= 0x01; - - return words << 1; } static struct scsi_host_template ixp4xx_sht = { diff --git a/trunk/drivers/ata/pata_legacy.c b/trunk/drivers/ata/pata_legacy.c index 333dc15f8ccf..17159b5e1e43 100644 --- a/trunk/drivers/ata/pata_legacy.c +++ b/trunk/drivers/ata/pata_legacy.c @@ -28,6 +28,7 @@ * * Unsupported but docs exist: * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220 + * Winbond W83759A * * This driver handles legacy (that is "ISA/VLB side") IDE ports found * on PC class systems. There are three hybrid devices that are exceptions @@ -35,7 +36,7 @@ * the MPIIX where the tuning is PCI side but the IDE is "ISA side". * * Specific support is included for the ht6560a/ht6560b/opti82c611a/ - * opti82c465mv/promise 20230c/20630/winbond83759A + * opti82c465mv/promise 20230c/20630 * * Use the autospeed and pio_mask options with: * Appian ADI/2 aka CLPD7220 or AIC25VL01. @@ -46,6 +47,9 @@ * For now use autospeed and pio_mask as above with the W83759A. This may * change. * + * TODO + * Merge existing pata_qdi driver + * */ #include @@ -60,13 +64,12 @@ #include #define DRV_NAME "pata_legacy" -#define DRV_VERSION "0.6.5" +#define DRV_VERSION "0.5.5" #define NR_HOST 6 -static int all; -module_param(all, int, 0444); -MODULE_PARM_DESC(all, "Grab all legacy port devices, even if PCI(0=off, 1=on)"); +static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; +static int legacy_irq[NR_HOST] = { 14, 15, 11, 10, 8, 12 }; struct legacy_data { unsigned long timing; @@ -77,106 +80,20 @@ struct legacy_data { }; -enum controller { - BIOS = 0, - SNOOP = 1, - PDC20230 = 2, - HT6560A = 3, - HT6560B = 4, - OPTI611A = 5, - OPTI46X = 6, - QDI6500 = 7, - QDI6580 = 8, - QDI6580DP = 9, /* Dual channel mode is different */ - W83759A = 10, - - UNKNOWN = -1 -}; - - -struct legacy_probe { - unsigned char *name; - unsigned long port; - unsigned int irq; - unsigned int slot; - enum controller type; - unsigned long private; -}; - -struct legacy_controller { - const char *name; - struct ata_port_operations *ops; - unsigned int pio_mask; - unsigned int flags; - int (*setup)(struct platform_device *, struct legacy_probe *probe, - struct legacy_data *data); -}; - -static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; - -static struct legacy_probe probe_list[NR_HOST]; static struct legacy_data legacy_data[NR_HOST]; static struct ata_host *legacy_host[NR_HOST]; static int nr_legacy_host; -static int probe_all; /* Set to check all ISA port ranges */ -static int ht6560a; /* HT 6560A on primary 1, second 2, both 3 */ -static int ht6560b; /* HT 6560A on primary 1, second 2, both 3 */ -static int opti82c611a; /* Opti82c611A on primary 1, sec 2, both 3 */ -static int opti82c46x; /* Opti 82c465MV present(pri/sec autodetect) */ -static int qdi; /* Set to probe QDI controllers */ -static int winbond; /* Set to probe Winbond controllers, - give I/O port if non stdanard */ -static int autospeed; /* Chip present which snoops speed changes */ -static int pio_mask = 0x1F; /* PIO range for autospeed devices */ +static int probe_all; /* Set to check all ISA port ranges */ +static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */ +static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */ +static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */ +static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */ +static int autospeed; /* Chip present which snoops speed changes */ +static int pio_mask = 0x1F; /* PIO range for autospeed devices */ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ -/** - * legacy_probe_add - Add interface to probe list - * @port: Controller port - * @irq: IRQ number - * @type: Controller type - * @private: Controller specific info - * - * Add an entry into the probe list for ATA controllers. This is used - * to add the default ISA slots and then to build up the table - * further according to other ISA/VLB/Weird device scans - * - * An I/O port list is used to keep ordering stable and sane, as we - * don't have any good way to talk about ordering otherwise - */ - -static int legacy_probe_add(unsigned long port, unsigned int irq, - enum controller type, unsigned long private) -{ - struct legacy_probe *lp = &probe_list[0]; - int i; - struct legacy_probe *free = NULL; - - for (i = 0; i < NR_HOST; i++) { - if (lp->port == 0 && free == NULL) - free = lp; - /* Matching port, or the correct slot for ordering */ - if (lp->port == port || legacy_port[i] == port) { - free = lp; - break; - } - lp++; - } - if (free == NULL) { - printk(KERN_ERR "pata_legacy: Too many interfaces.\n"); - return -1; - } - /* Fill in the entry for later probing */ - free->port = port; - free->irq = irq; - free->type = type; - free->private = private; - return 0; -} - - /** * legacy_set_mode - mode setting * @link: IDE link @@ -196,8 +113,7 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { - ata_dev_printk(dev, KERN_INFO, - "configured for PIO\n"); + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; @@ -255,7 +171,7 @@ static struct ata_port_operations simple_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .port_start = ata_port_start, }; static struct ata_port_operations legacy_port_ops = { @@ -282,16 +198,15 @@ static struct ata_port_operations legacy_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .port_start = ata_port_start, }; /* * Promise 20230C and 20620 support * - * This controller supports PIO0 to PIO2. We set PIO timings - * conservatively to allow for 50MHz Vesa Local Bus. The 20620 DMA - * support is weird being DMA to controller and PIO'd to the host - * and not supported. + * This controller supports PIO0 to PIO2. We set PIO timings conservatively to + * allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to + * controller and PIO'd to the host and not supported. */ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -306,7 +221,8 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) local_irq_save(flags); /* Unlock the control interface */ - do { + do + { inb(0x1F5); outb(inb(0x1F2) | 0x80, 0x1F2); inb(0x1F2); @@ -315,7 +231,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) inb(0x1F2); inb(0x1F2); } - while ((inb(0x1F2) & 0x80) && --tries); + while((inb(0x1F2) & 0x80) && --tries); local_irq_restore(flags); @@ -333,14 +249,13 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) } -static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw) +static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - if (ata_id_has_dword_io(dev->id)) { - struct ata_port *ap = dev->link->ap; - int slop = buflen & 3; - unsigned long flags; + struct ata_port *ap = adev->link->ap; + int slop = buflen & 3; + unsigned long flags; + if (ata_id_has_dword_io(adev->id)) { local_irq_save(flags); /* Perform the 32bit I/O synchronization sequence */ @@ -349,27 +264,26 @@ static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, ioread8(ap->ioaddr.nsect_addr); /* Now the data */ - if (rw == READ) - ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else + + if (write_data) iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); + else + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { - u32 pad; - if (rw == READ) { - pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); - memcpy(buf + buflen - slop, &pad, slop); - } else { + __le32 pad = 0; + if (write_data) { memcpy(&pad, buf + buflen - slop, slop); iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); + } else { + pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); } - buflen += 4 - slop; } local_irq_restore(flags); - } else - buflen = ata_data_xfer_noirq(dev, buf, buflen, rw); - - return buflen; + } + else + ata_data_xfer_noirq(adev, buf, buflen, write_data); } static struct ata_port_operations pdc20230_port_ops = { @@ -396,14 +310,14 @@ static struct ata_port_operations pdc20230_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .port_start = ata_port_start, }; /* * Holtek 6560A support * - * This controller supports PIO0 to PIO2 (no IORDY even though higher - * timings can be loaded). + * This controller supports PIO0 to PIO2 (no IORDY even though higher timings + * can be loaded). */ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -450,14 +364,14 @@ static struct ata_port_operations ht6560a_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .port_start = ata_port_start, }; /* * Holtek 6560B support * - * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO - * setting unless we see an ATAPI device in which case we force it off. + * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting + * unless we see an ATAPI device in which case we force it off. * * FIXME: need to implement 2nd channel support. */ @@ -484,7 +398,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) if (adev->class != ATA_DEV_ATA) { u8 rconf = inb(0x3E6); if (rconf & 0x24) { - rconf &= ~0x24; + rconf &= ~ 0x24; outb(rconf, 0x3E6); } } @@ -509,13 +423,13 @@ static struct ata_port_operations ht6560b_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ + .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .port_start = ata_port_start, }; /* @@ -548,8 +462,7 @@ static u8 opti_syscfg(u8 reg) * This controller supports PIO0 to PIO3. */ -static void opti82c611a_set_piomode(struct ata_port *ap, - struct ata_device *adev) +static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev) { u8 active, recover, setup; struct ata_timing t; @@ -636,7 +549,7 @@ static struct ata_port_operations opti82c611a_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .port_start = ata_port_start, }; /* @@ -768,398 +681,77 @@ static struct ata_port_operations opti82c46x_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_sff_port_start, + .port_start = ata_port_start, }; -static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct ata_timing t; - struct legacy_data *qdi = ap->host->private_data; - int active, recovery; - u8 timing; - - /* Get the timing data in cycles */ - ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - - if (qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); - } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); - } - timing = (recovery << 4) | active | 0x08; - - qdi->clock[adev->devno] = timing; - - outb(timing, qdi->timing); -} /** - * qdi6580dp_set_piomode - PIO setup for dual channel - * @ap: Port - * @adev: Device + * legacy_init_one - attach a legacy interface + * @port: port number + * @io: I/O port start + * @ctrl: control port * @irq: interrupt line * - * In dual channel mode the 6580 has one clock per channel and we have - * to software clockswitch in qc_issue_prot. + * Register an ISA bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. */ -static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev) +static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq) { - struct ata_timing t; - struct legacy_data *qdi = ap->host->private_data; - int active, recovery; - u8 timing; - - /* Get the timing data in cycles */ - ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - - if (qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); - } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); - } - timing = (recovery << 4) | active | 0x08; - - qdi->clock[adev->devno] = timing; + struct legacy_data *ld = &legacy_data[nr_legacy_host]; + struct ata_host *host; + struct ata_port *ap; + struct platform_device *pdev; + struct ata_port_operations *ops = &legacy_port_ops; + void __iomem *io_addr, *ctrl_addr; + int pio_modes = pio_mask; + u32 mask = (1 << port); + u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; + int ret; - outb(timing, qdi->timing + 2 * ap->port_no); - /* Clear the FIFO */ - if (adev->class != ATA_DEV_ATA) - outb(0x5F, qdi->timing + 3); -} + pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); -/** - * qdi6580_set_piomode - PIO setup for single channel - * @ap: Port - * @adev: Device - * - * In single channel mode the 6580 has one clock per device and we can - * avoid the requirement to clock switch. We also have to load the timing - * into the right clock according to whether we are master or slave. - */ + ret = -EBUSY; + if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL || + devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL) + goto fail; -static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct ata_timing t; - struct legacy_data *qdi = ap->host->private_data; - int active, recovery; - u8 timing; + ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io, 8); + ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1); + if (!io_addr || !ctrl_addr) + goto fail; - /* Get the timing data in cycles */ - ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - - if (qdi->fast) { - active = 8 - FIT(t.active, 1, 8); - recovery = 18 - FIT(t.recover, 3, 18); - } else { - active = 9 - FIT(t.active, 2, 9); - recovery = 15 - FIT(t.recover, 0, 15); + if (ht6560a & mask) { + ops = &ht6560a_port_ops; + pio_modes = 0x07; + iordy = ATA_FLAG_NO_IORDY; } - timing = (recovery << 4) | active | 0x08; - qdi->clock[adev->devno] = timing; - outb(timing, qdi->timing + 2 * adev->devno); - /* Clear the FIFO */ - if (adev->class != ATA_DEV_ATA) - outb(0x5F, qdi->timing + 3); -} - -/** - * qdi_qc_issue_prot - command issue - * @qc: command pending - * - * Called when the libata layer is about to issue a command. We wrap - * this interface so that we can load the correct ATA timings. - */ - -static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_device *adev = qc->dev; - struct legacy_data *qdi = ap->host->private_data; - - if (qdi->clock[adev->devno] != qdi->last) { - if (adev->pio_mode) { - qdi->last = qdi->clock[adev->devno]; - outb(qdi->clock[adev->devno], qdi->timing + - 2 * ap->port_no); - } + if (ht6560b & mask) { + ops = &ht6560b_port_ops; + pio_modes = 0x1F; + } + if (opti82c611a & mask) { + ops = &opti82c611a_port_ops; + pio_modes = 0x0F; + } + if (opti82c46x & mask) { + ops = &opti82c46x_port_ops; + pio_modes = 0x0F; } - return ata_qc_issue_prot(qc); -} - -static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int rw) -{ - struct ata_port *ap = adev->link->ap; - int slop = buflen & 3; - - if (ata_id_has_dword_io(adev->id)) { - if (rw == WRITE) - iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else - ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - - if (unlikely(slop)) { - u32 pad; - if (rw == WRITE) { - memcpy(&pad, buf + buflen - slop, slop); - pad = le32_to_cpu(pad); - iowrite32(pad, ap->ioaddr.data_addr); - } else { - pad = ioread32(ap->ioaddr.data_addr); - pad = cpu_to_le32(pad); - memcpy(buf + buflen - slop, &pad, slop); - } - } - return (buflen + 3) & ~3; - } else - return ata_data_xfer(adev, buf, buflen, rw); -} - -static int qdi_port(struct platform_device *dev, - struct legacy_probe *lp, struct legacy_data *ld) -{ - if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL) - return -EBUSY; - ld->timing = lp->private; - return 0; -} - -static struct ata_port_operations qdi6500_port_ops = { - .set_piomode = qdi6500_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = qdi_qc_issue_prot, - - .data_xfer = vlb32_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -static struct ata_port_operations qdi6580_port_ops = { - .set_piomode = qdi6580_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = vlb32_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -static struct ata_port_operations qdi6580dp_port_ops = { - .set_piomode = qdi6580dp_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = qdi_qc_issue_prot, - - .data_xfer = vlb32_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -static DEFINE_SPINLOCK(winbond_lock); - -static void winbond_writecfg(unsigned long port, u8 reg, u8 val) -{ - unsigned long flags; - spin_lock_irqsave(&winbond_lock, flags); - outb(reg, port + 0x01); - outb(val, port + 0x02); - spin_unlock_irqrestore(&winbond_lock, flags); -} - -static u8 winbond_readcfg(unsigned long port, u8 reg) -{ - u8 val; - - unsigned long flags; - spin_lock_irqsave(&winbond_lock, flags); - outb(reg, port + 0x01); - val = inb(port + 0x02); - spin_unlock_irqrestore(&winbond_lock, flags); - - return val; -} - -static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - struct ata_timing t; - struct legacy_data *winbond = ap->host->private_data; - int active, recovery; - u8 reg; - int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); - - reg = winbond_readcfg(winbond->timing, 0x81); - - /* Get the timing data in cycles */ - if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ - ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); - else - ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); - - active = (FIT(t.active, 3, 17) - 1) & 0x0F; - recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; - timing = (active << 4) | recovery; - winbond_writecfg(winbond->timing, timing, reg); - - /* Load the setup timing */ - - reg = 0x35; - if (adev->class != ATA_DEV_ATA) - reg |= 0x08; /* FIFO off */ - if (!ata_pio_need_iordy(adev)) - reg |= 0x02; /* IORDY off */ - reg |= (FIT(t.setup, 0, 3) << 6); - winbond_writecfg(winbond->timing, timing + 1, reg); -} - -static int winbond_port(struct platform_device *dev, - struct legacy_probe *lp, struct legacy_data *ld) -{ - if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL) - return -EBUSY; - ld->timing = lp->private; - return 0; -} - -static struct ata_port_operations winbond_port_ops = { - .set_piomode = winbond_set_piomode, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = vlb32_data_xfer, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -static struct legacy_controller controllers[] = { - {"BIOS", &legacy_port_ops, 0x1F, - ATA_FLAG_NO_IORDY, NULL }, - {"Snooping", &simple_port_ops, 0x1F, - 0 , NULL }, - {"PDC20230", &pdc20230_port_ops, 0x7, - ATA_FLAG_NO_IORDY, NULL }, - {"HT6560A", &ht6560a_port_ops, 0x07, - ATA_FLAG_NO_IORDY, NULL }, - {"HT6560B", &ht6560b_port_ops, 0x1F, - ATA_FLAG_NO_IORDY, NULL }, - {"OPTI82C611A", &opti82c611a_port_ops, 0x0F, - 0 , NULL }, - {"OPTI82C46X", &opti82c46x_port_ops, 0x0F, - 0 , NULL }, - {"QDI6500", &qdi6500_port_ops, 0x07, - ATA_FLAG_NO_IORDY, qdi_port }, - {"QDI6580", &qdi6580_port_ops, 0x1F, - 0 , qdi_port }, - {"QDI6580DP", &qdi6580dp_port_ops, 0x1F, - 0 , qdi_port }, - {"W83759A", &winbond_port_ops, 0x1F, - 0 , winbond_port } -}; -/** - * probe_chip_type - Discover controller - * @probe: Probe entry to check - * - * Probe an ATA port and identify the type of controller. We don't - * check if the controller appears to be driveless at this point. - */ + /* Probe for automatically detectable controllers */ -static __init int probe_chip_type(struct legacy_probe *probe) -{ - int mask = 1 << probe->slot; - - if (winbond && (probe->port == 0x1F0 || probe->port == 0x170)) { - u8 reg = winbond_readcfg(winbond, 0x81); - reg |= 0x80; /* jumpered mode off */ - winbond_writecfg(winbond, 0x81, reg); - reg = winbond_readcfg(winbond, 0x83); - reg |= 0xF0; /* local control */ - winbond_writecfg(winbond, 0x83, reg); - reg = winbond_readcfg(winbond, 0x85); - reg |= 0xF0; /* programmable timing */ - winbond_writecfg(winbond, 0x85, reg); - - reg = winbond_readcfg(winbond, 0x81); - - if (reg & mask) - return W83759A; - } - if (probe->port == 0x1F0) { + if (io == 0x1F0 && ops == &legacy_port_ops) { unsigned long flags; + local_irq_save(flags); + /* Probes */ - outb(inb(0x1F2) | 0x80, 0x1F2); inb(0x1F5); + outb(inb(0x1F2) | 0x80, 0x1F2); inb(0x1F2); inb(0x3F6); inb(0x3F6); @@ -1168,83 +760,29 @@ static __init int probe_chip_type(struct legacy_probe *probe) if ((inb(0x1F2) & 0x80) == 0) { /* PDC20230c or 20630 ? */ - printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller" - " detected.\n"); + printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n"); + pio_modes = 0x07; + ops = &pdc20230_port_ops; + iordy = ATA_FLAG_NO_IORDY; udelay(100); inb(0x1F5); - local_irq_restore(flags); - return PDC20230; } else { outb(0x55, 0x1F2); inb(0x1F2); inb(0x1F2); - if (inb(0x1F2) == 0x00) - printk(KERN_INFO "PDC20230-B VLB ATA " - "controller detected.\n"); - local_irq_restore(flags); - return BIOS; + if (inb(0x1F2) == 0x00) { + printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n"); + } } local_irq_restore(flags); } - if (ht6560a & mask) - return HT6560A; - if (ht6560b & mask) - return HT6560B; - if (opti82c611a & mask) - return OPTI611A; - if (opti82c46x & mask) - return OPTI46X; - if (autospeed & mask) - return SNOOP; - return BIOS; -} - - -/** - * legacy_init_one - attach a legacy interface - * @pl: probe record - * - * Register an ISA bus IDE interface. Such interfaces are PIO and we - * assume do not support IRQ sharing. - */ - -static __init int legacy_init_one(struct legacy_probe *probe) -{ - struct legacy_controller *controller = &controllers[probe->type]; - int pio_modes = controller->pio_mask; - unsigned long io = probe->port; - u32 mask = (1 << probe->slot); - struct ata_port_operations *ops = controller->ops; - struct legacy_data *ld = &legacy_data[probe->slot]; - struct ata_host *host = NULL; - struct ata_port *ap; - struct platform_device *pdev; - struct ata_device *dev; - void __iomem *io_addr, *ctrl_addr; - u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; - int ret; - iordy |= controller->flags; - - pdev = platform_device_register_simple(DRV_NAME, probe->slot, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - ret = -EBUSY; - if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL || - devm_request_region(&pdev->dev, io + 0x0206, 1, - "pata_legacy") == NULL) - goto fail; + /* Chip does mode setting by command snooping */ + if (ops == &legacy_port_ops && (autospeed & mask)) + ops = &simple_port_ops; ret = -ENOMEM; - io_addr = devm_ioport_map(&pdev->dev, io, 8); - ctrl_addr = devm_ioport_map(&pdev->dev, io + 0x0206, 1); - if (!io_addr || !ctrl_addr) - goto fail; - if (controller->setup) - if (controller->setup(pdev, probe, ld) < 0) - goto fail; host = ata_host_alloc(&pdev->dev, 1); if (!host) goto fail; @@ -1257,29 +795,19 @@ static __init int legacy_init_one(struct legacy_probe *probe) ap->ioaddr.altstatus_addr = ctrl_addr; ap->ioaddr.ctl_addr = ctrl_addr; ata_std_ports(&ap->ioaddr); - ap->host->private_data = ld; + ap->private_data = ld; - ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, io + 0x0206); + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl); - ret = ata_host_activate(host, probe->irq, ata_interrupt, 0, - &legacy_sht); + ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht); if (ret) goto fail; - ld->platform_dev = pdev; - /* Nothing found means we drop the port as its probably not there */ + legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev); + ld->platform_dev = pdev; + return 0; - ret = -ENODEV; - ata_link_for_each_dev(dev, &ap->link) { - if (!ata_dev_absent(dev)) { - legacy_host[probe->slot] = host; - ld->platform_dev = pdev; - return 0; - } - } fail: - if (host) - ata_host_detach(host); platform_device_unregister(pdev); return ret; } @@ -1290,15 +818,13 @@ static __init int legacy_init_one(struct legacy_probe *probe) * @master: set this if we find an ATA master * @master: set this if we find an ATA secondary * - * A small number of vendors implemented early PCI ATA interfaces - * on bridge logic without the ATA interface being PCI visible. - * Where we have a matching PCI driver we must skip the relevant - * device here. If we don't know about it then the legacy driver - * is the right driver anyway. + * A small number of vendors implemented early PCI ATA interfaces on bridge logic + * without the ATA interface being PCI visible. Where we have a matching PCI driver + * we must skip the relevant device here. If we don't know about it then the legacy + * driver is the right driver anyway. */ -static void __init legacy_check_special_cases(struct pci_dev *p, int *primary, - int *secondary) +static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary) { /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */ if (p->vendor == 0x1078 && p->device == 0x0000) { @@ -1314,8 +840,7 @@ static void __init legacy_check_special_cases(struct pci_dev *p, int *primary, if (p->vendor == 0x8086 && p->device == 0x1234) { u16 r; pci_read_config_word(p, 0x6C, &r); - if (r & 0x8000) { - /* ATA port enabled */ + if (r & 0x8000) { /* ATA port enabled */ if (r & 0x4000) *secondary = 1; else @@ -1325,114 +850,6 @@ static void __init legacy_check_special_cases(struct pci_dev *p, int *primary, } } -static __init void probe_opti_vlb(void) -{ - /* If an OPTI 82C46X is present find out where the channels are */ - static const char *optis[4] = { - "3/463MV", "5MV", - "5MVA", "5MVB" - }; - u8 chans = 1; - u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6; - - opti82c46x = 3; /* Assume master and slave first */ - printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", - optis[ctrl]); - if (ctrl == 3) - chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1; - ctrl = opti_syscfg(0xAC); - /* Check enabled and this port is the 465MV port. On the - MVB we may have two channels */ - if (ctrl & 8) { - if (chans == 2) { - legacy_probe_add(0x1F0, 14, OPTI46X, 0); - legacy_probe_add(0x170, 15, OPTI46X, 0); - } - if (ctrl & 4) - legacy_probe_add(0x170, 15, OPTI46X, 0); - else - legacy_probe_add(0x1F0, 14, OPTI46X, 0); - } else - legacy_probe_add(0x1F0, 14, OPTI46X, 0); -} - -static __init void qdi65_identify_port(u8 r, u8 res, unsigned long port) -{ - static const unsigned long ide_port[2] = { 0x170, 0x1F0 }; - /* Check card type */ - if ((r & 0xF0) == 0xC0) { - /* QD6500: single channel */ - if (r & 8) - /* Disabled ? */ - return; - legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), - QDI6500, port); - } - if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { - /* QD6580: dual channel */ - if (!request_region(port + 2 , 2, "pata_qdi")) { - release_region(port, 2); - return; - } - res = inb(port + 3); - /* Single channel mode ? */ - if (res & 1) - legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), - QDI6580, port); - else { /* Dual channel mode */ - legacy_probe_add(0x1F0, 14, QDI6580DP, port); - /* port + 0x02, r & 0x04 */ - legacy_probe_add(0x170, 15, QDI6580DP, port + 2); - } - release_region(port + 2, 2); - } -} - -static __init void probe_qdi_vlb(void) -{ - unsigned long flags; - static const unsigned long qd_port[2] = { 0x30, 0xB0 }; - int i; - - /* - * Check each possible QD65xx base address - */ - - for (i = 0; i < 2; i++) { - unsigned long port = qd_port[i]; - u8 r, res; - - - if (request_region(port, 2, "pata_qdi")) { - /* Check for a card */ - local_irq_save(flags); - /* I have no h/w that needs this delay but it - is present in the historic code */ - r = inb(port); - udelay(1); - outb(0x19, port); - udelay(1); - res = inb(port); - udelay(1); - outb(r, port); - udelay(1); - local_irq_restore(flags); - - /* Fail */ - if (res == 0x19) { - release_region(port, 2); - continue; - } - /* Passes the presence test */ - r = inb(port + 1); - udelay(1); - /* Check port agrees with port set */ - if ((r & 2) >> 1 == i) - qdi65_identify_port(r, res, port); - release_region(port, 2); - } - } -} /** * legacy_init - attach legacy interfaces @@ -1450,17 +867,15 @@ static __init int legacy_init(void) int ct = 0; int primary = 0; int secondary = 0; - int pci_present = 0; - struct legacy_probe *pl = &probe_list[0]; - int slot = 0; + int last_port = NR_HOST; struct pci_dev *p = NULL; for_each_pci_dev(p) { int r; - /* Check for any overlap of the system ATA mappings. Native - mode controllers stuck on these addresses or some devices - in 'raid' mode won't be found by the storage class test */ + /* Check for any overlap of the system ATA mappings. Native mode controllers + stuck on these addresses or some devices in 'raid' mode won't be found by + the storage class test */ for (r = 0; r < 6; r++) { if (pci_resource_start(p, r) == 0x1f0) primary = 1; @@ -1470,39 +885,49 @@ static __init int legacy_init(void) /* Check for special cases */ legacy_check_special_cases(p, &primary, &secondary); - /* If PCI bus is present then don't probe for tertiary - legacy ports */ - pci_present = 1; + /* If PCI bus is present then don't probe for tertiary legacy ports */ + if (probe_all == 0) + last_port = 2; } - if (winbond == 1) - winbond = 0x130; /* Default port, alt is 1B0 */ - - if (primary == 0 || all) - legacy_probe_add(0x1F0, 14, UNKNOWN, 0); - if (secondary == 0 || all) - legacy_probe_add(0x170, 15, UNKNOWN, 0); - - if (probe_all || !pci_present) { - /* ISA/VLB extra ports */ - legacy_probe_add(0x1E8, 11, UNKNOWN, 0); - legacy_probe_add(0x168, 10, UNKNOWN, 0); - legacy_probe_add(0x1E0, 8, UNKNOWN, 0); - legacy_probe_add(0x160, 12, UNKNOWN, 0); + /* If an OPTI 82C46X is present find out where the channels are */ + if (opti82c46x) { + static const char *optis[4] = { + "3/463MV", "5MV", + "5MVA", "5MVB" + }; + u8 chans = 1; + u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6; + + opti82c46x = 3; /* Assume master and slave first */ + printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]); + if (ctrl == 3) + chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1; + ctrl = opti_syscfg(0xAC); + /* Check enabled and this port is the 465MV port. On the + MVB we may have two channels */ + if (ctrl & 8) { + if (ctrl & 4) + opti82c46x = 2; /* Slave */ + else + opti82c46x = 1; /* Master */ + if (chans == 2) + opti82c46x = 3; /* Master and Slave */ + } /* Slave only */ + else if (chans == 1) + opti82c46x = 1; } - if (opti82c46x) - probe_opti_vlb(); - if (qdi) - probe_qdi_vlb(); - - for (i = 0; i < NR_HOST; i++, pl++) { - if (pl->port == 0) + for (i = 0; i < last_port; i++) { + /* Skip primary if we have seen a PCI one */ + if (i == 0 && primary == 1) + continue; + /* Skip secondary if we have seen a PCI one */ + if (i == 1 && secondary == 1) continue; - if (pl->type == UNKNOWN) - pl->type = probe_chip_type(pl); - pl->slot = slot++; - if (legacy_init_one(pl) == 0) + if (legacy_init_one(i, legacy_port[i], + legacy_port[i] + 0x0206, + legacy_irq[i]) == 0) ct++; } if (ct != 0) @@ -1516,8 +941,11 @@ static __exit void legacy_exit(void) for (i = 0; i < nr_legacy_host; i++) { struct legacy_data *ld = &legacy_data[i]; + ata_host_detach(legacy_host[i]); platform_device_unregister(ld->platform_dev); + if (ld->timing) + release_region(ld->timing, 2); } } @@ -1532,9 +960,9 @@ module_param(ht6560a, int, 0); module_param(ht6560b, int, 0); module_param(opti82c611a, int, 0); module_param(opti82c46x, int, 0); -module_param(qdi, int, 0); module_param(pio_mask, int, 0); module_param(iordy_mask, int, 0); module_init(legacy_init); module_exit(legacy_exit); + diff --git a/trunk/drivers/ata/pata_mpc52xx.c b/trunk/drivers/ata/pata_mpc52xx.c index dc401626cdb2..50c56e2814c1 100644 --- a/trunk/drivers/ata/pata_mpc52xx.c +++ b/trunk/drivers/ata/pata_mpc52xx.c @@ -364,7 +364,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) { unsigned int ipb_freq; struct resource res_mem; - int ata_irq; + int ata_irq = NO_IRQ; struct mpc52xx_ata __iomem *ata_regs; struct mpc52xx_ata_priv *priv; int rv; diff --git a/trunk/drivers/ata/pata_ninja32.c b/trunk/drivers/ata/pata_ninja32.c deleted file mode 100644 index 1c1b83541d13..000000000000 --- a/trunk/drivers/ata/pata_ninja32.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * pata_ninja32.c - Ninja32 PATA for new ATA layer - * (C) 2007 Red Hat Inc - * Alan Cox - * - * Note: The controller like many controllers has shared timings for - * PIO and DMA. We thus flip to the DMA timings in dma_start and flip back - * in the dma_stop function. Thus we actually don't need a set_dmamode - * method as the PIO method is always called and will set the right PIO - * timing parameters. - * - * The Ninja32 Cardbus is not a generic SFF controller. Instead it is - * laid out as follows off BAR 0. This is based upon Mark Lord's delkin - * driver and the extensive analysis done by the BSD developers, notably - * ITOH Yasufumi. - * - * Base + 0x00 IRQ Status - * Base + 0x01 IRQ control - * Base + 0x02 Chipset control - * Base + 0x04 VDMA and reset control + wait bits - * Base + 0x08 BMIMBA - * Base + 0x0C DMA Length - * Base + 0x10 Taskfile - * Base + 0x18 BMDMA Status ? - * Base + 0x1C - * Base + 0x1D Bus master control - * bit 0 = enable - * bit 1 = 0 write/1 read - * bit 2 = 1 sgtable - * bit 3 = go - * bit 4-6 wait bits - * bit 7 = done - * Base + 0x1E AltStatus - * Base + 0x1F timing register - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "pata_ninja32" -#define DRV_VERSION "0.0.1" - - -/** - * ninja32_set_piomode - set initial PIO mode data - * @ap: ATA interface - * @adev: ATA device - * - * Called to do the PIO mode setup. Our timing registers are shared - * but we want to set the PIO timing by default. - */ - -static void ninja32_set_piomode(struct ata_port *ap, struct ata_device *adev) -{ - static u16 pio_timing[5] = { - 0xd6, 0x85, 0x44, 0x33, 0x13 - }; - iowrite8(pio_timing[adev->pio_mode - XFER_PIO_0], - ap->ioaddr.bmdma_addr + 0x1f); - ap->private_data = adev; -} - - -static void ninja32_dev_select(struct ata_port *ap, unsigned int device) -{ - struct ata_device *adev = &ap->link.device[device]; - if (ap->private_data != adev) { - iowrite8(0xd6, ap->ioaddr.bmdma_addr + 0x1f); - ata_std_dev_select(ap, device); - ninja32_set_piomode(ap, adev); - } -} - -static struct scsi_host_template ninja32_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .ioctl = ata_scsi_ioctl, - .queuecommand = ata_scsi_queuecmd, - .can_queue = ATA_DEF_QUEUE, - .this_id = ATA_SHT_THIS_ID, - .sg_tablesize = LIBATA_MAX_PRD, - .cmd_per_lun = ATA_SHT_CMD_PER_LUN, - .emulated = ATA_SHT_EMULATED, - .use_clustering = ATA_SHT_USE_CLUSTERING, - .proc_name = DRV_NAME, - .dma_boundary = ATA_DMA_BOUNDARY, - .slave_configure = ata_scsi_slave_config, - .slave_destroy = ata_scsi_slave_destroy, - .bios_param = ata_std_bios_param, -}; - -static struct ata_port_operations ninja32_port_ops = { - .set_piomode = ninja32_set_piomode, - .mode_filter = ata_pci_default_filter, - - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ninja32_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .bmdma_setup = ata_bmdma_setup, - .bmdma_start = ata_bmdma_start, - .bmdma_stop = ata_bmdma_stop, - .bmdma_status = ata_bmdma_status, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer, - - .irq_handler = ata_interrupt, - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - -static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct ata_host *host; - struct ata_port *ap; - void __iomem *base; - int rc; - - host = ata_host_alloc(&dev->dev, 1); - if (!host) - return -ENOMEM; - ap = host->ports[0]; - - /* Set up the PCI device */ - rc = pcim_enable_device(dev); - if (rc) - return rc; - rc = pcim_iomap_regions(dev, 1 << 0, DRV_NAME); - if (rc == -EBUSY) - pcim_pin_device(dev); - if (rc) - return rc; - - host->iomap = pcim_iomap_table(dev); - rc = pci_set_dma_mask(dev, ATA_DMA_MASK); - if (rc) - return rc; - rc = pci_set_consistent_dma_mask(dev, ATA_DMA_MASK); - if (rc) - return rc; - pci_set_master(dev); - - /* Set up the register mappings */ - base = host->iomap[0]; - if (!base) - return -ENOMEM; - ap->ops = &ninja32_port_ops; - ap->pio_mask = 0x1F; - ap->flags |= ATA_FLAG_SLAVE_POSS; - - ap->ioaddr.cmd_addr = base + 0x10; - ap->ioaddr.ctl_addr = base + 0x1E; - ap->ioaddr.altstatus_addr = base + 0x1E; - ap->ioaddr.bmdma_addr = base; - ata_std_ports(&ap->ioaddr); - - iowrite8(0x05, base + 0x01); /* Enable interrupt lines */ - iowrite8(0xB3, base + 0x02); /* Burst, ?? setup */ - iowrite8(0x00, base + 0x04); /* WAIT0 ? */ - /* FIXME: Should we disable them at remove ? */ - return ata_host_activate(host, dev->irq, ata_interrupt, - IRQF_SHARED, &ninja32_sht); -} - -static const struct pci_device_id ninja32[] = { - { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { }, -}; - -static struct pci_driver ninja32_pci_driver = { - .name = DRV_NAME, - .id_table = ninja32, - .probe = ninja32_init_one, - .remove = ata_pci_remove_one -}; - -static int __init ninja32_init(void) -{ - return pci_register_driver(&ninja32_pci_driver); -} - -static void __exit ninja32_exit(void) -{ - pci_unregister_driver(&ninja32_pci_driver); -} - -MODULE_AUTHOR("Alan Cox"); -MODULE_DESCRIPTION("low-level driver for Ninja32 ATA"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, ninja32); -MODULE_VERSION(DRV_VERSION); - -module_init(ninja32_init); -module_exit(ninja32_exit); diff --git a/trunk/drivers/ata/pata_pcmcia.c b/trunk/drivers/ata/pata_pcmcia.c index 3e7f6a9da28b..fd36099428a4 100644 --- a/trunk/drivers/ata/pata_pcmcia.c +++ b/trunk/drivers/ata/pata_pcmcia.c @@ -42,7 +42,7 @@ #define DRV_NAME "pata_pcmcia" -#define DRV_VERSION "0.3.3" +#define DRV_VERSION "0.3.2" /* * Private data structure to glue stuff together @@ -86,47 +86,6 @@ static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_d return ata_do_set_mode(link, r_failed_dev); } -/** - * pcmcia_set_mode_8bit - PCMCIA specific mode setup - * @link: link - * @r_failed_dev: Return pointer for failed device - * - * For the simple emulated 8bit stuff the less we do the better. - */ - -static int pcmcia_set_mode_8bit(struct ata_link *link, - struct ata_device **r_failed_dev) -{ - return 0; -} - -/** - * ata_data_xfer_8bit - Transfer data by 8bit PIO - * @dev: device to target - * @buf: data buffer - * @buflen: buffer length - * @rw: read/write - * - * Transfer data from/to the device data register by 8 bit PIO. - * - * LOCKING: - * Inherited from caller. - */ - -static unsigned int ata_data_xfer_8bit(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw) -{ - struct ata_port *ap = dev->link->ap; - - if (rw == READ) - ioread8_rep(ap->ioaddr.data_addr, buf, buflen); - else - iowrite8_rep(ap->ioaddr.data_addr, buf, buflen); - - return buflen; -} - - static struct scsi_host_template pcmcia_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -170,31 +129,6 @@ static struct ata_port_operations pcmcia_port_ops = { .port_start = ata_sff_port_start, }; -static struct ata_port_operations pcmcia_8bit_port_ops = { - .set_mode = pcmcia_set_mode_8bit, - .tf_load = ata_tf_load, - .tf_read = ata_tf_read, - .check_status = ata_check_status, - .exec_command = ata_exec_command, - .dev_select = ata_std_dev_select, - - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, - .error_handler = ata_bmdma_error_handler, - .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_40wire, - - .qc_prep = ata_qc_prep, - .qc_issue = ata_qc_issue_prot, - - .data_xfer = ata_data_xfer_8bit, - - .irq_clear = ata_bmdma_irq_clear, - .irq_on = ata_irq_on, - - .port_start = ata_sff_port_start, -}; - #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) @@ -219,12 +153,9 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) cistpl_cftable_entry_t dflt; } *stk = NULL; cistpl_cftable_entry_t *cfg; - int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p; + int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM; unsigned long io_base, ctl_base; void __iomem *io_addr, *ctl_addr; - int n_ports = 1; - - struct ata_port_operations *ops = &pcmcia_port_ops; info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) @@ -351,32 +282,27 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) /* FIXME: Could be more ports at base + 0x10 but we only deal with one right now */ if (pdev->io.NumPorts1 >= 0x20) - n_ports = 2; + printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n"); - if (pdev->manf_id == 0x0097 && pdev->card_id == 0x1620) - ops = &pcmcia_8bit_port_ops; /* * Having done the PCMCIA plumbing the ATA side is relatively * sane. */ ret = -ENOMEM; - host = ata_host_alloc(&pdev->dev, n_ports); + host = ata_host_alloc(&pdev->dev, 1); if (!host) goto failed; + ap = host->ports[0]; - for (p = 0; p < n_ports; p++) { - ap = host->ports[p]; + ap->ops = &pcmcia_port_ops; + ap->pio_mask = 1; /* ISA so PIO 0 cycles */ + ap->flags |= ATA_FLAG_SLAVE_POSS; + ap->ioaddr.cmd_addr = io_addr; + ap->ioaddr.altstatus_addr = ctl_addr; + ap->ioaddr.ctl_addr = ctl_addr; + ata_std_ports(&ap->ioaddr); - ap->ops = ops; - ap->pio_mask = 1; /* ISA so PIO 0 cycles */ - ap->flags |= ATA_FLAG_SLAVE_POSS; - ap->ioaddr.cmd_addr = io_addr + 0x10 * p; - ap->ioaddr.altstatus_addr = ctl_addr + 0x10 * p; - ap->ioaddr.ctl_addr = ctl_addr + 0x10 * p; - ata_std_ports(&ap->ioaddr); - - ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); - } + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); /* activate */ ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt, @@ -434,7 +360,6 @@ static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904), PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */ - PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ diff --git a/trunk/drivers/ata/pata_pdc2027x.c b/trunk/drivers/ata/pata_pdc2027x.c index 028af5dbeed6..2622577521a1 100644 --- a/trunk/drivers/ata/pata_pdc2027x.c +++ b/trunk/drivers/ata/pata_pdc2027x.c @@ -348,7 +348,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long ata_id_c_string(pair->id, model_num, ATA_ID_PROD, ATA_ID_PROD_LEN + 1); /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */ - if (strstr(model_num, "Maxtor") == NULL && pair->dma_mode == XFER_UDMA_6) + if (strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6) mask &= ~ (1 << (6 + ATA_SHIFT_UDMA)); return ata_pci_default_filter(adev, mask); diff --git a/trunk/drivers/ata/pata_pdc202xx_old.c b/trunk/drivers/ata/pata_pdc202xx_old.c index 3ed866723e0c..6c9689b59b06 100644 --- a/trunk/drivers/ata/pata_pdc202xx_old.c +++ b/trunk/drivers/ata/pata_pdc202xx_old.c @@ -168,7 +168,8 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) pdc202xx_set_dmamode(ap, qc->dev); /* Cases the state machine will not complete correctly without help */ - if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATAPI_PROT_DMA) { + if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA) + { len = qc->nbytes / 2; if (tf->flags & ATA_TFLAG_WRITE) @@ -207,7 +208,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no); /* Cases the state machine will not complete correctly */ - if (tf->protocol == ATAPI_PROT_DMA || (tf->flags & ATA_TFLAG_LBA48)) { + if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) { iowrite32(0, atapi_reg); iowrite8(ioread8(clock) & ~sel66, clock); } diff --git a/trunk/drivers/ata/pata_qdi.c b/trunk/drivers/ata/pata_qdi.c index 9f308ed76cc8..a4c0e502cb42 100644 --- a/trunk/drivers/ata/pata_qdi.c +++ b/trunk/drivers/ata/pata_qdi.c @@ -124,33 +124,29 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } -static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) +static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - if (ata_id_has_dword_io(dev->id)) { - struct ata_port *ap = dev->link->ap; - int slop = buflen & 3; + struct ata_port *ap = adev->link->ap; + int slop = buflen & 3; - if (rw == READ) - ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else + if (ata_id_has_dword_io(adev->id)) { + if (write_data) iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); + else + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { - u32 pad; - if (rw == READ) { - pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); - memcpy(buf + buflen - slop, &pad, slop); - } else { + __le32 pad = 0; + if (write_data) { memcpy(&pad, buf + buflen - slop, slop); iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); + } else { + pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); } - buflen += 4 - slop; } } else - buflen = ata_data_xfer(dev, buf, buflen, rw); - - return buflen; + ata_data_xfer(adev, buf, buflen, write_data); } static struct scsi_host_template qdi_sht = { diff --git a/trunk/drivers/ata/pata_scc.c b/trunk/drivers/ata/pata_scc.c index 55055b27524c..ea2ef9fc15be 100644 --- a/trunk/drivers/ata/pata_scc.c +++ b/trunk/drivers/ata/pata_scc.c @@ -768,47 +768,45 @@ static u8 scc_bmdma_status (struct ata_port *ap) /** * scc_data_xfer - Transfer data by PIO - * @dev: device for this I/O + * @adev: device for this I/O * @buf: data buffer * @buflen: buffer length - * @rw: read/write + * @write_data: read/write * * Note: Original code is ata_data_xfer(). */ -static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw) +static void scc_data_xfer (struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = adev->link->ap; unsigned int words = buflen >> 1; unsigned int i; u16 *buf16 = (u16 *) buf; void __iomem *mmio = ap->ioaddr.data_addr; /* Transfer multiple of 2 bytes */ - if (rw == READ) - for (i = 0; i < words; i++) - buf16[i] = le16_to_cpu(in_be32(mmio)); - else + if (write_data) { for (i = 0; i < words; i++) out_be32(mmio, cpu_to_le16(buf16[i])); + } else { + for (i = 0; i < words; i++) + buf16[i] = le16_to_cpu(in_be32(mmio)); + } /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { u16 align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (rw == READ) { - align_buf[0] = le16_to_cpu(in_be32(mmio)); - memcpy(trailing_buf, align_buf, 1); - } else { + if (write_data) { memcpy(align_buf, trailing_buf, 1); out_be32(mmio, cpu_to_le16(align_buf[0])); + } else { + align_buf[0] = le16_to_cpu(in_be32(mmio)); + memcpy(trailing_buf, align_buf, 1); } - words++; } - - return words << 1; } /** diff --git a/trunk/drivers/ata/pata_serverworks.c b/trunk/drivers/ata/pata_serverworks.c index 9c523fbf529e..8bed88873720 100644 --- a/trunk/drivers/ata/pata_serverworks.c +++ b/trunk/drivers/ata/pata_serverworks.c @@ -41,7 +41,7 @@ #include #define DRV_NAME "pata_serverworks" -#define DRV_VERSION "0.4.3" +#define DRV_VERSION "0.4.2" #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ @@ -102,7 +102,7 @@ static int osb4_cable(struct ata_port *ap) { } /** - * csb_cable - CSB5/6 cable detect + * csb4_cable - CSB5/6 cable detect * @ap: ATA port to check * * Serverworks default arrangement is to use the drive side detection @@ -110,7 +110,7 @@ static int osb4_cable(struct ata_port *ap) { */ static int csb_cable(struct ata_port *ap) { - return ATA_CBL_PATA_UNK; + return ATA_CBL_PATA80; } struct sv_cable_table { @@ -231,6 +231,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo return ata_pci_default_filter(adev, mask); } + /** * serverworks_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -242,7 +243,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev) { static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; - int offset = 1 + 2 * ap->port_no - adev->devno; + int offset = 1 + (2 * ap->port_no) - adev->devno; int devbits = (2 * ap->port_no + adev->devno) * 4; u16 csb5_pio; struct pci_dev *pdev = to_pci_dev(ap->host->dev); diff --git a/trunk/drivers/ata/pata_via.c b/trunk/drivers/ata/pata_via.c index 39627ab684bf..453d72bf2598 100644 --- a/trunk/drivers/ata/pata_via.c +++ b/trunk/drivers/ata/pata_via.c @@ -185,8 +185,7 @@ static int via_cable_detect(struct ata_port *ap) { if (ata66 & (0x10100000 >> (16 * ap->port_no))) return ATA_CBL_PATA80; /* Check with ACPI so we can spot BIOS reported SATA bridges */ - if (ata_acpi_init_gtm(ap) && - ata_acpi_cbl_80wire(ap, ata_acpi_init_gtm(ap))) + if (ata_acpi_cbl_80wire(ap)) return ATA_CBL_PATA80; return ATA_CBL_PATA40; } diff --git a/trunk/drivers/ata/pata_winbond.c b/trunk/drivers/ata/pata_winbond.c index 99c92eda217b..7116a9e7a8b2 100644 --- a/trunk/drivers/ata/pata_winbond.c +++ b/trunk/drivers/ata/pata_winbond.c @@ -92,33 +92,29 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) } -static unsigned int winbond_data_xfer(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw) +static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { - struct ata_port *ap = dev->link->ap; + struct ata_port *ap = adev->link->ap; int slop = buflen & 3; - if (ata_id_has_dword_io(dev->id)) { - if (rw == READ) - ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else + if (ata_id_has_dword_io(adev->id)) { + if (write_data) iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); + else + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { - u32 pad; - if (rw == READ) { - pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); - memcpy(buf + buflen - slop, &pad, slop); - } else { + __le32 pad = 0; + if (write_data) { memcpy(&pad, buf + buflen - slop, slop); iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); + } else { + pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); } - buflen += 4 - slop; } } else - buflen = ata_data_xfer(dev, buf, buflen, rw); - - return buflen; + ata_data_xfer(adev, buf, buflen, write_data); } static struct scsi_host_template winbond_sht = { @@ -195,7 +191,7 @@ static __init int winbond_init_one(unsigned long port) reg = winbond_readcfg(port, 0x81); if (!(reg & 0x03)) /* Disabled */ - return -ENODEV; + return 0; for (i = 0; i < 2 ; i ++) { unsigned long cmd_port = 0x1F0 - (0x80 * i); diff --git a/trunk/drivers/ata/pdc_adma.c b/trunk/drivers/ata/pdc_adma.c index 8e1b7e9c0ae4..bd4c2a3c88d7 100644 --- a/trunk/drivers/ata/pdc_adma.c +++ b/trunk/drivers/ata/pdc_adma.c @@ -321,9 +321,8 @@ static int adma_fill_sg(struct ata_queued_cmd *qc) u8 *buf = pp->pkt, *last_buf = NULL; int i = (2 + buf[3]) * 8; u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0); - unsigned int si; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { u32 addr; u32 len; @@ -456,7 +455,7 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc) adma_packet_start(qc); return 0; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: BUG(); break; diff --git a/trunk/drivers/ata/sata_fsl.c b/trunk/drivers/ata/sata_fsl.c index 922d7b2efba8..d015b4adcfe0 100644 --- a/trunk/drivers/ata/sata_fsl.c +++ b/trunk/drivers/ata/sata_fsl.c @@ -333,14 +333,13 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc, struct prde *prd_ptr_to_indirect_ext = NULL; unsigned indirect_ext_segment_sz = 0; dma_addr_t indirect_ext_segment_paddr; - unsigned int si; VPRINTK("SATA FSL : cd = 0x%x, prd = 0x%x\n", cmd_desc, prd); indirect_ext_segment_paddr = cmd_desc_paddr + SATA_FSL_CMD_DESC_OFFSET_TO_PRDT + SATA_FSL_MAX_PRD_DIRECT * 16; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { dma_addr_t sg_addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); @@ -418,7 +417,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc) } /* setup "ACMD - atapi command" in cmd. desc. if this is ATAPI cmd */ - if (ata_is_atapi(qc->tf.protocol)) { + if (is_atapi_taskfile(&qc->tf)) { desc_info |= ATAPI_CMD; memset((void *)&cd->acmd, 0, 32); memcpy((void *)&cd->acmd, qc->cdb, qc->dev->cdb_len); diff --git a/trunk/drivers/ata/sata_inic162x.c b/trunk/drivers/ata/sata_inic162x.c index 96e614a1c169..323c087e8cc1 100644 --- a/trunk/drivers/ata/sata_inic162x.c +++ b/trunk/drivers/ata/sata_inic162x.c @@ -585,7 +585,7 @@ static struct ata_port_operations inic_port_ops = { }; static struct ata_port_info inic_port_info = { - /* For some reason, ATAPI_PROT_PIO is broken on this + /* For some reason, ATA_PROT_ATAPI is broken on this * controller, and no, PIO_POLLING does't fix it. It somehow * manages to report the wrong ireason and ignoring ireason * results in machine lock up. Tell libata to always prefer diff --git a/trunk/drivers/ata/sata_mv.c b/trunk/drivers/ata/sata_mv.c index 7e72463a90eb..37b850ae0845 100644 --- a/trunk/drivers/ata/sata_mv.c +++ b/trunk/drivers/ata/sata_mv.c @@ -1136,10 +1136,9 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) struct mv_port_priv *pp = qc->ap->private_data; struct scatterlist *sg; struct mv_sg *mv_sg, *last_sg = NULL; - unsigned int si; mv_sg = pp->sg_tbl; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { dma_addr_t addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); diff --git a/trunk/drivers/ata/sata_nv.c b/trunk/drivers/ata/sata_nv.c index a0f98fdab7a0..ed5dc7cb50cd 100644 --- a/trunk/drivers/ata/sata_nv.c +++ b/trunk/drivers/ata/sata_nv.c @@ -1336,18 +1336,21 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) { struct nv_adma_port_priv *pp = qc->ap->private_data; + unsigned int idx; struct nv_adma_prd *aprd; struct scatterlist *sg; - unsigned int si; VPRINTK("ENTER\n"); - for_each_sg(qc->sg, sg, qc->n_elem, si) { - aprd = (si < 5) ? &cpb->aprd[si] : - &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (si-5)]; - nv_adma_fill_aprd(qc, sg, si, aprd); + idx = 0; + + ata_for_each_sg(sg, qc) { + aprd = (idx < 5) ? &cpb->aprd[idx] : + &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)]; + nv_adma_fill_aprd(qc, sg, idx, aprd); + idx++; } - if (si > 5) + if (idx > 5) cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); else cpb->next_aprd = cpu_to_le64(0); @@ -1992,14 +1995,17 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; + unsigned int idx; struct nv_swncq_port_priv *pp = ap->private_data; struct ata_prd *prd; - unsigned int si, idx; + + WARN_ON(qc->__sg == NULL); + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); prd = pp->prd + ATA_MAX_PRD * qc->tag; idx = 0; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { u32 addr, offset; u32 sg_len, len; @@ -2021,7 +2027,8 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc) } } - prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + if (idx) + prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap, diff --git a/trunk/drivers/ata/sata_promise.c b/trunk/drivers/ata/sata_promise.c index a07d319f6e8c..7914def54fa3 100644 --- a/trunk/drivers/ata/sata_promise.c +++ b/trunk/drivers/ata/sata_promise.c @@ -450,19 +450,19 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) struct pdc_port_priv *pp = ap->private_data; u8 *buf = pp->pkt; u32 *buf32 = (u32 *) buf; - unsigned int dev_sel, feature; + unsigned int dev_sel, feature, nbytes; /* set control bits (byte 0), zero delay seq id (byte 3), * and seq id (byte 2) */ switch (qc->tf.protocol) { - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: if (!(qc->tf.flags & ATA_TFLAG_WRITE)) buf32[0] = cpu_to_le32(PDC_PKT_READ); else buf32[0] = 0; break; - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI_NODATA: buf32[0] = cpu_to_le32(PDC_PKT_NODATA); break; default: @@ -473,37 +473,45 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) buf32[2] = 0; /* no next-packet */ /* select drive */ - if (sata_scr_valid(&ap->link)) + if (sata_scr_valid(&ap->link)) { dev_sel = PDC_DEVICE_SATA; - else - dev_sel = qc->tf.device; - + } else { + dev_sel = ATA_DEVICE_OBS; + if (qc->dev->devno != 0) + dev_sel |= ATA_DEV1; + } buf[12] = (1 << 5) | ATA_REG_DEVICE; buf[13] = dev_sel; buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY; buf[15] = dev_sel; /* once more, waiting for BSY to clear */ buf[16] = (1 << 5) | ATA_REG_NSECT; - buf[17] = qc->tf.nsect; + buf[17] = 0x00; buf[18] = (1 << 5) | ATA_REG_LBAL; - buf[19] = qc->tf.lbal; + buf[19] = 0x00; /* set feature and byte counter registers */ - if (qc->tf.protocol != ATAPI_PROT_DMA) + if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) { feature = PDC_FEATURE_ATAPI_PIO; - else + /* set byte counter register to real transfer byte count */ + nbytes = qc->nbytes; + if (nbytes > 0xffff) + nbytes = 0xffff; + } else { feature = PDC_FEATURE_ATAPI_DMA; - + /* set byte counter register to 0 */ + nbytes = 0; + } buf[20] = (1 << 5) | ATA_REG_FEATURE; buf[21] = feature; buf[22] = (1 << 5) | ATA_REG_BYTEL; - buf[23] = qc->tf.lbam; + buf[23] = nbytes & 0xFF; buf[24] = (1 << 5) | ATA_REG_BYTEH; - buf[25] = qc->tf.lbah; + buf[25] = (nbytes >> 8) & 0xFF; /* send ATAPI packet command 0xA0 */ buf[26] = (1 << 5) | ATA_REG_CMD; - buf[27] = qc->tf.command; + buf[27] = ATA_CMD_PACKET; /* select drive and check DRQ */ buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY; @@ -533,15 +541,17 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; + unsigned int idx; const u32 SG_COUNT_ASIC_BUG = 41*4; - unsigned int si, idx; - u32 len; if (!(qc->flags & ATA_QCFLAG_DMAMAP)) return; + WARN_ON(qc->__sg == NULL); + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); + idx = 0; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { u32 addr, offset; u32 sg_len, len; @@ -568,27 +578,29 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc) } } - len = le32_to_cpu(ap->prd[idx - 1].flags_len); + if (idx) { + u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len); - if (len > SG_COUNT_ASIC_BUG) { - u32 addr; + if (len > SG_COUNT_ASIC_BUG) { + u32 addr; - VPRINTK("Splitting last PRD.\n"); + VPRINTK("Splitting last PRD.\n"); - addr = le32_to_cpu(ap->prd[idx - 1].addr); - ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG); + addr = le32_to_cpu(ap->prd[idx - 1].addr); + ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG); - addr = addr + len - SG_COUNT_ASIC_BUG; - len = SG_COUNT_ASIC_BUG; - ap->prd[idx].addr = cpu_to_le32(addr); - ap->prd[idx].flags_len = cpu_to_le32(len); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); + addr = addr + len - SG_COUNT_ASIC_BUG; + len = SG_COUNT_ASIC_BUG; + ap->prd[idx].addr = cpu_to_le32(addr); + ap->prd[idx].flags_len = cpu_to_le32(len); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); - idx++; - } + idx++; + } - ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + } } static void pdc_qc_prep(struct ata_queued_cmd *qc) @@ -615,14 +627,14 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) pdc_pkt_footer(&qc->tf, pp->pkt, i); break; - case ATAPI_PROT_PIO: + case ATA_PROT_ATAPI: pdc_fill_sg(qc); break; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: pdc_fill_sg(qc); /*FALLTHROUGH*/ - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI_NODATA: pdc_atapi_pkt(qc); break; @@ -742,8 +754,8 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap, switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: - case ATAPI_PROT_DMA: - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI_DMA: + case ATA_PROT_ATAPI_NODATA: qc->err_mask |= ac_err_mask(ata_wait_idle(ap)); ata_qc_complete(qc); handled = 1; @@ -888,7 +900,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) { switch (qc->tf.protocol) { - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI_NODATA: if (qc->dev->flags & ATA_DFLAG_CDB_INTR) break; /*FALLTHROUGH*/ @@ -896,7 +908,7 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_POLLING) break; /*FALLTHROUGH*/ - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: case ATA_PROT_DMA: pdc_packet_start(qc); return 0; @@ -910,14 +922,16 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { - WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA); + WARN_ON(tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_ATAPI_DMA); ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { - WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA); + WARN_ON(tf->protocol == ATA_PROT_DMA || + tf->protocol == ATA_PROT_ATAPI_DMA); ata_exec_command(ap, tf); } diff --git a/trunk/drivers/ata/sata_promise.h b/trunk/drivers/ata/sata_promise.h index 00d6000e546f..6ee5e190262d 100644 --- a/trunk/drivers/ata/sata_promise.h +++ b/trunk/drivers/ata/sata_promise.h @@ -46,7 +46,7 @@ static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf, unsigned int devno, u8 *buf) { u8 dev_reg; - __le32 *buf32 = (__le32 *) buf; + u32 *buf32 = (u32 *) buf; /* set control bits (byte 0), zero delay seq id (byte 3), * and seq id (byte 2) diff --git a/trunk/drivers/ata/sata_qstor.c b/trunk/drivers/ata/sata_qstor.c index 91cc12c82040..c68b241805fd 100644 --- a/trunk/drivers/ata/sata_qstor.c +++ b/trunk/drivers/ata/sata_qstor.c @@ -287,10 +287,14 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) struct scatterlist *sg; struct ata_port *ap = qc->ap; struct qs_port_priv *pp = ap->private_data; + unsigned int nelem; u8 *prd = pp->pkt + QS_CPB_BYTES; - unsigned int si; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + WARN_ON(qc->__sg == NULL); + WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); + + nelem = 0; + ata_for_each_sg(sg, qc) { u64 addr; u32 len; @@ -302,11 +306,12 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) *(__le32 *)prd = cpu_to_le32(len); prd += sizeof(u64); - VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", si, + VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem, (unsigned long long)addr, len); + nelem++; } - return si; + return nelem; } static void qs_qc_prep(struct ata_queued_cmd *qc) @@ -371,7 +376,7 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) qs_packet_start(qc); return 0; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: BUG(); break; diff --git a/trunk/drivers/ata/sata_sil.c b/trunk/drivers/ata/sata_sil.c index 0b8191b52f97..f5119bf40c24 100644 --- a/trunk/drivers/ata/sata_sil.c +++ b/trunk/drivers/ata/sata_sil.c @@ -416,14 +416,15 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) */ /* Check the ATA_DFLAG_CDB_INTR flag is enough here. - * The flag was turned on only for atapi devices. No - * need to check ata_is_atapi(qc->tf.protocol) again. + * The flag was turned on only for atapi devices. + * No need to check is_atapi_taskfile(&qc->tf) again. */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) goto err_hsm; break; case HSM_ST_LAST: - if (ata_is_dma(qc->tf.protocol)) { + if (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA) { /* clear DMA-Start bit */ ap->ops->bmdma_stop(qc); @@ -450,7 +451,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) /* kick HSM in the ass */ ata_hsm_move(ap, qc, status, 0); - if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol)) + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2); return; diff --git a/trunk/drivers/ata/sata_sil24.c b/trunk/drivers/ata/sata_sil24.c index b4b1f91ea693..864c1c1b8511 100644 --- a/trunk/drivers/ata/sata_sil24.c +++ b/trunk/drivers/ata/sata_sil24.c @@ -813,9 +813,8 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, { struct scatterlist *sg; struct sil24_sge *last_sge = NULL; - unsigned int si; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { sge->addr = cpu_to_le64(sg_dma_address(sg)); sge->cnt = cpu_to_le32(sg_dma_len(sg)); sge->flags = 0; @@ -824,7 +823,8 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, sge++; } - last_sge->flags = cpu_to_le32(SGE_TRM); + if (likely(last_sge)) + last_sge->flags = cpu_to_le32(SGE_TRM); } static int sil24_qc_defer(struct ata_queued_cmd *qc) @@ -852,7 +852,9 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc) * set. * */ - int is_excl = (ata_is_atapi(prot) || + int is_excl = (prot == ATA_PROT_ATAPI || + prot == ATA_PROT_ATAPI_NODATA || + prot == ATA_PROT_ATAPI_DMA || (qc->flags & ATA_QCFLAG_RESULT_TF)); if (unlikely(ap->excl_link)) { @@ -883,21 +885,35 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) cb = &pp->cmd_block[sil24_tag(qc->tag)]; - if (!ata_is_atapi(qc->tf.protocol)) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_DMA: + case ATA_PROT_NCQ: + case ATA_PROT_NODATA: prb = &cb->ata.prb; sge = cb->ata.sge; - } else { + break; + + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_DMA: + case ATA_PROT_ATAPI_NODATA: prb = &cb->atapi.prb; sge = cb->atapi.sge; memset(cb->atapi.cdb, 0, 32); memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len); - if (ata_is_data(qc->tf.protocol)) { + if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) { if (qc->tf.flags & ATA_TFLAG_WRITE) ctrl = PRB_CTRL_PACKET_WRITE; else ctrl = PRB_CTRL_PACKET_READ; } + break; + + default: + prb = NULL; /* shut up, gcc */ + sge = NULL; + BUG(); } prb->ctrl = cpu_to_le16(ctrl); diff --git a/trunk/drivers/ata/sata_sx4.c b/trunk/drivers/ata/sata_sx4.c index e3d56bc6726d..4d857185f33b 100644 --- a/trunk/drivers/ata/sata_sx4.c +++ b/trunk/drivers/ata/sata_sx4.c @@ -334,7 +334,7 @@ static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf, { u32 addr; unsigned int dw = PDC_DIMM_APKT_PRD >> 2; - __le32 *buf32 = (__le32 *) buf; + u32 *buf32 = (u32 *) buf; /* output ATA packet S/G table */ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA + @@ -356,7 +356,7 @@ static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf, { u32 addr; unsigned int dw = PDC_DIMM_HPKT_PRD >> 2; - __le32 *buf32 = (__le32 *) buf; + u32 *buf32 = (u32 *) buf; /* output Host DMA packet S/G table */ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA + @@ -377,7 +377,7 @@ static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf, unsigned int portno) { unsigned int i, dw; - __le32 *buf32 = (__le32 *) buf; + u32 *buf32 = (u32 *) buf; u8 dev_reg; unsigned int dimm_sg = PDC_20621_DIMM_BASE + @@ -429,8 +429,7 @@ static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf, unsigned int portno) { unsigned int dw; - u32 tmp; - __le32 *buf32 = (__le32 *) buf; + u32 tmp, *buf32 = (u32 *) buf; unsigned int host_sg = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) + @@ -474,7 +473,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc) void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; unsigned int portno = ap->port_no; - unsigned int i, si, idx, total_len = 0, sgt_len; + unsigned int i, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP)); @@ -488,7 +487,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc) * Build S/G table */ idx = 0; - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { buf[idx++] = cpu_to_le32(sg_dma_address(sg)); buf[idx++] = cpu_to_le32(sg_dma_len(sg)); total_len += sg_dma_len(sg); @@ -701,7 +700,7 @@ static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) pdc20621_packet_start(qc); return 0; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: BUG(); break; diff --git a/trunk/drivers/crypto/Kconfig b/trunk/drivers/crypto/Kconfig index 74bd599dfb0c..8a70a9edabda 100644 --- a/trunk/drivers/crypto/Kconfig +++ b/trunk/drivers/crypto/Kconfig @@ -88,10 +88,16 @@ config CRYPTO_DEV_HIFN_795X select CRYPTO_DES select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER + select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG depends on PCI help This option allows you to have support for HIFN 795x crypto adapters. - +config CRYPTO_DEV_HIFN_795X_RNG + bool "HIFN 795x random number generator" + depends on CRYPTO_DEV_HIFN_795X + help + Select this option if you want to enable the random number generator + on the HIFN 795x crypto adapters. endif # CRYPTO_HW diff --git a/trunk/drivers/crypto/hifn_795x.c b/trunk/drivers/crypto/hifn_795x.c index 16413e57597c..dfbf24c4033c 100644 --- a/trunk/drivers/crypto/hifn_795x.c +++ b/trunk/drivers/crypto/hifn_795x.c @@ -463,7 +463,7 @@ struct hifn_device unsigned int pk_clk_freq; -#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) +#ifdef CRYPTO_DEV_HIFN_795X_RNG unsigned int rng_wait_time; ktime_t rngtime; struct hwrng rng; @@ -795,7 +795,7 @@ static struct pci2id { } }; -#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) +#ifdef CRYPTO_DEV_HIFN_795X_RNG static int hifn_rng_data_present(struct hwrng *rng, int wait) { struct hifn_device *dev = (struct hifn_device *)rng->priv; @@ -880,7 +880,7 @@ static int hifn_init_pubrng(struct hifn_device *dev) dprintk("Chip %s: RNG engine has been successfully initialised.\n", dev->name); -#if defined(CONFIG_HW_RANDOM) || defined(CONFIG_HW_RANDOM_MODULE) +#ifdef CRYPTO_DEV_HIFN_795X_RNG /* First value must be discarded */ hifn_read_1(dev, HIFN_1_RNG_DATA); dev->rngtime = ktime_get(); diff --git a/trunk/drivers/ide/Kconfig b/trunk/drivers/ide/Kconfig index ee01e273a537..fb06555708a8 100644 --- a/trunk/drivers/ide/Kconfig +++ b/trunk/drivers/ide/Kconfig @@ -374,6 +374,17 @@ comment "PCI IDE chipsets support" config BLK_DEV_IDEPCI bool +config IDEPCI_SHARE_IRQ + bool "Sharing PCI IDE interrupts support" + depends on BLK_DEV_IDEPCI + help + Some ATA/IDE chipsets have hardware support which allows for + sharing a single IRQ with other cards. To enable support for + this in the ATA/IDE driver, say Y here. + + It is safe to say Y to this question, in most cases. + If unsure, say N. + config IDEPCI_PCIBUS_ORDER def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI @@ -696,6 +707,7 @@ config BLK_DEV_SVWKS config BLK_DEV_SGIIOC4 tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 + select IDEPCI_SHARE_IRQ select BLK_DEV_IDEDMA_PCI help This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 diff --git a/trunk/drivers/ide/arm/icside.c b/trunk/drivers/ide/arm/icside.c index 673402f4a295..93f71fcfc04d 100644 --- a/trunk/drivers/ide/arm/icside.c +++ b/trunk/drivers/ide/arm/icside.c @@ -272,6 +272,8 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) case XFER_SW_DMA_0: cycle_time = 480; break; + default: + return; } /* diff --git a/trunk/drivers/ide/cris/ide-cris.c b/trunk/drivers/ide/cris/ide-cris.c index 325e608d9e62..476e0d65ed43 100644 --- a/trunk/drivers/ide/cris/ide-cris.c +++ b/trunk/drivers/ide/cris/ide-cris.c @@ -747,6 +747,8 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed) strobe = ATA_DMA2_STROBE; hold = ATA_DMA2_HOLD; break; + default: + return; } if (speed >= XFER_UDMA_0) diff --git a/trunk/drivers/ide/ide-acpi.c b/trunk/drivers/ide/ide-acpi.c index e0bb0cfa7bdd..899d56536e80 100644 --- a/trunk/drivers/ide/ide-acpi.c +++ b/trunk/drivers/ide/ide-acpi.c @@ -383,19 +383,27 @@ static int taskfile_load_raw(ide_drive_t *drive, gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); memset(&args, 0, sizeof(ide_task_t)); + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.data_phase = TASKFILE_NO_DATA; + args.handler = &task_no_data_intr; /* convert gtf to IDE Taskfile */ - memcpy(&args.tf_array[7], >f->tfa, 7); - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; + args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */ + args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */ + args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */ + args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */ + args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */ + args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */ + args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */ if (ide_noacpitfs) { DEBPRINT("_GTF execution disabled\n"); return err; } - err = ide_no_data_taskfile(drive, &args); + err = ide_raw_taskfile(drive, &args, NULL); if (err) - printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n", + printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n", __FUNCTION__, err); return err; diff --git a/trunk/drivers/ide/ide-cd.c b/trunk/drivers/ide/ide-cd.c index 44b033ec0ab0..c7d77f0ad892 100644 --- a/trunk/drivers/ide/ide-cd.c +++ b/trunk/drivers/ide/ide-cd.c @@ -917,13 +917,19 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY)) return startstop; - /* FIXME: for Virtual DMA we must check harder */ if (info->dma) info->dma = !hwif->dma_setup(drive); /* Set up the controller registers. */ - ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL | - IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma); + /* FIXME: for Virtual DMA we must check harder */ + HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG); + HWIF(drive)->OUTB(0, IDE_IREASON_REG); + HWIF(drive)->OUTB(0, IDE_SECTOR_REG); + + HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG); + HWIF(drive)->OUTB(xferlen >> 8 , IDE_BCOUNTH_REG); + if (IDE_CONTROL_REG) + HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* waiting for CDB interrupt, not DMA yet. */ diff --git a/trunk/drivers/ide/ide-disk.c b/trunk/drivers/ide/ide-disk.c index d8fdd865dea9..b1781908e1f2 100644 --- a/trunk/drivers/ide/ide-disk.c +++ b/trunk/drivers/ide/ide-disk.c @@ -129,50 +129,6 @@ static int lba_capacity_is_ok (struct hd_driveid *id) return 0; /* lba_capacity value may be bad */ } -static const u8 ide_rw_cmds[] = { - WIN_MULTREAD, - WIN_MULTWRITE, - WIN_MULTREAD_EXT, - WIN_MULTWRITE_EXT, - WIN_READ, - WIN_WRITE, - WIN_READ_EXT, - WIN_WRITE_EXT, - WIN_READDMA, - WIN_WRITEDMA, - WIN_READDMA_EXT, - WIN_WRITEDMA_EXT, -}; - -static const u8 ide_data_phases[] = { - TASKFILE_MULTI_IN, - TASKFILE_MULTI_OUT, - TASKFILE_IN, - TASKFILE_OUT, - TASKFILE_IN_DMA, - TASKFILE_OUT_DMA, -}; - -static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma) -{ - u8 index, lba48, write; - - lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; - write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; - - if (dma) - index = drive->vdma ? 4 : 8; - else - index = drive->mult_count ? 0 : 4; - - task->tf.command = ide_rw_cmds[index + lba48 + write]; - - if (dma) - index = 8; /* fixup index */ - - task->data_phase = ide_data_phases[index / 2 + write]; -} - /* * __ide_do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. @@ -181,11 +137,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, { ide_hwif_t *hwif = HWIF(drive); unsigned int dma = drive->using_dma; - u16 nsectors = (u16)rq->nr_sectors; u8 lba48 = (drive->addressing == 1) ? 1 : 0; - ide_task_t task; - struct ide_taskfile *tf = &task.tf; - ide_startstop_t rc; + task_ioreg_t command = WIN_NOP; + ata_nsector_t nsectors; + + nsectors.all = (u16) rq->nr_sectors; if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { if (block + rq->nr_sectors > 1ULL << 28) @@ -199,76 +155,121 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ide_map_sg(drive, rq); } - memset(&task, 0, sizeof(task)); - task.tf_flags = IDE_TFLAG_NO_SELECT_MASK; /* FIXME? */ - task.tf_flags |= (IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE); + if (IDE_CONTROL_REG) + hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + + /* FIXME: SELECT_MASK(drive, 0) ? */ if (drive->select.b.lba) { if (lba48) { + task_ioreg_t tasklets[10]; + pr_debug("%s: LBA=0x%012llx\n", drive->name, (unsigned long long)block); - tf->hob_nsect = (nsectors >> 8) & 0xff; - tf->hob_lbal = (u8)(block >> 24); - if (sizeof(block) != 4) { - tf->hob_lbam = (u8)((u64)block >> 32); - tf->hob_lbah = (u8)((u64)block >> 40); + tasklets[0] = 0; + tasklets[1] = 0; + tasklets[2] = nsectors.b.low; + tasklets[3] = nsectors.b.high; + tasklets[4] = (task_ioreg_t) block; + tasklets[5] = (task_ioreg_t) (block>>8); + tasklets[6] = (task_ioreg_t) (block>>16); + tasklets[7] = (task_ioreg_t) (block>>24); + if (sizeof(block) == 4) { + tasklets[8] = (task_ioreg_t) 0; + tasklets[9] = (task_ioreg_t) 0; + } else { + tasklets[8] = (task_ioreg_t)((u64)block >> 32); + tasklets[9] = (task_ioreg_t)((u64)block >> 40); } - - tf->nsect = nsectors & 0xff; - tf->lbal = (u8) block; - tf->lbam = (u8)(block >> 8); - tf->lbah = (u8)(block >> 16); #ifdef DEBUG printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", - drive->name, tf->hob_nsect, tf->nsect, - tf->hob_lbah, tf->hob_lbam, tf->hob_lbal, - tf->lbah, tf->lbam, tf->lbal); + drive->name, tasklets[3], tasklets[2], + tasklets[9], tasklets[8], tasklets[7], + tasklets[6], tasklets[5], tasklets[4]); #endif - task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_OUT_HOB); + hwif->OUTB(tasklets[1], IDE_FEATURE_REG); + hwif->OUTB(tasklets[3], IDE_NSECTOR_REG); + hwif->OUTB(tasklets[7], IDE_SECTOR_REG); + hwif->OUTB(tasklets[8], IDE_LCYL_REG); + hwif->OUTB(tasklets[9], IDE_HCYL_REG); + + hwif->OUTB(tasklets[0], IDE_FEATURE_REG); + hwif->OUTB(tasklets[2], IDE_NSECTOR_REG); + hwif->OUTB(tasklets[4], IDE_SECTOR_REG); + hwif->OUTB(tasklets[5], IDE_LCYL_REG); + hwif->OUTB(tasklets[6], IDE_HCYL_REG); + hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG); } else { - tf->nsect = nsectors & 0xff; - tf->lbal = block; - tf->lbam = block >>= 8; - tf->lbah = block >>= 8; - tf->device = (block >> 8) & 0xf; + hwif->OUTB(0x00, IDE_FEATURE_REG); + hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); + hwif->OUTB(block, IDE_SECTOR_REG); + hwif->OUTB(block>>=8, IDE_LCYL_REG); + hwif->OUTB(block>>=8, IDE_HCYL_REG); + hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); } } else { unsigned int sect,head,cyl,track; track = (int)block / drive->sect; sect = (int)block % drive->sect + 1; + hwif->OUTB(sect, IDE_SECTOR_REG); head = track % drive->head; cyl = track / drive->head; pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect); - tf->nsect = nsectors & 0xff; - tf->lbal = sect; - tf->lbam = cyl; - tf->lbah = cyl >> 8; - tf->device = head; + hwif->OUTB(0x00, IDE_FEATURE_REG); + hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); + hwif->OUTB(cyl, IDE_LCYL_REG); + hwif->OUTB(cyl>>8, IDE_HCYL_REG); + hwif->OUTB(head|drive->select.all,IDE_SELECT_REG); } - if (rq_data_dir(rq)) - task.tf_flags |= IDE_TFLAG_WRITE; - - ide_tf_set_cmd(drive, &task, dma); - if (!dma) - hwif->data_phase = task.data_phase; - task.rq = rq; - - rc = do_rw_taskfile(drive, &task); - - if (rc == ide_stopped && dma) { + if (dma) { + if (!hwif->dma_setup(drive)) { + if (rq_data_dir(rq)) { + command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; + if (drive->vdma) + command = lba48 ? WIN_WRITE_EXT: WIN_WRITE; + } else { + command = lba48 ? WIN_READDMA_EXT : WIN_READDMA; + if (drive->vdma) + command = lba48 ? WIN_READ_EXT: WIN_READ; + } + hwif->dma_exec_cmd(drive, command); + hwif->dma_start(drive); + return ide_started; + } /* fallback to PIO */ - task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK; - ide_tf_set_cmd(drive, &task, 0); - hwif->data_phase = task.data_phase; ide_init_sg_cmd(drive, rq); - rc = do_rw_taskfile(drive, &task); } - return rc; + if (rq_data_dir(rq) == READ) { + + if (drive->mult_count) { + hwif->data_phase = TASKFILE_MULTI_IN; + command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD; + } else { + hwif->data_phase = TASKFILE_IN; + command = lba48 ? WIN_READ_EXT : WIN_READ; + } + + ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL); + return ide_started; + } else { + if (drive->mult_count) { + hwif->data_phase = TASKFILE_MULTI_OUT; + command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; + } else { + hwif->data_phase = TASKFILE_OUT; + command = lba48 ? WIN_WRITE_EXT : WIN_WRITE; + } + + /* FIXME: ->OUTBSYNC ? */ + hwif->OUTB(command, IDE_COMMAND_REG); + + return pre_task_out_intr(drive, rq); + } } /* @@ -306,29 +307,57 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s * Queries for true maximum capacity of the drive. * Returns maximum LBA address (> 0) of the drive, 0 if failed. */ -static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) +static unsigned long idedisk_read_native_max_address(ide_drive_t *drive) { ide_task_t args; - struct ide_taskfile *tf = &args.tf; - u64 addr = 0; + unsigned long addr = 0; /* Create IDE/ATA command request structure */ memset(&args, 0, sizeof(ide_task_t)); - if (lba48) - tf->command = WIN_READ_NATIVE_MAX_EXT; - else - tf->command = WIN_READ_NATIVE_MAX; - tf->device = ATA_LBA; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - if (lba48) - args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_OUT_HOB); + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; /* submit command request */ - ide_no_data_taskfile(drive, &args); + ide_raw_taskfile(drive, &args, NULL); /* if OK, compute maximum address value */ - if ((tf->status & 0x01) == 0) - addr = ide_get_lba_addr(tf, lba48) + 1; + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) + | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) + | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) + | ((args.tfRegister[IDE_SECTOR_OFFSET] )); + addr++; /* since the return value is (maxlba - 1), we add 1 */ + } + return addr; +} + +static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive) +{ + ide_task_t args; + unsigned long long addr = 0; + + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + + /* if OK, compute maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) | + (args.hobRegister[IDE_LCYL_OFFSET] << 8) | + args.hobRegister[IDE_SECTOR_OFFSET]; + u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | + ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | + (args.tfRegister[IDE_SECTOR_OFFSET]); + addr = ((__u64)high << 24) | low; + addr++; /* since the return value is (maxlba - 1), we add 1 */ + } return addr; } @@ -336,37 +365,67 @@ static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) * Sets maximum virtual LBA address of the drive. * Returns new maximum virtual LBA address (> 0) or 0 on failure. */ -static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48) +static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req) { ide_task_t args; - struct ide_taskfile *tf = &args.tf; - u64 addr_set = 0; - + unsigned long addr_set = 0; + addr_req--; /* Create IDE/ATA command request structure */ memset(&args, 0, sizeof(ide_task_t)); - tf->lbal = (addr_req >> 0) & 0xff; - tf->lbam = (addr_req >>= 8) & 0xff; - tf->lbah = (addr_req >>= 8) & 0xff; - if (lba48) { - tf->hob_lbal = (addr_req >>= 8) & 0xff; - tf->hob_lbam = (addr_req >>= 8) & 0xff; - tf->hob_lbah = (addr_req >>= 8) & 0xff; - tf->command = WIN_SET_MAX_EXT; - } else { - tf->device = (addr_req >>= 8) & 0x0f; - tf->command = WIN_SET_MAX; + args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); + args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff); + args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff); + args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + /* submit command request */ + ide_raw_taskfile(drive, &args, NULL); + /* if OK, read new maximum address value */ + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) + | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) + | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) + | ((args.tfRegister[IDE_SECTOR_OFFSET] )); + addr_set++; } - tf->device |= ATA_LBA; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - if (lba48) - args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_OUT_HOB); + return addr_set; +} + +static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req) +{ + ide_task_t args; + unsigned long long addr_set = 0; + + addr_req--; + /* Create IDE/ATA command request structure */ + memset(&args, 0, sizeof(ide_task_t)); + args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); + args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff); + args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff); + args.tfRegister[IDE_SELECT_OFFSET] = 0x40; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT; + args.hobRegister[IDE_SECTOR_OFFSET] = (addr_req >>= 8) & 0xff; + args.hobRegister[IDE_LCYL_OFFSET] = (addr_req >>= 8) & 0xff; + args.hobRegister[IDE_HCYL_OFFSET] = (addr_req >>= 8) & 0xff; + args.hobRegister[IDE_SELECT_OFFSET] = 0x40; + args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; /* submit command request */ - ide_no_data_taskfile(drive, &args); + ide_raw_taskfile(drive, &args, NULL); /* if OK, compute maximum address value */ - if ((tf->status & 0x01) == 0) - addr_set = ide_get_lba_addr(tf, lba48) + 1; - + if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { + u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) | + (args.hobRegister[IDE_LCYL_OFFSET] << 8) | + args.hobRegister[IDE_SECTOR_OFFSET]; + u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | + ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | + (args.tfRegister[IDE_SECTOR_OFFSET]); + addr_set = ((__u64)high << 24) | low; + addr_set++; + } return addr_set; } @@ -412,8 +471,10 @@ static void idedisk_check_hpa(ide_drive_t *drive) int lba48 = idedisk_supports_lba48(drive->id); capacity = drive->capacity64; - - set_max = idedisk_read_native_max_address(drive, lba48); + if (lba48) + set_max = idedisk_read_native_max_address_ext(drive); + else + set_max = idedisk_read_native_max_address(drive); if (ide_in_drive_list(drive->id, hpa_list)) { /* @@ -434,8 +495,10 @@ static void idedisk_check_hpa(ide_drive_t *drive) capacity, sectors_to_MB(capacity), set_max, sectors_to_MB(set_max)); - set_max = idedisk_set_max_address(drive, set_max, lba48); - + if (lba48) + set_max = idedisk_set_max_address_ext(drive, set_max); + else + set_max = idedisk_set_max_address(drive, set_max); if (set_max) { drive->capacity64 = set_max; printk(KERN_INFO "%s: Host Protected Area disabled.\n", @@ -493,32 +556,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive) static int smart_enable(ide_drive_t *drive) { ide_task_t args; - struct ide_taskfile *tf = &args.tf; memset(&args, 0, sizeof(ide_task_t)); - tf->feature = SMART_ENABLE; - tf->lbam = SMART_LCYL_PASS; - tf->lbah = SMART_HCYL_PASS; - tf->command = WIN_SMART; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - return ide_no_data_taskfile(drive, &args); + args.tfRegister[IDE_FEATURE_OFFSET] = SMART_ENABLE; + args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; + args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + return ide_raw_taskfile(drive, &args, NULL); } static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd) { ide_task_t args; - struct ide_taskfile *tf = &args.tf; memset(&args, 0, sizeof(ide_task_t)); - tf->feature = sub_cmd; - tf->nsect = 0x01; - tf->lbam = SMART_LCYL_PASS; - tf->lbah = SMART_HCYL_PASS; - tf->command = WIN_SMART; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - args.data_phase = TASKFILE_IN; + args.tfRegister[IDE_FEATURE_OFFSET] = sub_cmd; + args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; + args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; + args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; + args.command_type = IDE_DRIVE_TASK_IN; + args.data_phase = TASKFILE_IN; + args.handler = &task_in_intr; (void) smart_enable(drive); - return ide_raw_taskfile(drive, &args, buf, 1); + return ide_raw_taskfile(drive, &args, buf); } static int proc_idedisk_read_cache @@ -596,20 +659,19 @@ static ide_proc_entry_t idedisk_proc[] = { static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) { ide_drive_t *drive = q->queuedata; - ide_task_t task; - memset(&task, 0, sizeof(task)); + memset(rq->cmd, 0, sizeof(rq->cmd)); + if (ide_id_has_flush_cache_ext(drive->id) && (drive->capacity64 >= (1UL << 28))) - task.tf.command = WIN_FLUSH_CACHE_EXT; + rq->cmd[0] = WIN_FLUSH_CACHE_EXT; else - task.tf.command = WIN_FLUSH_CACHE; - task.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - task.data_phase = TASKFILE_NO_DATA; + rq->cmd[0] = WIN_FLUSH_CACHE; + - rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + rq->cmd_type = REQ_TYPE_ATA_TASK; rq->cmd_flags |= REQ_SOFTBARRIER; - rq->special = &task; + rq->buffer = rq->cmd; } /* @@ -691,11 +753,12 @@ static int write_cache(ide_drive_t *drive, int arg) if (ide_id_has_flush_cache(drive->id)) { memset(&args, 0, sizeof(ide_task_t)); - args.tf.feature = arg ? + args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; - args.tf.command = WIN_SETFEATURES; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - err = ide_no_data_taskfile(drive, &args); + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + err = ide_raw_taskfile(drive, &args, NULL); if (err == 0) drive->wcache = arg; } @@ -711,11 +774,12 @@ static int do_idedisk_flushcache (ide_drive_t *drive) memset(&args, 0, sizeof(ide_task_t)); if (ide_id_has_flush_cache_ext(drive->id)) - args.tf.command = WIN_FLUSH_CACHE_EXT; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT; else - args.tf.command = WIN_FLUSH_CACHE; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - return ide_no_data_taskfile(drive, &args); + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + return ide_raw_taskfile(drive, &args, NULL); } static int set_acoustic (ide_drive_t *drive, int arg) @@ -726,11 +790,13 @@ static int set_acoustic (ide_drive_t *drive, int arg) return -EINVAL; memset(&args, 0, sizeof(ide_task_t)); - args.tf.feature = arg ? SETFEATURES_EN_AAM : SETFEATURES_DIS_AAM; - args.tf.nsect = arg; - args.tf.command = WIN_SETFEATURES; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - ide_no_data_taskfile(drive, &args); + args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? SETFEATURES_EN_AAM : + SETFEATURES_DIS_AAM; + args.tfRegister[IDE_NSECTOR_OFFSET] = arg; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + ide_raw_taskfile(drive, &args, NULL); drive->acoustic = arg; return 0; } @@ -991,15 +1057,16 @@ static int idedisk_open(struct inode *inode, struct file *filp) if (drive->removable && idkp->openers == 1) { ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); - args.tf.command = WIN_DOORLOCK; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; check_disk_change(inode->i_bdev); /* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - if (drive->doorlocking && ide_no_data_taskfile(drive, &args)) + if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) drive->doorlocking = 0; } return 0; @@ -1017,9 +1084,10 @@ static int idedisk_release(struct inode *inode, struct file *filp) if (drive->removable && idkp->openers == 1) { ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); - args.tf.command = WIN_DOORUNLOCK; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - if (drive->doorlocking && ide_no_data_taskfile(drive, &args)) + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK; + args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.handler = &task_no_data_intr; + if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) drive->doorlocking = 0; } diff --git a/trunk/drivers/ide/ide-dma.c b/trunk/drivers/ide/ide-dma.c index 18c78ad2b31e..4703837bf1fc 100644 --- a/trunk/drivers/ide/ide-dma.c +++ b/trunk/drivers/ide/ide-dma.c @@ -491,6 +491,10 @@ EXPORT_SYMBOL(ide_dma_host_on); int __ide_dma_on (ide_drive_t *drive) { + /* consult the list of known "bad" drives */ + if (__ide_dma_bad_drive(drive)) + return 1; + drive->using_dma = 1; ide_toggle_bounce(drive, 1); @@ -823,19 +827,22 @@ int ide_set_dma(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; int rc; - /* - * Force DMAing for the beginning of the check. - * Some chipsets appear to do interesting - * things, if not checked and cleared. - * PARANOIA!!! - */ - hwif->dma_off_quietly(drive); - rc = ide_dma_check(drive); - if (rc) - return rc; - return hwif->ide_dma_on(drive); + switch(rc) { + case -1: /* DMA needs to be disabled */ + hwif->dma_off_quietly(drive); + return -1; + case 0: /* DMA needs to be enabled */ + return hwif->ide_dma_on(drive); + case 1: /* DMA setting cannot be changed */ + break; + default: + BUG(); + break; + } + + return rc; } #ifdef CONFIG_BLK_DEV_IDEDMA_PCI @@ -961,6 +968,11 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) hwif->dma_base = base; + if (hwif->mate) + hwif->dma_master = hwif->channel ? hwif->mate->dma_base : base; + else + hwif->dma_master = base; + if (!(hwif->dma_command)) hwif->dma_command = hwif->dma_base; if (!(hwif->dma_vendor1)) @@ -1002,6 +1014,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); } printk("\n"); + + BUG_ON(!hwif->dma_master); } EXPORT_SYMBOL_GPL(ide_setup_dma); diff --git a/trunk/drivers/ide/ide-floppy.c b/trunk/drivers/ide/ide-floppy.c index ff8232ef9659..04a357808f2e 100644 --- a/trunk/drivers/ide/ide-floppy.c +++ b/trunk/drivers/ide/ide-floppy.c @@ -369,6 +369,27 @@ typedef struct ide_floppy_obj { #define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 +#if 0 +/* + * Special requests for our block device strategy routine. + */ +#define IDEFLOPPY_FIRST_RQ 90 + +/* + * IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue. + */ +#define IDEFLOPPY_PC_RQ 90 + +#define IDEFLOPPY_LAST_RQ 90 + +/* + * A macro which can be used to check if a given request command + * originated in the driver or in the buffer cache layer. + */ +#define IDEFLOPPY_RQ_CMD(cmd) ((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ)) + +#endif + /* * Error codes which are returned in rq->errors to the higher part * of the driver. @@ -772,8 +793,9 @@ static void idefloppy_retry_pc (ide_drive_t *drive) { idefloppy_pc_t *pc; struct request *rq; + atapi_error_t error; - (void)drive->hwif->INB(IDE_ERROR_REG); + error.all = HWIF(drive)->INB(IDE_ERROR_REG); pc = idefloppy_next_pc_storage(drive); rq = idefloppy_next_rq_storage(drive); idefloppy_create_request_sense_cmd(pc); @@ -787,12 +809,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive) static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; - ide_hwif_t *hwif = drive->hwif; + atapi_status_t status; + atapi_bcount_t bcount; + atapi_ireason_t ireason; idefloppy_pc_t *pc = floppy->pc; struct request *rq = pc->rq; unsigned int temp; - u16 bcount; - u8 stat, ireason; debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", __FUNCTION__); @@ -808,16 +830,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) } /* Clear the interrupt */ - stat = drive->hwif->INB(IDE_STATUS_REG); + status.all = HWIF(drive)->INB(IDE_STATUS_REG); - if ((stat & DRQ_STAT) == 0) { /* No more interrupts */ + if (!status.b.drq) { /* No more interrupts */ debug_log(KERN_INFO "Packet command completed, %d bytes " "transferred\n", pc->actually_transferred); clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); local_irq_enable_in_hardirq(); - if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) { + if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ debug_log(KERN_INFO "ide-floppy: %s: I/O error\n", drive->name); @@ -848,32 +870,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) } /* Get the number of bytes to transfer */ - bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | - hwif->INB(IDE_BCOUNTL_REG); + bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); + bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); /* on this interrupt */ - ireason = hwif->INB(IDE_IREASON_REG); + ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); - if (ireason & CD) { + if (ireason.b.cod) { printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n"); return ide_do_reset(drive); } - if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) { + if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk(KERN_ERR "ide-floppy: We wanted to %s, ", - (ireason & IO) ? "Write" : "Read"); + ireason.b.io ? "Write":"Read"); printk(KERN_ERR "but the floppy wants us to %s !\n", - (ireason & IO) ? "Read" : "Write"); + ireason.b.io ? "Read":"Write"); return ide_do_reset(drive); } if (!test_bit(PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ - temp = pc->actually_transferred + bcount; + temp = pc->actually_transferred + bcount.all; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-floppy: The floppy wants " "to send us more data than expected " "- discarding data\n"); - idefloppy_discard_data(drive, bcount); + idefloppy_discard_data(drive,bcount.all); BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, &idefloppy_pc_intr, @@ -889,21 +911,23 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) if (test_bit(PC_WRITING, &pc->flags)) { if (pc->buffer != NULL) /* Write the current buffer */ - hwif->atapi_output_bytes(drive, pc->current_position, - bcount); + HWIF(drive)->atapi_output_bytes(drive, + pc->current_position, + bcount.all); else - idefloppy_output_buffers(drive, pc, bcount); + idefloppy_output_buffers(drive, pc, bcount.all); } else { if (pc->buffer != NULL) /* Read the current buffer */ - hwif->atapi_input_bytes(drive, pc->current_position, - bcount); + HWIF(drive)->atapi_input_bytes(drive, + pc->current_position, + bcount.all); else - idefloppy_input_buffers(drive, pc, bcount); + idefloppy_input_buffers(drive, pc, bcount.all); } /* Update the current position */ - pc->actually_transferred += bcount; - pc->current_position += bcount; + pc->actually_transferred += bcount.all; + pc->current_position += bcount.all; BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ @@ -919,15 +943,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive) { ide_startstop_t startstop; idefloppy_floppy_t *floppy = drive->driver_data; - u8 ireason; + atapi_ireason_t ireason; if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { printk(KERN_ERR "ide-floppy: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = drive->hwif->INB(IDE_IREASON_REG); - if ((ireason & CD) == 0 || (ireason & IO)) { + ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); + if (!ireason.b.cod || ireason.b.io) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while " "issuing a packet command\n"); return ide_do_reset(drive); @@ -967,15 +991,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; ide_startstop_t startstop; - u8 ireason; + atapi_ireason_t ireason; if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { printk(KERN_ERR "ide-floppy: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = drive->hwif->INB(IDE_IREASON_REG); - if ((ireason & CD) == 0 || (ireason & IO)) { + ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); + if (!ireason.b.cod || ireason.b.io) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) " "while issuing a packet command\n"); return ide_do_reset(drive); @@ -1017,9 +1041,21 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p { idefloppy_floppy_t *floppy = drive->driver_data; ide_hwif_t *hwif = drive->hwif; + atapi_feature_t feature; + atapi_bcount_t bcount; ide_handler_t *pkt_xfer_routine; - u16 bcount; - u8 dma; + +#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone + and have lived on another thread's stack; that stack may have become + unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */ +#if IDEFLOPPY_DEBUG_BUGS + if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && + pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { + printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - " + "Two request sense in serial were issued\n"); + } +#endif /* IDEFLOPPY_DEBUG_BUGS */ +#endif if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD) @@ -1057,20 +1093,25 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p /* We haven't transferred any data yet */ pc->actually_transferred = 0; pc->current_position = pc->buffer; - bcount = min(pc->request_transfer, 63 * 1024); + bcount.all = min(pc->request_transfer, 63 * 1024); if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) ide_dma_off(drive); - dma = 0; + feature.all = 0; if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - dma = !hwif->dma_setup(drive); + feature.b.dma = !hwif->dma_setup(drive); - ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK | - IDE_TFLAG_OUT_DEVICE, bcount, dma); + if (IDE_CONTROL_REG) + HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); + /* Use PIO/DMA */ + HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG); + HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG); + HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG); + HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG); - if (dma) { /* Begin DMA, if necessary */ + if (feature.b.dma) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); hwif->dma_start(drive); } @@ -1624,14 +1665,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg) /* Else assume format_unit has finished, and we're ** at 0x10000 */ } else { + atapi_status_t status; unsigned long flags; - u8 stat; local_irq_save(flags); - stat = drive->hwif->INB(IDE_STATUS_REG); + status.all = HWIF(drive)->INB(IDE_STATUS_REG); local_irq_restore(flags); - progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000; + progress_indication = !status.b.dsc ? 0 : 0x10000; } if (put_user(progress_indication, arg)) return (-EFAULT); diff --git a/trunk/drivers/ide/ide-io.c b/trunk/drivers/ide/ide-io.c index 2711b5a6962d..bef781fec500 100644 --- a/trunk/drivers/ide/ide-io.c +++ b/trunk/drivers/ide/ide-io.c @@ -189,14 +189,18 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * return ide_stopped; } if (ide_id_has_flush_cache_ext(drive->id)) - args->tf.command = WIN_FLUSH_CACHE_EXT; + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT; else - args->tf.command = WIN_FLUSH_CACHE; - goto out_do_tf; + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + args->handler = &task_no_data_intr; + return do_rw_taskfile(drive, args); case idedisk_pm_standby: /* Suspend step 2 (standby) */ - args->tf.command = WIN_STANDBYNOW1; - goto out_do_tf; + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + args->handler = &task_no_data_intr; + return do_rw_taskfile(drive, args); case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */ ide_set_max_pio(drive); @@ -210,8 +214,10 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * return ide_stopped; case idedisk_pm_idle: /* Resume step 2 (idle) */ - args->tf.command = WIN_IDLEIMMEDIATE; - goto out_do_tf; + args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE; + args->command_type = IDE_DRIVE_TASK_NO_DATA; + args->handler = task_no_data_intr; + return do_rw_taskfile(drive, args); case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */ /* @@ -221,6 +227,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * */ if (drive->hwif->ide_dma_on == NULL) break; + drive->hwif->dma_off_quietly(drive); /* * TODO: respect ->using_dma setting */ @@ -229,11 +236,6 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * } pm->pm_step = ide_pm_state_completed; return ide_stopped; - -out_do_tf: - args->tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - args->data_phase = TASKFILE_NO_DATA; - return do_rw_taskfile(drive, args); } /** @@ -296,48 +298,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) spin_unlock_irqrestore(&ide_lock, flags); } -void ide_tf_read(ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_taskfile *tf = &task->tf; - - if (task->tf_flags & IDE_TFLAG_IN_DATA) { - u16 data = hwif->INW(IDE_DATA_REG); - - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - - /* be sure we're looking at the low order bits */ - hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); - - if (task->tf_flags & IDE_TFLAG_IN_NSECT) - tf->nsect = hwif->INB(IDE_NSECTOR_REG); - if (task->tf_flags & IDE_TFLAG_IN_LBAL) - tf->lbal = hwif->INB(IDE_SECTOR_REG); - if (task->tf_flags & IDE_TFLAG_IN_LBAM) - tf->lbam = hwif->INB(IDE_LCYL_REG); - if (task->tf_flags & IDE_TFLAG_IN_LBAH) - tf->lbah = hwif->INB(IDE_HCYL_REG); - if (task->tf_flags & IDE_TFLAG_IN_DEVICE) - tf->device = hwif->INB(IDE_SELECT_REG); - - if (task->tf_flags & IDE_TFLAG_LBA48) { - hwif->OUTB(drive->ctl | 0x80, IDE_CONTROL_REG); - - if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = hwif->INB(IDE_FEATURE_REG); - if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = hwif->INB(IDE_NSECTOR_REG); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = hwif->INB(IDE_SECTOR_REG); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = hwif->INB(IDE_LCYL_REG); - if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = hwif->INB(IDE_HCYL_REG); - } -} - /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -372,22 +332,51 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) args[1] = err; args[2] = hwif->INB(IDE_NSECTOR_REG); } + } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { + u8 *args = (u8 *) rq->buffer; + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + + if (args) { + args[0] = stat; + args[1] = err; + /* be sure we're looking at the low order bits */ + hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); + args[2] = hwif->INB(IDE_NSECTOR_REG); + args[3] = hwif->INB(IDE_SECTOR_REG); + args[4] = hwif->INB(IDE_LCYL_REG); + args[5] = hwif->INB(IDE_HCYL_REG); + args[6] = hwif->INB(IDE_SELECT_REG); + } } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = (ide_task_t *) rq->special; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); if (args) { - struct ide_taskfile *tf = &args->tf; - - tf->error = err; - tf->status = stat; - - args->tf_flags |= (IDE_TFLAG_IN_TF|IDE_TFLAG_IN_DEVICE); - if (args->tf_flags & IDE_TFLAG_LBA48) - args->tf_flags |= IDE_TFLAG_IN_HOB; - - ide_tf_read(drive, args); + if (args->tf_in_flags.b.data) { + u16 data = hwif->INW(IDE_DATA_REG); + args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; + args->hobRegister[IDE_DATA_OFFSET] = (data >> 8) & 0xFF; + } + args->tfRegister[IDE_ERROR_OFFSET] = err; + /* be sure we're looking at the low order bits */ + hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); + args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); + args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); + args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); + args->tfRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); + args->tfRegister[IDE_SELECT_OFFSET] = hwif->INB(IDE_SELECT_REG); + args->tfRegister[IDE_STATUS_OFFSET] = stat; + + if (drive->addressing == 1) { + hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + args->hobRegister[IDE_FEATURE_OFFSET] = hwif->INB(IDE_FEATURE_REG); + args->hobRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); + args->hobRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); + args->hobRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); + args->hobRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); + } } } else if (blk_pm_request(rq)) { struct request_pm_state *pm = rq->data; @@ -626,6 +615,28 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg) return __ide_abort(drive, rq); } +/** + * ide_cmd - issue a simple drive command + * @drive: drive the command is for + * @cmd: command byte + * @nsect: sector byte + * @handler: handler for the command completion + * + * Issue a simple drive command with interrupts. + * The drive must be selected beforehand. + */ + +static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, + ide_handler_t *handler) +{ + ide_hwif_t *hwif = HWIF(drive); + if (IDE_CONTROL_REG) + hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(drive,0); + hwif->OUTB(nsect,IDE_NSECTOR_REG); + ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL); +} + /** * drive_cmd_intr - drive command completion interrupt * @drive: drive the completion interrupt occurred on @@ -662,26 +673,32 @@ static ide_startstop_t drive_cmd_intr (ide_drive_t *drive) return ide_stopped; } -static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf) +static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task) { - tf->nsect = drive->sect; - tf->lbal = drive->sect; - tf->lbam = drive->cyl; - tf->lbah = drive->cyl >> 8; - tf->device = ((drive->head - 1) | drive->select.all) & ~ATA_LBA; - tf->command = WIN_SPECIFY; + task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; + task->tfRegister[IDE_SECTOR_OFFSET] = drive->sect; + task->tfRegister[IDE_LCYL_OFFSET] = drive->cyl; + task->tfRegister[IDE_HCYL_OFFSET] = drive->cyl>>8; + task->tfRegister[IDE_SELECT_OFFSET] = ((drive->head-1)|drive->select.all)&0xBF; + task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY; + + task->handler = &set_geometry_intr; } -static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf) +static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task) { - tf->nsect = drive->sect; - tf->command = WIN_RESTORE; + task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; + task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE; + + task->handler = &recal_intr; } -static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf) +static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task) { - tf->nsect = drive->mult_req; - tf->command = WIN_SETMULT; + task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req; + task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT; + + task->handler = &set_multmode_intr; } static ide_startstop_t ide_disk_special(ide_drive_t *drive) @@ -690,19 +707,19 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive) ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); - args.data_phase = TASKFILE_NO_DATA; + args.command_type = IDE_DRIVE_TASK_NO_DATA; if (s->b.set_geometry) { s->b.set_geometry = 0; - ide_tf_set_specify_cmd(drive, &args.tf); + ide_init_specify_cmd(drive, &args); } else if (s->b.recalibrate) { s->b.recalibrate = 0; - ide_tf_set_restore_cmd(drive, &args.tf); + ide_init_restore_cmd(drive, &args); } else if (s->b.set_multmode) { s->b.set_multmode = 0; if (drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; - ide_tf_set_setmult_cmd(drive, &args.tf); + ide_init_setmult_cmd(drive, &args); } else if (s->all) { int special = s->all; s->all = 0; @@ -710,9 +727,6 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive) return ide_stopped; } - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE | - IDE_TFLAG_CUSTOM_HANDLER; - do_rw_taskfile(drive, &args); return ide_started; @@ -847,17 +861,13 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { ide_hwif_t *hwif = HWIF(drive); - u8 *args = rq->buffer; - ide_task_t ltask; - struct ide_taskfile *tf = <ask.tf; - if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { - ide_task_t *task = rq->special; + ide_task_t *args = rq->special; - if (task == NULL) + if (!args) goto done; - hwif->data_phase = task->data_phase; + hwif->data_phase = args->data_phase; switch (hwif->data_phase) { case TASKFILE_MULTI_OUT: @@ -870,34 +880,55 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, break; } - return do_rw_taskfile(drive, task); - } - - if (args == NULL) - goto done; - - memset(<ask, 0, sizeof(ltask)); - if (rq->cmd_type == REQ_TYPE_ATA_CMD) { + if (args->tf_out_flags.all != 0) + return flagged_taskfile(drive, args); + return do_rw_taskfile(drive, args); + } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { + u8 *args = rq->buffer; + + if (!args) + goto done; #ifdef DEBUG - printk("%s: DRIVE_CMD\n", drive->name); + printk("%s: DRIVE_TASK_CMD ", drive->name); + printk("cmd=0x%02x ", args[0]); + printk("fr=0x%02x ", args[1]); + printk("ns=0x%02x ", args[2]); + printk("sc=0x%02x ", args[3]); + printk("lcyl=0x%02x ", args[4]); + printk("hcyl=0x%02x ", args[5]); + printk("sel=0x%02x\n", args[6]); #endif - tf->feature = args[2]; - if (args[0] == WIN_SMART) { - tf->nsect = args[3]; - tf->lbal = args[1]; - tf->lbam = 0x4f; - tf->lbah = 0xc2; - ltask.tf_flags = IDE_TFLAG_OUT_TF; - } else { - tf->nsect = args[1]; - ltask.tf_flags = IDE_TFLAG_OUT_FEATURE | - IDE_TFLAG_OUT_NSECT; - } + hwif->OUTB(args[1], IDE_FEATURE_REG); + hwif->OUTB(args[3], IDE_SECTOR_REG); + hwif->OUTB(args[4], IDE_LCYL_REG); + hwif->OUTB(args[5], IDE_HCYL_REG); + hwif->OUTB((args[6] & 0xEF)|drive->select.all, IDE_SELECT_REG); + ide_cmd(drive, args[0], args[2], &drive_cmd_intr); + return ide_started; + } else if (rq->cmd_type == REQ_TYPE_ATA_CMD) { + u8 *args = rq->buffer; + + if (!args) + goto done; +#ifdef DEBUG + printk("%s: DRIVE_CMD ", drive->name); + printk("cmd=0x%02x ", args[0]); + printk("sc=0x%02x ", args[1]); + printk("fr=0x%02x ", args[2]); + printk("xx=0x%02x\n", args[3]); +#endif + if (args[0] == WIN_SMART) { + hwif->OUTB(0x4f, IDE_LCYL_REG); + hwif->OUTB(0xc2, IDE_HCYL_REG); + hwif->OUTB(args[2],IDE_FEATURE_REG); + hwif->OUTB(args[1],IDE_SECTOR_REG); + ide_cmd(drive, args[0], args[3], &drive_cmd_intr); + return ide_started; + } + hwif->OUTB(args[2],IDE_FEATURE_REG); + ide_cmd(drive, args[0], args[1], &drive_cmd_intr); + return ide_started; } - tf->command = args[0]; - ide_tf_load(drive, <ask); - ide_execute_command(drive, args[0], &drive_cmd_intr, WAIT_WORSTCASE, NULL); - return ide_started; done: /* @@ -972,7 +1003,6 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) /* bail early if we've exceeded max_failures */ if (drive->max_failures && (drive->failures > drive->max_failures)) { - rq->cmd_flags |= REQ_FAILED; goto kill_rq; } @@ -1005,6 +1035,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) ide_config_drive_speed(drive, drive->desired_speed); if (rq->cmd_type == REQ_TYPE_ATA_CMD || + rq->cmd_type == REQ_TYPE_ATA_TASK || rq->cmd_type == REQ_TYPE_ATA_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { @@ -1216,12 +1247,8 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) { - /* - * set nIEN for previous hwif, drives in the - * quirk_list may not like intr setups/cleanups - */ - if (drive->quirk_list != 1) - hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); + /* set nIEN for previous hwif */ + SELECT_INTERRUPT(drive); } hwgroup->hwif = hwif; hwgroup->drive = drive; @@ -1427,8 +1454,12 @@ void ide_timer_expiry (unsigned long data) */ spin_unlock(&ide_lock); hwif = HWIF(drive); +#if DISABLE_IRQ_NOSYNC + disable_irq_nosync(hwif->irq); +#else /* disable_irq_nosync ?? */ disable_irq(hwif->irq); +#endif /* DISABLE_IRQ_NOSYNC */ /* local CPU only, * as if we were handling an interrupt */ local_irq_disable(); @@ -1754,19 +1785,3 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio } EXPORT_SYMBOL(ide_do_drive_cmd); - -void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma) -{ - ide_task_t task; - - memset(&task, 0, sizeof(task)); - task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM | - IDE_TFLAG_OUT_FEATURE | tf_flags; - task.tf.feature = dma; /* Use PIO/DMA */ - task.tf.lbam = bcount & 0xff; - task.tf.lbah = (bcount >> 8) & 0xff; - - ide_tf_load(drive, &task); -} - -EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load); diff --git a/trunk/drivers/ide/ide-iops.c b/trunk/drivers/ide/ide-iops.c index c97c0719ddf1..bb9693dabe41 100644 --- a/trunk/drivers/ide/ide-iops.c +++ b/trunk/drivers/ide/ide-iops.c @@ -158,6 +158,14 @@ void default_hwif_mmiops (ide_hwif_t *hwif) EXPORT_SYMBOL(default_hwif_mmiops); +u32 ide_read_24 (ide_drive_t *drive) +{ + u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG); + u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG); + u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG); + return (hcyl<<16)|(lcyl<<8)|sect; +} + void SELECT_DRIVE (ide_drive_t *drive) { if (HWIF(drive)->selectproc) @@ -167,12 +175,26 @@ void SELECT_DRIVE (ide_drive_t *drive) EXPORT_SYMBOL(SELECT_DRIVE); +void SELECT_INTERRUPT (ide_drive_t *drive) +{ + if (HWIF(drive)->intrproc) + HWIF(drive)->intrproc(drive); + else + HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG); +} + void SELECT_MASK (ide_drive_t *drive, int mask) { if (HWIF(drive)->maskproc) HWIF(drive)->maskproc(drive, mask); } +void QUIRK_LIST (ide_drive_t *drive) +{ + if (HWIF(drive)->quirkproc) + drive->quirk_list = HWIF(drive)->quirkproc(drive); +} + /* * Some localbus EIDE interfaces require a special access sequence * when using 32-bit I/O instructions to transfer data. We call this @@ -427,6 +449,7 @@ int drive_is_ready (ide_drive_t *drive) udelay(1); #endif +#ifdef CONFIG_IDEPCI_SHARE_IRQ /* * We do a passive status test under shared PCI interrupts on * cards that truly share the ATA side interrupt, but may also share @@ -436,6 +459,7 @@ int drive_is_ready (ide_drive_t *drive) if (IDE_CONTROL_REG) stat = hwif->INB(IDE_ALTSTATUS_REG); else +#endif /* CONFIG_IDEPCI_SHARE_IRQ */ /* Note: this may clear a pending IRQ!! */ stat = hwif->INB(IDE_STATUS_REG); @@ -618,9 +642,9 @@ u8 eighty_ninty_three (ide_drive_t *drive) int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) { - if (args->tf.command == WIN_SETFEATURES && - args->tf.lbal > XFER_UDMA_2 && - args->tf.feature == SETFEATURES_XFER) { + if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && + (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) && + (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) { if (eighty_ninty_three(drive) == 0) { printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot " "be set\n", drive->name); @@ -638,9 +662,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) */ int set_transfer (ide_drive_t *drive, ide_task_t *args) { - if (args->tf.command == WIN_SETFEATURES && - args->tf.lbal >= XFER_SW_DMA_0 && - args->tf.feature == SETFEATURES_XFER && + if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && + (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) && + (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) && (drive->id->dma_ultra || drive->id->dma_mword || drive->id->dma_1word)) @@ -878,9 +902,8 @@ EXPORT_SYMBOL(ide_set_handler); * handler and IRQ setup do not race. All IDE command kick off * should go via this function or do equivalent locking. */ - -void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler, - unsigned timeout, ide_expiry_t *expiry) + +void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry) { unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -1028,7 +1051,8 @@ static void ide_disk_pre_reset(ide_drive_t *drive) drive->special.all = 0; drive->special.b.set_geometry = legacy; drive->special.b.recalibrate = legacy; - drive->mult_count = 0; + if (OK_TO_RESET_CONTROLLER) + drive->mult_count = 0; if (!drive->keep_settings && !drive->using_dma) drive->mult_req = 0; if (drive->mult_req != drive->mult_count) @@ -1113,6 +1137,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) for (unit = 0; unit < MAX_DRIVES; ++unit) pre_reset(&hwif->drives[unit]); +#if OK_TO_RESET_CONTROLLER if (!IDE_CONTROL_REG) { spin_unlock_irqrestore(&ide_lock, flags); return ide_stopped; @@ -1149,8 +1174,11 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) * state when the disks are reset this way. At least, the Winbond * 553 documentation says that */ - if (hwif->resetproc) + if (hwif->resetproc != NULL) { hwif->resetproc(drive); + } + +#endif /* OK_TO_RESET_CONTROLLER */ spin_unlock_irqrestore(&ide_lock, flags); return ide_started; diff --git a/trunk/drivers/ide/ide-lib.c b/trunk/drivers/ide/ide-lib.c index a3bd8e8ed6b0..062d3bcb2471 100644 --- a/trunk/drivers/ide/ide-lib.c +++ b/trunk/drivers/ide/ide-lib.c @@ -441,12 +441,6 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) * case could happen iff the transfer mode has already been set on * the device by ide-proc.c::set_xfer_rate()). */ - if (rate < XFER_PIO_0) { - if (hwif->host_flags & IDE_HFLAG_ABUSE_SET_DMA_MODE) - return ide_set_dma_mode(drive, rate); - else - return ide_config_drive_speed(drive, rate); - } return ide_set_dma_mode(drive, rate); } @@ -464,7 +458,8 @@ static void ide_dump_opcode(ide_drive_t *drive) spin_unlock(&ide_lock); if (!rq) return; - if (rq->cmd_type == REQ_TYPE_ATA_CMD) { + if (rq->cmd_type == REQ_TYPE_ATA_CMD || + rq->cmd_type == REQ_TYPE_ATA_TASK) { char *args = rq->buffer; if (args) { opcode = args[0]; @@ -473,7 +468,8 @@ static void ide_dump_opcode(ide_drive_t *drive) } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = rq->special; if (args) { - opcode = args->tf.command; + task_struct_t *tf = (task_struct_t *) args->tfRegister; + opcode = tf->command; found = 1; } } @@ -485,118 +481,141 @@ static void ide_dump_opcode(ide_drive_t *drive) printk("0x%02x\n", opcode); } -u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48) +static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) { - u32 high, low; - - if (lba48) - high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) | - tf->hob_lbal; - else - high = tf->device & 0xf; - low = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; - - return ((u64)high << 24) | low; -} -EXPORT_SYMBOL_GPL(ide_get_lba_addr); - -static void ide_dump_sector(ide_drive_t *drive) -{ - ide_task_t task; - struct ide_taskfile *tf = &task.tf; - int lba48 = (drive->addressing == 1) ? 1 : 0; - - memset(&task, 0, sizeof(task)); - if (lba48) - task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA | - IDE_TFLAG_LBA48; - else - task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE; - - ide_tf_read(drive, &task); - - if (lba48 || (tf->device & ATA_LBA)) - printk(", LBAsect=%llu", - (unsigned long long)ide_get_lba_addr(tf, lba48)); - else - printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam, - tf->device & 0xf, tf->lbal); -} + ide_hwif_t *hwif = HWIF(drive); + unsigned long flags; + u8 err = 0; -static void ide_dump_ata_error(ide_drive_t *drive, u8 err) -{ - printk("{ "); - if (err & ABRT_ERR) printk("DriveStatusError "); - if (err & ICRC_ERR) - printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); - if (err & ECC_ERR) printk("UncorrectableError "); - if (err & ID_ERR) printk("SectorIdNotFound "); - if (err & TRK0_ERR) printk("TrackZeroNotFound "); - if (err & MARK_ERR) printk("AddrMarkNotFound "); - printk("}"); - if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || - (err & (ECC_ERR|ID_ERR|MARK_ERR))) { - ide_dump_sector(drive); - if (HWGROUP(drive) && HWGROUP(drive)->rq) - printk(", sector=%llu", - (unsigned long long)HWGROUP(drive)->rq->sector); + local_irq_save(flags); + printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); + if (stat & BUSY_STAT) + printk("Busy "); + else { + if (stat & READY_STAT) printk("DriveReady "); + if (stat & WRERR_STAT) printk("DeviceFault "); + if (stat & SEEK_STAT) printk("SeekComplete "); + if (stat & DRQ_STAT) printk("DataRequest "); + if (stat & ECC_STAT) printk("CorrectedError "); + if (stat & INDEX_STAT) printk("Index "); + if (stat & ERR_STAT) printk("Error "); } - printk("\n"); -} - -static void ide_dump_atapi_error(ide_drive_t *drive, u8 err) -{ - printk("{ "); - if (err & ILI_ERR) printk("IllegalLengthIndication "); - if (err & EOM_ERR) printk("EndOfMedia "); - if (err & ABRT_ERR) printk("AbortedCommand "); - if (err & MCR_ERR) printk("MediaChangeRequested "); - if (err & LFS_ERR) printk("LastFailedSense=0x%02x ", - (err & LFS_ERR) >> 4); printk("}\n"); + if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { + err = hwif->INB(IDE_ERROR_REG); + printk("%s: %s: error=0x%02x { ", drive->name, msg, err); + if (err & ABRT_ERR) printk("DriveStatusError "); + if (err & ICRC_ERR) + printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); + if (err & ECC_ERR) printk("UncorrectableError "); + if (err & ID_ERR) printk("SectorIdNotFound "); + if (err & TRK0_ERR) printk("TrackZeroNotFound "); + if (err & MARK_ERR) printk("AddrMarkNotFound "); + printk("}"); + if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || + (err & (ECC_ERR|ID_ERR|MARK_ERR))) { + if (drive->addressing == 1) { + __u64 sectors = 0; + u32 low = 0, high = 0; + hwif->OUTB(drive->ctl&~0x80, IDE_CONTROL_REG); + low = ide_read_24(drive); + hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); + high = ide_read_24(drive); + sectors = ((__u64)high << 24) | low; + printk(", LBAsect=%llu, high=%d, low=%d", + (unsigned long long) sectors, + high, low); + } else { + u8 cur = hwif->INB(IDE_SELECT_REG); + if (cur & 0x40) { /* using LBA? */ + printk(", LBAsect=%ld", (unsigned long) + ((cur&0xf)<<24) + |(hwif->INB(IDE_HCYL_REG)<<16) + |(hwif->INB(IDE_LCYL_REG)<<8) + | hwif->INB(IDE_SECTOR_REG)); + } else { + printk(", CHS=%d/%d/%d", + (hwif->INB(IDE_HCYL_REG)<<8) + + hwif->INB(IDE_LCYL_REG), + cur & 0xf, + hwif->INB(IDE_SECTOR_REG)); + } + } + if (HWGROUP(drive) && HWGROUP(drive)->rq) + printk(", sector=%llu", + (unsigned long long)HWGROUP(drive)->rq->sector); + } + printk("\n"); + } + ide_dump_opcode(drive); + local_irq_restore(flags); + return err; } /** - * ide_dump_status - translate ATA/ATAPI error + * ide_dump_atapi_status - print human readable atapi status * @drive: drive that status applies to * @msg: text message to print * @stat: status byte to decode * * Error reporting, in human readable form (luxurious, but a memory hog). - * Combines the drive name, message and status byte to provide a - * user understandable explanation of the device error. */ -u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) +static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat) { unsigned long flags; - u8 err = 0; + atapi_status_t status; + atapi_error_t error; + + status.all = stat; + error.all = 0; local_irq_save(flags); printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); - if (stat & BUSY_STAT) + if (status.b.bsy) printk("Busy "); else { - if (stat & READY_STAT) printk("DriveReady "); - if (stat & WRERR_STAT) printk("DeviceFault "); - if (stat & SEEK_STAT) printk("SeekComplete "); - if (stat & DRQ_STAT) printk("DataRequest "); - if (stat & ECC_STAT) printk("CorrectedError "); - if (stat & INDEX_STAT) printk("Index "); - if (stat & ERR_STAT) printk("Error "); + if (status.b.drdy) printk("DriveReady "); + if (status.b.df) printk("DeviceFault "); + if (status.b.dsc) printk("SeekComplete "); + if (status.b.drq) printk("DataRequest "); + if (status.b.corr) printk("CorrectedError "); + if (status.b.idx) printk("Index "); + if (status.b.check) printk("Error "); } printk("}\n"); - if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { - err = drive->hwif->INB(IDE_ERROR_REG); - printk("%s: %s: error=0x%02x ", drive->name, msg, err); - if (drive->media == ide_disk) - ide_dump_ata_error(drive, err); - else - ide_dump_atapi_error(drive, err); + if (status.b.check && !status.b.bsy) { + error.all = HWIF(drive)->INB(IDE_ERROR_REG); + printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all); + if (error.b.ili) printk("IllegalLengthIndication "); + if (error.b.eom) printk("EndOfMedia "); + if (error.b.abrt) printk("AbortedCommand "); + if (error.b.mcr) printk("MediaChangeRequested "); + if (error.b.sense_key) printk("LastFailedSense=0x%02x ", + error.b.sense_key); + printk("}\n"); } ide_dump_opcode(drive); local_irq_restore(flags); - return err; + return error.all; +} + +/** + * ide_dump_status - translate ATA/ATAPI error + * @drive: drive the error occured on + * @msg: information string + * @stat: status byte + * + * Error reporting, in human readable form (luxurious, but a memory hog). + * Combines the drive name, message and status byte to provide a + * user understandable explanation of the device error. + */ + +u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) +{ + if (drive->media == ide_disk) + return ide_dump_ata_status(drive, msg, stat); + return ide_dump_atapi_status(drive, msg, stat); } EXPORT_SYMBOL(ide_dump_status); diff --git a/trunk/drivers/ide/ide-probe.c b/trunk/drivers/ide/ide-probe.c index 0379d1f697cf..0cb3d2bb3ab9 100644 --- a/trunk/drivers/ide/ide-probe.c +++ b/trunk/drivers/ide/ide-probe.c @@ -95,10 +95,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive) #ifdef CONFIG_IDEDISK_MULTI_MODE id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; id->multsect_valid = id->multsect ? 1 : 0; - drive->mult_req = id->multsect_valid ? id->max_multsect : 0; + drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; drive->special.b.set_multmode = drive->mult_req ? 1 : 0; #else /* original, pre IDE-NFG, per request of AC */ - drive->mult_req = 0; + drive->mult_req = INITIAL_MULT_COUNT; if (drive->mult_req > id->max_multsect) drive->mult_req = id->max_multsect; if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) @@ -234,10 +234,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd) drive->media = ide_disk; printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" ); - - if (hwif->quirkproc) - drive->quirk_list = hwif->quirkproc(drive); - + QUIRK_LIST(drive); return; err_misc: @@ -833,8 +830,16 @@ static void probe_hwif(ide_hwif_t *hwif) drive->nice1 = 1; - if (hwif->ide_dma_on) + if (hwif->ide_dma_on) { + /* + * Force DMAing for the beginning of the check. + * Some chipsets appear to do interesting + * things, if not checked and cleared. + * PARANOIA!!! + */ + hwif->dma_off_quietly(drive); ide_set_dma(drive); + } } } @@ -963,6 +968,11 @@ static int ide_init_queue(ide_drive_t *drive) * Much of the code is for correctly detecting/handling irq sharing * and irq serialization situations. This is somewhat complex because * it handles static as well as dynamic (PCMCIA) IDE interfaces. + * + * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with + * interrupts completely disabled. This can be bad for interrupt latency, + * but anything else has led to problems on some machines. We re-enable + * interrupts as much as we can safely do in most places. */ static int init_irq (ide_hwif_t *hwif) { @@ -1045,13 +1055,17 @@ static int init_irq (ide_hwif_t *hwif) * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { - int sa = 0; + int sa = IRQF_DISABLED; #if defined(__mc68000__) || defined(CONFIG_APUS) sa = IRQF_SHARED; #endif /* __mc68000__ || CONFIG_APUS */ - if (IDE_CHIPSET_IS_PCI(hwif->chipset)) + if (IDE_CHIPSET_IS_PCI(hwif->chipset)) { sa = IRQF_SHARED; +#ifndef CONFIG_IDEPCI_SHARE_IRQ + sa |= IRQF_DISABLED; +#endif /* CONFIG_IDEPCI_SHARE_IRQ */ + } if (hwif->io_ports[IDE_CONTROL_OFFSET]) /* clear nIEN */ diff --git a/trunk/drivers/ide/ide-tape.c b/trunk/drivers/ide/ide-tape.c index 3cbca3f4628a..1495792d7917 100644 --- a/trunk/drivers/ide/ide-tape.c +++ b/trunk/drivers/ide/ide-tape.c @@ -614,6 +614,16 @@ typedef struct os_dat_s { /*************************** End of tunable parameters ***********************/ +/* + * Debugging/Performance analysis + * + * I/O trace support + */ +#define USE_IOTRACE 0 +#if USE_IOTRACE +#define IO_IDETAPE_FIFO 500 +#endif + /* * Read/Write error simulation */ @@ -1808,8 +1818,9 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive) idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc; struct request *rq; + atapi_error_t error; - (void)drive->hwif->INB(IDE_ERROR_REG); + error.all = HWIF(drive)->INB(IDE_ERROR_REG); pc = idetape_next_pc_storage(drive); rq = idetape_next_rq_storage(drive); idetape_create_request_sense_cmd(pc); @@ -1847,13 +1858,15 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; + atapi_status_t status; + atapi_bcount_t bcount; + atapi_ireason_t ireason; idetape_pc_t *pc = tape->pc; + unsigned int temp; #if SIMULATE_ERRORS static int error_sim_count = 0; #endif - u16 bcount; - u8 stat, ireason; #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 4) @@ -1862,10 +1875,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_LOG */ /* Clear the interrupt */ - stat = hwif->INB(IDE_STATUS_REG); + status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { - if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) { + if (HWIF(drive)->ide_dma_end(drive) || status.b.check) { /* * A DMA error is sometimes expected. For example, * if the tape is crossing a filemark during a @@ -1899,7 +1912,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) } /* No more interrupts */ - if ((stat & DRQ_STAT) == 0) { + if (!status.b.drq) { #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred); @@ -1914,13 +1927,12 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) (++error_sim_count % 100) == 0) { printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name); - stat |= ERR_STAT; + status.b.check = 1; } #endif - if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) - stat &= ~ERR_STAT; - if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) { - /* Error detected */ + if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) + status.b.check = 0; + if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 1) printk(KERN_INFO "ide-tape: %s: I/O error\n", @@ -1939,7 +1951,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) } pc->error = 0; if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) && - (stat & SEEK_STAT) == 0) { + !status.b.dsc) { /* Media access command */ tape->dsc_polling_start = jiffies; tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST; @@ -1961,30 +1973,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) return ide_do_reset(drive); } /* Get the number of bytes to transfer on this interrupt. */ - bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | - hwif->INB(IDE_BCOUNTL_REG); + bcount.b.high = hwif->INB(IDE_BCOUNTH_REG); + bcount.b.low = hwif->INB(IDE_BCOUNTL_REG); - ireason = hwif->INB(IDE_IREASON_REG); + ireason.all = hwif->INB(IDE_IREASON_REG); - if (ireason & CD) { + if (ireason.b.cod) { printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); return ide_do_reset(drive); } - if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) { + if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk(KERN_ERR "ide-tape: We wanted to %s, ", - (ireason & IO) ? "Write" : "Read"); + ireason.b.io ? "Write":"Read"); printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n", - (ireason & IO) ? "Read" : "Write"); + ireason.b.io ? "Read":"Write"); return ide_do_reset(drive); } if (!test_bit(PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ - temp = pc->actually_transferred + bcount; + temp = pc->actually_transferred + bcount.all; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); - idetape_discard_data(drive, bcount); + idetape_discard_data(drive, bcount.all); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; } @@ -1996,26 +2008,23 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) } if (test_bit(PC_WRITING, &pc->flags)) { if (pc->bh != NULL) - idetape_output_buffers(drive, pc, bcount); + idetape_output_buffers(drive, pc, bcount.all); else /* Write the current buffer */ - hwif->atapi_output_bytes(drive, pc->current_position, - bcount); + HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all); } else { if (pc->bh != NULL) - idetape_input_buffers(drive, pc, bcount); + idetape_input_buffers(drive, pc, bcount.all); else /* Read the current buffer */ - hwif->atapi_input_bytes(drive, pc->current_position, - bcount); + HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all); } /* Update the current position */ - pc->actually_transferred += bcount; - pc->current_position += bcount; + pc->actually_transferred += bcount.all; + pc->current_position += bcount.all; #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes " - "on that interrupt\n", pc->c[0], bcount); + printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all); #endif /* And set the interrupt handler again */ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); @@ -2069,28 +2078,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; + atapi_ireason_t ireason; int retries = 100; ide_startstop_t startstop; - u8 ireason; if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = hwif->INB(IDE_IREASON_REG); - while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) { + ireason.all = hwif->INB(IDE_IREASON_REG); + while (retries-- && (!ireason.b.cod || ireason.b.io)) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing " "a packet command, retrying\n"); udelay(100); - ireason = hwif->INB(IDE_IREASON_REG); + ireason.all = hwif->INB(IDE_IREASON_REG); if (retries == 0) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while " "issuing a packet command, ignoring\n"); - ireason |= CD; - ireason &= ~IO; + ireason.b.cod = 1; + ireason.b.io = 0; } } - if ((ireason & CD) == 0 || (ireason & IO)) { + if (!ireason.b.cod || ireason.b.io) { printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing " "a packet command\n"); return ide_do_reset(drive); @@ -2111,8 +2120,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape { ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; + atapi_bcount_t bcount; int dma_ok = 0; - u16 bcount; #if IDETAPE_DEBUG_BUGS if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && @@ -2161,7 +2170,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape pc->actually_transferred = 0; pc->current_position = pc->buffer; /* Request to transfer the entire buffer at once */ - bcount = pc->request_transfer; + bcount.all = pc->request_transfer; if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { printk(KERN_WARNING "ide-tape: DMA disabled, " @@ -2171,9 +2180,12 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) dma_ok = !hwif->dma_setup(drive); - ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK | - IDE_TFLAG_OUT_DEVICE, bcount, dma_ok); - + if (IDE_CONTROL_REG) + hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG); /* Use PIO/DMA */ + hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG); + hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG); + hwif->OUTB(drive->select.all, IDE_SELECT_REG); if (dma_ok) /* Will begin DMA later */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { @@ -2283,11 +2295,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; - u8 stat; + atapi_status_t status; - stat = drive->hwif->INB(IDE_STATUS_REG); - if (stat & SEEK_STAT) { - if (stat & ERR_STAT) { + status.all = HWIF(drive)->INB(IDE_STATUS_REG); + if (status.b.dsc) { + if (status.b.check) { /* Error detected */ if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD) printk(KERN_ERR "ide-tape: %s: I/O error, ", @@ -2405,7 +2417,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = NULL; struct request *postponed_rq = tape->postponed_rq; - u8 stat; + atapi_status_t status; #if IDETAPE_DEBUG_LOG #if 0 @@ -2453,7 +2465,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, * If the tape is still busy, postpone our request and service * the other device meanwhile. */ - stat = drive->hwif->INB(IDE_STATUS_REG); + status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2)) set_bit(IDETAPE_IGNORE_DSC, &tape->flags); @@ -2469,7 +2481,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); calculate_speeds(drive); if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) && - (stat & SEEK_STAT) == 0) { + !status.b.dsc) { if (postponed_rq == NULL) { tape->dsc_polling_start = jiffies; tape->dsc_polling_frequency = tape->best_dsc_rw_frequency; @@ -2490,6 +2502,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, } if (rq->cmd[0] & REQ_IDETAPE_READ) { tape->buffer_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); @@ -2497,6 +2512,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, } if (rq->cmd[0] & REQ_IDETAPE_WRITE) { tape->buffer_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); @@ -3223,6 +3241,9 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks) idetape_switch_buffers(tape, new_stage); idetape_add_stage_tail(drive, new_stage); tape->pipeline_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif calculate_speeds(drive); /* @@ -3472,6 +3493,9 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) idetape_remove_stage_head(drive); spin_unlock_irqrestore(&tape->spinlock, flags); tape->pipeline_head++; +#if USE_IOTRACE + IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); +#endif calculate_speeds(drive); } #if IDETAPE_DEBUG_BUGS diff --git a/trunk/drivers/ide/ide-taskfile.c b/trunk/drivers/ide/ide-taskfile.c index 2d63ea9ee61b..2b60f1b0437e 100644 --- a/trunk/drivers/ide/ide-taskfile.c +++ b/trunk/drivers/ide/ide-taskfile.c @@ -63,78 +63,65 @@ static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount) } } -void ide_tf_load(ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = drive->hwif; - struct ide_taskfile *tf = &task->tf; - u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; - - if (task->tf_flags & IDE_TFLAG_FLAGGED) - HIHI = 0xFF; - -#ifdef DEBUG - printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x " - "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n", - drive->name, tf->feature, tf->nsect, tf->lbal, - tf->lbam, tf->lbah, tf->device, tf->command); -#endif - - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - - if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0) - SELECT_MASK(drive, 0); - - if (task->tf_flags & IDE_TFLAG_OUT_DATA) - hwif->OUTW((tf->hob_data << 8) | tf->data, IDE_DATA_REG); - - if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) - hwif->OUTB(tf->hob_feature, IDE_FEATURE_REG); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) - hwif->OUTB(tf->hob_nsect, IDE_NSECTOR_REG); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) - hwif->OUTB(tf->hob_lbal, IDE_SECTOR_REG); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) - hwif->OUTB(tf->hob_lbam, IDE_LCYL_REG); - if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) - hwif->OUTB(tf->hob_lbah, IDE_HCYL_REG); - - if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) - hwif->OUTB(tf->feature, IDE_FEATURE_REG); - if (task->tf_flags & IDE_TFLAG_OUT_NSECT) - hwif->OUTB(tf->nsect, IDE_NSECTOR_REG); - if (task->tf_flags & IDE_TFLAG_OUT_LBAL) - hwif->OUTB(tf->lbal, IDE_SECTOR_REG); - if (task->tf_flags & IDE_TFLAG_OUT_LBAM) - hwif->OUTB(tf->lbam, IDE_LCYL_REG); - if (task->tf_flags & IDE_TFLAG_OUT_LBAH) - hwif->OUTB(tf->lbah, IDE_HCYL_REG); - - if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) - hwif->OUTB((tf->device & HIHI) | drive->select.all, IDE_SELECT_REG); -} - int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) { ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); - args.tf.nsect = 0x01; + args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; if (drive->media == ide_disk) - args.tf.command = WIN_IDENTIFY; + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_IDENTIFY; else - args.tf.command = WIN_PIDENTIFY; - args.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; - args.data_phase = TASKFILE_IN; - return ide_raw_taskfile(drive, &args, buf, 1); + args.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY; + args.command_type = IDE_DRIVE_TASK_IN; + args.data_phase = TASKFILE_IN; + args.handler = &task_in_intr; + return ide_raw_taskfile(drive, &args, buf); } -static int inline task_dma_ok(ide_task_t *task) +ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) { - if (blk_fs_request(task->rq) || (task->tf_flags & IDE_TFLAG_FLAGGED)) - return 1; + ide_hwif_t *hwif = HWIF(drive); + task_struct_t *taskfile = (task_struct_t *) task->tfRegister; + hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; + u8 HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF; + + /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ + if (IDE_CONTROL_REG) { + /* clear nIEN */ + hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + } + SELECT_MASK(drive, 0); + + if (drive->addressing == 1) { + hwif->OUTB(hobfile->feature, IDE_FEATURE_REG); + hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG); + hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG); + hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG); + hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG); + } + + hwif->OUTB(taskfile->feature, IDE_FEATURE_REG); + hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); + hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG); + hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); + hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); + + hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); + + if (task->handler != NULL) { + if (task->prehandler != NULL) { + hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); + ndelay(400); /* FIXME */ + return task->prehandler(drive, task->rq); + } + ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); + return ide_started; + } + + if (!drive->using_dma) + return ide_stopped; - switch (task->tf.command) { + switch (taskfile->command) { case WIN_WRITEDMA_ONCE: case WIN_WRITEDMA: case WIN_WRITEDMA_EXT: @@ -142,79 +129,24 @@ static int inline task_dma_ok(ide_task_t *task) case WIN_READDMA: case WIN_READDMA_EXT: case WIN_IDENTIFY_DMA: - return 1; - } - - return 0; -} - -static ide_startstop_t task_no_data_intr(ide_drive_t *); -static ide_startstop_t set_geometry_intr(ide_drive_t *); -static ide_startstop_t recal_intr(ide_drive_t *); -static ide_startstop_t set_multmode_intr(ide_drive_t *); -static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); -static ide_startstop_t task_in_intr(ide_drive_t *); - -ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = HWIF(drive); - struct ide_taskfile *tf = &task->tf; - ide_handler_t *handler = NULL; - - if (task->data_phase == TASKFILE_MULTI_IN || - task->data_phase == TASKFILE_MULTI_OUT) { - if (!drive->mult_count) { - printk(KERN_ERR "%s: multimode not set!\n", - drive->name); - return ide_stopped; - } - } - - if (task->tf_flags & IDE_TFLAG_FLAGGED) - task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS; - - if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) - ide_tf_load(drive, task); - - switch (task->data_phase) { - case TASKFILE_MULTI_OUT: - case TASKFILE_OUT: - hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG); - ndelay(400); /* FIXME */ - return pre_task_out_intr(drive, task->rq); - case TASKFILE_MULTI_IN: - case TASKFILE_IN: - handler = task_in_intr; - /* fall-through */ - case TASKFILE_NO_DATA: - if (handler == NULL) - handler = task_no_data_intr; - /* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */ - if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) { - switch (tf->command) { - case WIN_SPECIFY: handler = set_geometry_intr; break; - case WIN_RESTORE: handler = recal_intr; break; - case WIN_SETMULT: handler = set_multmode_intr; break; + if (!hwif->dma_setup(drive)) { + hwif->dma_exec_cmd(drive, taskfile->command); + hwif->dma_start(drive); + return ide_started; } - } - ide_execute_command(drive, tf->command, handler, - WAIT_WORSTCASE, NULL); - return ide_started; - default: - if (task_dma_ok(task) == 0 || drive->using_dma == 0 || - hwif->dma_setup(drive)) - return ide_stopped; - hwif->dma_exec_cmd(drive, tf->command); - hwif->dma_start(drive); - return ide_started; + break; + default: + if (task->handler == NULL) + return ide_stopped; } + + return ide_stopped; } -EXPORT_SYMBOL_GPL(do_rw_taskfile); /* * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. */ -static ide_startstop_t set_multmode_intr(ide_drive_t *drive) +ide_startstop_t set_multmode_intr (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 stat; @@ -232,7 +164,7 @@ static ide_startstop_t set_multmode_intr(ide_drive_t *drive) /* * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. */ -static ide_startstop_t set_geometry_intr(ide_drive_t *drive) +ide_startstop_t set_geometry_intr (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); int retries = 5; @@ -255,7 +187,7 @@ static ide_startstop_t set_geometry_intr(ide_drive_t *drive) /* * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */ -static ide_startstop_t recal_intr(ide_drive_t *drive) +ide_startstop_t recal_intr (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 stat; @@ -268,7 +200,7 @@ static ide_startstop_t recal_intr(ide_drive_t *drive) /* * Handler for commands without a data phase */ -static ide_startstop_t task_no_data_intr(ide_drive_t *drive) +ide_startstop_t task_no_data_intr (ide_drive_t *drive) { ide_task_t *args = HWGROUP(drive)->rq->special; ide_hwif_t *hwif = HWIF(drive); @@ -285,6 +217,8 @@ static ide_startstop_t task_no_data_intr(ide_drive_t *drive) return ide_stopped; } +EXPORT_SYMBOL(task_no_data_intr); + static u8 wait_drive_not_busy(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -429,7 +363,7 @@ static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *task = rq->special; - if (task->tf_flags & IDE_TFLAG_FLAGGED) { + if (task->tf_out_flags.all) { u8 err = drive->hwif->INB(IDE_ERROR_REG); ide_end_drive_cmd(drive, stat, err); return; @@ -448,7 +382,7 @@ static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) /* * Handler for command with PIO data-in phase (Read/Read Multiple). */ -static ide_startstop_t task_in_intr(ide_drive_t *drive) +ide_startstop_t task_in_intr (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct request *rq = HWGROUP(drive)->rq; @@ -479,6 +413,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive) return ide_started; } +EXPORT_SYMBOL(task_in_intr); /* * Handler for command with PIO data-out phase (Write/Write Multiple). @@ -508,7 +443,7 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive) return ide_started; } -static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq) +ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; @@ -529,8 +464,9 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq) return ide_started; } +EXPORT_SYMBOL(pre_task_out_intr); -int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) +static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) { struct request rq; @@ -545,27 +481,36 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) * if we would find a solution to transfer any size. * To support special commands like READ LONG. */ - rq.hard_nr_sectors = rq.nr_sectors = nsect; - rq.hard_cur_sectors = rq.current_nr_sectors = nsect; + if (args->command_type != IDE_DRIVE_TASK_NO_DATA) { + if (data_size == 0) + rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; + else + rq.nr_sectors = data_size / SECTOR_SIZE; + + if (!rq.nr_sectors) { + printk(KERN_ERR "%s: in/out command without data\n", + drive->name); + return -EFAULT; + } - if (task->tf_flags & IDE_TFLAG_WRITE) - rq.cmd_flags |= REQ_RW; + rq.hard_nr_sectors = rq.nr_sectors; + rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors; - rq.special = task; - task->rq = &rq; + if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) + rq.cmd_flags |= REQ_RW; + } + rq.special = args; + args->rq = &rq; return ide_do_drive_cmd(drive, &rq, ide_wait); } -EXPORT_SYMBOL(ide_raw_taskfile); - -int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task) +int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf) { - task->data_phase = TASKFILE_NO_DATA; - - return ide_raw_taskfile(drive, task, NULL, 0); + return ide_diag_taskfile(drive, args, 0, buf); } -EXPORT_SYMBOL_GPL(ide_no_data_taskfile); + +EXPORT_SYMBOL(ide_raw_taskfile); #ifdef CONFIG_IDE_TASK_IOCTL int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) @@ -574,12 +519,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) ide_task_t args; u8 *outbuf = NULL; u8 *inbuf = NULL; - u8 *data_buf = NULL; + task_ioreg_t *argsptr = args.tfRegister; + task_ioreg_t *hobsptr = args.hobRegister; int err = 0; int tasksize = sizeof(struct ide_task_request_s); unsigned int taskin = 0; unsigned int taskout = 0; - u16 nsect = 0; u8 io_32bit = drive->io_32bit; char __user *buf = (char __user *)arg; @@ -627,52 +572,24 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } memset(&args, 0, sizeof(ide_task_t)); + memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); + memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE); - memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2); - memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); - - args.data_phase = req_task->data_phase; - - args.tf_flags = IDE_TFLAG_OUT_DEVICE; - if (drive->addressing == 1) - args.tf_flags |= IDE_TFLAG_LBA48; - - if (req_task->out_flags.all) { - args.tf_flags |= IDE_TFLAG_FLAGGED; - - if (req_task->out_flags.b.data) - args.tf_flags |= IDE_TFLAG_OUT_DATA; - - if (req_task->out_flags.b.nsector_hob) - args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT; - if (req_task->out_flags.b.sector_hob) - args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL; - if (req_task->out_flags.b.lcyl_hob) - args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM; - if (req_task->out_flags.b.hcyl_hob) - args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH; - - if (req_task->out_flags.b.error_feature) - args.tf_flags |= IDE_TFLAG_OUT_FEATURE; - if (req_task->out_flags.b.nsector) - args.tf_flags |= IDE_TFLAG_OUT_NSECT; - if (req_task->out_flags.b.sector) - args.tf_flags |= IDE_TFLAG_OUT_LBAL; - if (req_task->out_flags.b.lcyl) - args.tf_flags |= IDE_TFLAG_OUT_LBAM; - if (req_task->out_flags.b.hcyl) - args.tf_flags |= IDE_TFLAG_OUT_LBAH; - } else { - args.tf_flags |= IDE_TFLAG_OUT_TF; - if (args.tf_flags & IDE_TFLAG_LBA48) - args.tf_flags |= IDE_TFLAG_OUT_HOB; - } - - if (req_task->in_flags.b.data) - args.tf_flags |= IDE_TFLAG_IN_DATA; + args.tf_in_flags = req_task->in_flags; + args.tf_out_flags = req_task->out_flags; + args.data_phase = req_task->data_phase; + args.command_type = req_task->req_cmd; drive->io_32bit = 0; switch(req_task->data_phase) { + case TASKFILE_OUT_DMAQ: + case TASKFILE_OUT_DMA: + err = ide_diag_taskfile(drive, &args, taskout, outbuf); + break; + case TASKFILE_IN_DMAQ: + case TASKFILE_IN_DMA: + err = ide_diag_taskfile(drive, &args, taskin, inbuf); + break; case TASKFILE_MULTI_OUT: if (!drive->mult_count) { /* (hs): give up if multcount is not set */ @@ -684,11 +601,9 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } /* fall through */ case TASKFILE_OUT: - /* fall through */ - case TASKFILE_OUT_DMAQ: - case TASKFILE_OUT_DMA: - nsect = taskout / SECTOR_SIZE; - data_buf = outbuf; + args.prehandler = &pre_task_out_intr; + args.handler = &task_out_intr; + err = ide_diag_taskfile(drive, &args, taskout, outbuf); break; case TASKFILE_MULTI_IN: if (!drive->mult_count) { @@ -701,46 +616,22 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } /* fall through */ case TASKFILE_IN: - /* fall through */ - case TASKFILE_IN_DMAQ: - case TASKFILE_IN_DMA: - nsect = taskin / SECTOR_SIZE; - data_buf = inbuf; + args.handler = &task_in_intr; + err = ide_diag_taskfile(drive, &args, taskin, inbuf); break; case TASKFILE_NO_DATA: + args.handler = &task_no_data_intr; + err = ide_diag_taskfile(drive, &args, 0, NULL); break; default: err = -EFAULT; goto abort; } - if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA) - nsect = 0; - else if (!nsect) { - nsect = (args.tf.hob_nsect << 8) | args.tf.nsect; - - if (!nsect) { - printk(KERN_ERR "%s: in/out command without data\n", - drive->name); - err = -EFAULT; - goto abort; - } - } - - if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) - args.tf_flags |= IDE_TFLAG_WRITE; - - err = ide_raw_taskfile(drive, &args, data_buf, nsect); - - memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2); - memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE); - - if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) && - req_task->in_flags.all == 0) { - req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; - if (drive->addressing == 1) - req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); - } + memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE); + memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE); + req_task->in_flags = args.tf_in_flags; + req_task->out_flags = args.tf_out_flags; if (copy_to_user(buf, req_task, tasksize)) { err = -EFAULT; @@ -797,7 +688,6 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) u8 xfer_rate = 0; int argsize = 4; ide_task_t tfargs; - struct ide_taskfile *tf = &tfargs.tf; if (NULL == (void *) arg) { struct request rq; @@ -809,10 +699,13 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) return -EFAULT; memset(&tfargs, 0, sizeof(ide_task_t)); - tf->feature = args[2]; - tf->nsect = args[3]; - tf->lbal = args[1]; - tf->command = args[0]; + tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2]; + tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3]; + tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1]; + tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00; + tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00; + tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0]; if (args[3]) { argsize = 4 + (SECTOR_WORDS * 4 * args[3]); @@ -841,28 +734,135 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) return err; } +static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf) +{ + struct request rq; + + ide_init_drive_cmd(&rq); + rq.cmd_type = REQ_TYPE_ATA_TASK; + rq.buffer = buf; + return ide_do_drive_cmd(drive, &rq, ide_wait); +} + int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) { void __user *p = (void __user *)arg; int err = 0; - u8 args[7]; - ide_task_t task; + u8 args[7], *argbuf = args; + int argsize = 7; if (copy_from_user(args, p, 7)) return -EFAULT; + err = ide_wait_cmd_task(drive, argbuf); + if (copy_to_user(p, argbuf, argsize)) + err = -EFAULT; + return err; +} - memset(&task, 0, sizeof(task)); - memcpy(&task.tf_array[7], &args[1], 6); - task.tf.command = args[0]; - task.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; +/* + * NOTICE: This is additions from IBM to provide a discrete interface, + * for selective taskregister access operations. Nice JOB Klaus!!! + * Glad to be able to work and co-develop this with you and IBM. + */ +ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = HWIF(drive); + task_struct_t *taskfile = (task_struct_t *) task->tfRegister; + hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; - err = ide_no_data_taskfile(drive, &task); + if (task->data_phase == TASKFILE_MULTI_IN || + task->data_phase == TASKFILE_MULTI_OUT) { + if (!drive->mult_count) { + printk(KERN_ERR "%s: multimode not set!\n", drive->name); + return ide_stopped; + } + } - args[0] = task.tf.command; - memcpy(&args[1], &task.tf_array[7], 6); + /* + * (ks) Check taskfile in flags. + * If set, then execute as it is defined. + * If not set, then define default settings. + * The default values are: + * read all taskfile registers (except data) + * read the hob registers (sector, nsector, lcyl, hcyl) + */ + if (task->tf_in_flags.all == 0) { + task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; + if (drive->addressing == 1) + task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); + } - if (copy_to_user(p, args, 7)) - err = -EFAULT; + /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ + if (IDE_CONTROL_REG) + /* clear nIEN */ + hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + SELECT_MASK(drive, 0); + + if (task->tf_out_flags.b.data) { + u16 data = taskfile->data + (hobfile->data << 8); + hwif->OUTW(data, IDE_DATA_REG); + } + + /* (ks) send hob registers first */ + if (task->tf_out_flags.b.nsector_hob) + hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG); + if (task->tf_out_flags.b.sector_hob) + hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG); + if (task->tf_out_flags.b.lcyl_hob) + hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG); + if (task->tf_out_flags.b.hcyl_hob) + hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG); + + /* (ks) Send now the standard registers */ + if (task->tf_out_flags.b.error_feature) + hwif->OUTB(taskfile->feature, IDE_FEATURE_REG); + /* refers to number of sectors to transfer */ + if (task->tf_out_flags.b.nsector) + hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); + /* refers to sector offset or start sector */ + if (task->tf_out_flags.b.sector) + hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG); + if (task->tf_out_flags.b.lcyl) + hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); + if (task->tf_out_flags.b.hcyl) + hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); + + /* + * (ks) In the flagged taskfile approch, we will use all specified + * registers and the register value will not be changed, except the + * select bit (master/slave) in the drive_head register. We must make + * sure that the desired drive is selected. + */ + hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG); + switch(task->data_phase) { - return err; + case TASKFILE_OUT_DMAQ: + case TASKFILE_OUT_DMA: + case TASKFILE_IN_DMAQ: + case TASKFILE_IN_DMA: + if (!drive->using_dma) + break; + + if (!hwif->dma_setup(drive)) { + hwif->dma_exec_cmd(drive, taskfile->command); + hwif->dma_start(drive); + return ide_started; + } + break; + + default: + if (task->handler == NULL) + return ide_stopped; + + /* Issue the command */ + if (task->prehandler) { + hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); + ndelay(400); /* FIXME */ + return task->prehandler(drive, task->rq); + } + ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); + return ide_started; + } + + return ide_stopped; } diff --git a/trunk/drivers/ide/ide.c b/trunk/drivers/ide/ide.c index c6d4f630e18a..54943da6e4e5 100644 --- a/trunk/drivers/ide/ide.c +++ b/trunk/drivers/ide/ide.c @@ -424,6 +424,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->reset_poll = tmp_hwif->reset_poll; hwif->pre_reset = tmp_hwif->pre_reset; hwif->resetproc = tmp_hwif->resetproc; + hwif->intrproc = tmp_hwif->intrproc; hwif->maskproc = tmp_hwif->maskproc; hwif->quirkproc = tmp_hwif->quirkproc; hwif->busproc = tmp_hwif->busproc; @@ -467,6 +468,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) #endif hwif->dma_base = tmp_hwif->dma_base; + hwif->dma_master = tmp_hwif->dma_master; hwif->dma_command = tmp_hwif->dma_command; hwif->dma_vendor1 = tmp_hwif->dma_vendor1; hwif->dma_status = tmp_hwif->dma_status; @@ -600,6 +602,7 @@ void ide_unregister(unsigned int index) (void) ide_release_dma(hwif); hwif->dma_base = 0; + hwif->dma_master = 0; hwif->dma_command = 0; hwif->dma_vendor1 = 0; hwif->dma_status = 0; @@ -851,7 +854,8 @@ int set_using_dma(ide_drive_t *drive, int arg) err = 0; if (arg) { - if (ide_set_dma(drive)) + hwif->dma_off_quietly(drive); + if (ide_set_dma(drive) || hwif->ide_dma_on(drive)) err = -EIO; } else ide_dma_off(drive); diff --git a/trunk/drivers/ide/mips/au1xxx-ide.c b/trunk/drivers/ide/mips/au1xxx-ide.c index a4d0d4ca73d0..a4ce3ba15d61 100644 --- a/trunk/drivers/ide/mips/au1xxx-ide.c +++ b/trunk/drivers/ide/mips/au1xxx-ide.c @@ -198,6 +198,8 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed) break; #endif + default: + return; } au_writel(mem_sttime,MEM_STTIME2); diff --git a/trunk/drivers/ide/pci/aec62xx.c b/trunk/drivers/ide/pci/aec62xx.c index 7f4d1857d555..44268504ae43 100644 --- a/trunk/drivers/ide/pci/aec62xx.c +++ b/trunk/drivers/ide/pci/aec62xx.c @@ -202,7 +202,6 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, @@ -212,7 +211,6 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA | - IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, @@ -222,8 +220,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_ABUSE_SET_DMA_MODE, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA4, @@ -231,9 +228,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .name = "AEC6280", .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_ABUSE_SET_DMA_MODE | - IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -242,9 +237,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_ABUSE_SET_DMA_MODE | - IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, diff --git a/trunk/drivers/ide/pci/alim15x3.c b/trunk/drivers/ide/pci/alim15x3.c index 49aa82e412b6..ce293936af4b 100644 --- a/trunk/drivers/ide/pci/alim15x3.c +++ b/trunk/drivers/ide/pci/alim15x3.c @@ -402,6 +402,9 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed) u8 tmpbyte = 0x00; int m5229_udma = (hwif->channel) ? 0x57 : 0x56; + if (speed < XFER_PIO_0) + return; + if (speed == XFER_UDMA_6) speed1 = 0x47; diff --git a/trunk/drivers/ide/pci/amd74xx.c b/trunk/drivers/ide/pci/amd74xx.c index cee51fdafcf6..8d4125ec252c 100644 --- a/trunk/drivers/ide/pci/amd74xx.c +++ b/trunk/drivers/ide/pci/amd74xx.c @@ -266,7 +266,6 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) #define IDE_HFLAGS_AMD \ (IDE_HFLAG_PIO_NO_BLACKLIST | \ IDE_HFLAG_PIO_NO_DOWNGRADE | \ - IDE_HFLAG_ABUSE_SET_DMA_MODE | \ IDE_HFLAG_POST_SET_MODE | \ IDE_HFLAG_IO_32BIT | \ IDE_HFLAG_UNMASK_IRQS | \ diff --git a/trunk/drivers/ide/pci/atiixp.c b/trunk/drivers/ide/pci/atiixp.c index 5ae26564fb72..ef8e0164ef7a 100644 --- a/trunk/drivers/ide/pci/atiixp.c +++ b/trunk/drivers/ide/pci/atiixp.c @@ -133,6 +133,9 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed) u32 tmp32; u16 tmp16; + if (speed < XFER_MW_DMA_0) + return; + spin_lock_irqsave(&atiixp_lock, flags); save_mdma_mode[drive->dn] = 0; diff --git a/trunk/drivers/ide/pci/cmd64x.c b/trunk/drivers/ide/pci/cmd64x.c index 0b1e9479f019..bc553337b1be 100644 --- a/trunk/drivers/ide/pci/cmd64x.c +++ b/trunk/drivers/ide/pci/cmd64x.c @@ -322,6 +322,8 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_0: program_cycle_times(drive, 480, 215); break; + default: + return; } if (speed >= XFER_SW_DMA_0) @@ -331,15 +333,14 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) static int cmd648_ide_dma_end (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned long base = hwif->dma_base - (hwif->channel * 8); int err = __ide_dma_end(drive); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - u8 mrdmode = inb(base + 1); + u8 mrdmode = inb(hwif->dma_master + 0x01); /* clear the interrupt bit */ outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask, - base + 1); + hwif->dma_master + 0x01); return err; } @@ -364,11 +365,10 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive) static int cmd648_ide_dma_test_irq (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned long base = hwif->dma_base - (hwif->channel * 8); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; u8 dma_stat = inb(hwif->dma_status); - u8 mrdmode = inb(base + 1); + u8 mrdmode = inb(hwif->dma_master + 0x01); #ifdef DEBUG printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n", diff --git a/trunk/drivers/ide/pci/cs5520.c b/trunk/drivers/ide/pci/cs5520.c index d1a91bcb5b29..0466462fd21b 100644 --- a/trunk/drivers/ide/pci/cs5520.c +++ b/trunk/drivers/ide/pci/cs5520.c @@ -137,7 +137,6 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) IDE_HFLAG_CS5520 | \ IDE_HFLAG_VDMA | \ IDE_HFLAG_NO_ATAPI_DMA | \ - IDE_HFLAG_ABUSE_SET_DMA_MODE |\ IDE_HFLAG_BOOTABLE, \ .pio_mask = ATA_PIO4, \ } diff --git a/trunk/drivers/ide/pci/cs5530.c b/trunk/drivers/ide/pci/cs5530.c index df5966b33460..547690395eee 100644 --- a/trunk/drivers/ide/pci/cs5530.c +++ b/trunk/drivers/ide/pci/cs5530.c @@ -116,6 +116,8 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode) case XFER_MW_DMA_0: timings = 0x00077771; break; case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; + default: + return; } basereg = CS5530_BASEREG(drive->hwif); reg = inl(basereg + 4); /* get drive0 config register */ diff --git a/trunk/drivers/ide/pci/cs5535.c b/trunk/drivers/ide/pci/cs5535.c index 50b3d7791f55..ddcbeba671e1 100644 --- a/trunk/drivers/ide/pci/cs5535.c +++ b/trunk/drivers/ide/pci/cs5535.c @@ -190,7 +190,7 @@ static const struct ide_port_info cs5535_chipset __devinitdata = { .name = "CS5535", .init_hwif = init_hwif_cs5535, .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE | - IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_BOOTABLE, + IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA4, diff --git a/trunk/drivers/ide/pci/hpt34x.c b/trunk/drivers/ide/pci/hpt34x.c index dfba0d13fcd3..ae6307fae4f9 100644 --- a/trunk/drivers/ide/pci/hpt34x.c +++ b/trunk/drivers/ide/pci/hpt34x.c @@ -129,18 +129,14 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) hwif->set_dma_mode = &hpt34x_set_mode; } -#define IDE_HFLAGS_HPT34X \ - (IDE_HFLAG_NO_ATAPI_DMA | \ - IDE_HFLAG_ABUSE_SET_DMA_MODE | \ - IDE_HFLAG_NO_AUTODMA) - static const struct ide_port_info hpt34x_chipsets[] __devinitdata = { { /* 0 */ .name = "HPT343", .init_chipset = init_chipset_hpt34x, .init_hwif = init_hwif_hpt34x, .extra = 16, - .host_flags = IDE_HFLAGS_HPT34X, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_NO_AUTODMA, .pio_mask = ATA_PIO5, }, { /* 1 */ @@ -148,7 +144,9 @@ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = { .init_chipset = init_chipset_hpt34x, .init_hwif = init_hwif_hpt34x, .extra = 16, - .host_flags = IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_NO_AUTODMA | + IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO5, #ifdef CONFIG_HPT34X_AUTODMA .swdma_mask = ATA_SWDMA2, diff --git a/trunk/drivers/ide/pci/hpt366.c b/trunk/drivers/ide/pci/hpt366.c index 3777fb8c8043..9fce25bdec8a 100644 --- a/trunk/drivers/ide/pci/hpt366.c +++ b/trunk/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.30 Dec 12, 2007 + * linux/drivers/ide/pci/hpt366.c Version 1.22 Dec 4, 2007 * * Copyright (C) 1999-2003 Andre Hedrick * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -88,7 +88,7 @@ * - rename all the register related variables consistently * - move all the interrupt twiddling code from the speedproc handlers into * init_hwif_hpt366(), also grouping all the DMA related code together there - * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and + * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings * when setting an UltraDMA mode * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select @@ -458,13 +458,6 @@ enum ata_clock { NUM_ATA_CLOCKS }; -struct hpt_timings { - u32 pio_mask; - u32 dma_mask; - u32 ultra_mask; - u32 *clock_table[NUM_ATA_CLOCKS]; -}; - /* * Hold all the HighPoint chip information in one place. */ @@ -475,8 +468,7 @@ struct hpt_info { u8 udma_mask; /* Allowed UltraDMA modes mask. */ u8 dpll_clk; /* DPLL clock in MHz */ u8 pci_clk; /* PCI clock in MHz */ - struct hpt_timings *timings; /* Chipset timing data */ - u8 clock; /* ATA clock selected */ + u32 **settings; /* Chipset settings table */ }; /* Supported HighPoint chips */ @@ -494,30 +486,20 @@ enum { HPT371N }; -static struct hpt_timings hpt36x_timings = { - .pio_mask = 0xc1f8ffff, - .dma_mask = 0x303800ff, - .ultra_mask = 0x30070000, - .clock_table = { - [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x, - [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x, - [ATA_CLOCK_40MHZ] = forty_base_hpt36x, - [ATA_CLOCK_50MHZ] = NULL, - [ATA_CLOCK_66MHZ] = NULL - } +static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = { + twenty_five_base_hpt36x, + thirty_three_base_hpt36x, + forty_base_hpt36x, + NULL, + NULL }; -static struct hpt_timings hpt37x_timings = { - .pio_mask = 0xcfc3ffff, - .dma_mask = 0x31c001ff, - .ultra_mask = 0x303c0000, - .clock_table = { - [ATA_CLOCK_25MHZ] = NULL, - [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x, - [ATA_CLOCK_40MHZ] = NULL, - [ATA_CLOCK_50MHZ] = fifty_base_hpt37x, - [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x - } +static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = { + NULL, + thirty_three_base_hpt37x, + NULL, + fifty_base_hpt37x, + sixty_six_base_hpt37x }; static const struct hpt_info hpt36x __devinitdata = { @@ -525,7 +507,7 @@ static const struct hpt_info hpt36x __devinitdata = { .chip_type = HPT36x, .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2, .dpll_clk = 0, /* no DPLL */ - .timings = &hpt36x_timings + .settings = hpt36x_settings }; static const struct hpt_info hpt370 __devinitdata = { @@ -533,7 +515,7 @@ static const struct hpt_info hpt370 __devinitdata = { .chip_type = HPT370, .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, .dpll_clk = 48, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt370a __devinitdata = { @@ -541,7 +523,7 @@ static const struct hpt_info hpt370a __devinitdata = { .chip_type = HPT370A, .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, .dpll_clk = 48, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt374 __devinitdata = { @@ -549,7 +531,7 @@ static const struct hpt_info hpt374 __devinitdata = { .chip_type = HPT374, .udma_mask = ATA_UDMA5, .dpll_clk = 48, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt372 __devinitdata = { @@ -557,7 +539,7 @@ static const struct hpt_info hpt372 __devinitdata = { .chip_type = HPT372, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 55, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt372a __devinitdata = { @@ -565,7 +547,7 @@ static const struct hpt_info hpt372a __devinitdata = { .chip_type = HPT372A, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 66, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt302 __devinitdata = { @@ -573,7 +555,7 @@ static const struct hpt_info hpt302 __devinitdata = { .chip_type = HPT302, .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 66, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt371 __devinitdata = { @@ -581,7 +563,7 @@ static const struct hpt_info hpt371 __devinitdata = { .chip_type = HPT371, .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 66, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt372n __devinitdata = { @@ -589,7 +571,7 @@ static const struct hpt_info hpt372n __devinitdata = { .chip_type = HPT372N, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 77, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt302n __devinitdata = { @@ -597,7 +579,7 @@ static const struct hpt_info hpt302n __devinitdata = { .chip_type = HPT302N, .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 77, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static const struct hpt_info hpt371n __devinitdata = { @@ -605,7 +587,7 @@ static const struct hpt_info hpt371n __devinitdata = { .chip_type = HPT371N, .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 77, - .timings = &hpt37x_timings + .settings = hpt37x_settings }; static int check_in_drive_list(ide_drive_t *drive, const char **list) @@ -693,33 +675,71 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info) for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++) if (xfer_speeds[i] == speed) break; - - return info->timings->clock_table[info->clock][i]; + /* + * NOTE: info->settings only points to the pointer + * to the list of the actual register values + */ + return (*info->settings)[i]; } -static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed) +static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; struct hpt_info *info = pci_get_drvdata(dev); - struct hpt_timings *t = info->timings; - u8 itr_addr = 0x40 + (drive->dn * 4); + u8 itr_addr = drive->dn ? 0x44 : 0x40; u32 old_itr = 0; - u32 new_itr = get_speed_setting(speed, info); - u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask : - (speed < XFER_UDMA_0 ? t->dma_mask : - t->ultra_mask); + u32 itr_mask, new_itr; + + itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : + (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); + + new_itr = get_speed_setting(speed, info); - pci_read_config_dword(dev, itr_addr, &old_itr); - new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask); /* * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well) * to avoid problems handling I/O errors later */ + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); new_itr &= ~0xc0000000; pci_write_config_dword(dev, itr_addr, new_itr); } +static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = pci_get_drvdata(dev); + u8 itr_addr = 0x40 + (drive->dn * 4); + u32 old_itr = 0; + u32 itr_mask, new_itr; + + itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : + (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); + + new_itr = get_speed_setting(speed, info); + + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); + + if (speed < XFER_MW_DMA_0) + new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ + pci_write_config_dword(dev, itr_addr, new_itr); +} + +static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); + + if (info->chip_type >= HPT370) + hpt37x_set_mode(drive, speed); + else /* hpt368: hpt_minimum_revision(dev, 2) */ + hpt36x_set_mode(drive, speed); +} + static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { hpt3xx_set_mode(drive, XFER_PIO_0 + pio); @@ -736,6 +756,15 @@ static int hpt3xx_quirkproc(ide_drive_t *drive) return 0; } +static void hpt3xx_intrproc(ide_drive_t *drive) +{ + if (drive->quirk_list) + return; + + /* drives in the quirk_list may not like intr setups/cleanups */ + outb(drive->ctl | 2, IDE_CONTROL_REG); +} + static void hpt3xx_maskproc(ide_drive_t *drive, int mask) { ide_hwif_t *hwif = HWIF(drive); @@ -885,33 +914,32 @@ static int hpt374_ide_dma_end(ide_drive_t *drive) static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) { - unsigned long base = hwif->extra_base; - u8 scr2 = inb(base + 0x6b); + u8 scr2 = inb(hwif->dma_master + 0x7b); if ((scr2 & 0x7f) == mode) return; /* Tristate the bus */ - outb(0x80, base + 0x63); - outb(0x80, base + 0x67); + outb(0x80, hwif->dma_master + 0x73); + outb(0x80, hwif->dma_master + 0x77); /* Switch clock and reset channels */ - outb(mode, base + 0x6b); - outb(0xc0, base + 0x69); + outb(mode, hwif->dma_master + 0x7b); + outb(0xc0, hwif->dma_master + 0x79); /* * Reset the state machines. * NOTE: avoid accidentally enabling the disabled channels. */ - outb(inb(base + 0x60) | 0x32, base + 0x60); - outb(inb(base + 0x64) | 0x32, base + 0x64); + outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70); + outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74); /* Complete reset */ - outb(0x00, base + 0x69); + outb(0x00, hwif->dma_master + 0x79); /* Reconnect channels to bus */ - outb(0x00, base + 0x63); - outb(0x00, base + 0x67); + outb(0x00, hwif->dma_master + 0x73); + outb(0x00, hwif->dma_master + 0x77); } /** @@ -1182,7 +1210,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha * We also don't like using the DPLL because this causes glitches * on PRST-/SRST- when the state engine gets reset... */ - if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) { + if (chip_type >= HPT374 || info->settings[clock] == NULL) { u16 f_low, delta = pci_clk < 50 ? 2 : 4; int adjust; @@ -1198,7 +1226,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha clock = ATA_CLOCK_50MHZ; } - if (info->timings->clock_table[clock] == NULL) { + if (info->settings[clock] == NULL) { printk(KERN_ERR "%s: unknown bus timing!\n", name); kfree(info); return -EIO; @@ -1239,10 +1267,15 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha printk("%s: using %d MHz PCI clock\n", name, pci_clk); } + /* + * Advance the table pointer to a slot which points to the list + * of the register values settings matching the clock being used. + */ + info->settings += clock; + /* Store the clock frequencies. */ info->dpll_clk = dpll_clk; info->pci_clk = pci_clk; - info->clock = clock; /* Point to this chip's own instance of the hpt_info structure. */ pci_set_drvdata(dev, info); @@ -1287,8 +1320,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->set_pio_mode = &hpt3xx_set_pio_mode; hwif->set_dma_mode = &hpt3xx_set_mode; - hwif->quirkproc = &hpt3xx_quirkproc; + hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; hwif->busproc = &hpt3xx_busproc; @@ -1461,11 +1494,6 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2) return 0; } -#define IDE_HFLAGS_HPT3XX \ - (IDE_HFLAG_NO_ATAPI_DMA | \ - IDE_HFLAG_ABUSE_SET_DMA_MODE | \ - IDE_HFLAG_OFF_BOARD) - static const struct ide_port_info hpt366_chipsets[] __devinitdata = { { /* 0 */ .name = "HPT36x", @@ -1480,7 +1508,9 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { */ .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE, + .host_flags = IDE_HFLAG_SINGLE | + IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 1 */ @@ -1490,7 +1520,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAGS_HPT3XX, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 2 */ @@ -1500,7 +1530,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAGS_HPT3XX, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 3 */ @@ -1510,7 +1540,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAGS_HPT3XX, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 4 */ @@ -1521,7 +1551,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .udma_mask = ATA_UDMA5, .extra = 240, - .host_flags = IDE_HFLAGS_HPT3XX, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 5 */ @@ -1531,7 +1561,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAGS_HPT3XX, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, } diff --git a/trunk/drivers/ide/pci/it8213.c b/trunk/drivers/ide/pci/it8213.c index 2a0f45c4f4c4..90b52ed37bfc 100644 --- a/trunk/drivers/ide/pci/it8213.c +++ b/trunk/drivers/ide/pci/it8213.c @@ -101,11 +101,24 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed) pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); - if (speed >= XFER_UDMA_0) { - u8 udma = speed - XFER_UDMA_0; - - u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); + switch(speed) { + case XFER_UDMA_6: + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_SW_DMA_2: + break; + default: + return; + } + if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_byte(dev, 0x48, reg48 | u_flag); if (speed >= XFER_UDMA_5) { diff --git a/trunk/drivers/ide/pci/pdc202xx_new.c b/trunk/drivers/ide/pci/pdc202xx_new.c index ef4a99b99d1f..2b4f44e45a1a 100644 --- a/trunk/drivers/ide/pci/pdc202xx_new.c +++ b/trunk/drivers/ide/pci/pdc202xx_new.c @@ -146,7 +146,7 @@ static struct udma_timing { { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ }; -static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) +static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; @@ -162,18 +162,45 @@ static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) if (max_dma_rate(hwif->pci_dev) == 4) { u8 mode = speed & 0x07; - if (speed >= XFER_UDMA_0) { - set_indexed_reg(hwif, 0x10 + adj, - udma_timings[mode].reg10); - set_indexed_reg(hwif, 0x11 + adj, - udma_timings[mode].reg11); - set_indexed_reg(hwif, 0x12 + adj, - udma_timings[mode].reg12); - } else { - set_indexed_reg(hwif, 0x0e + adj, - mwdma_timings[mode].reg0e); - set_indexed_reg(hwif, 0x0f + adj, - mwdma_timings[mode].reg0f); + switch (speed) { + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + set_indexed_reg(hwif, 0x10 + adj, + udma_timings[mode].reg10); + set_indexed_reg(hwif, 0x11 + adj, + udma_timings[mode].reg11); + set_indexed_reg(hwif, 0x12 + adj, + udma_timings[mode].reg12); + break; + + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + set_indexed_reg(hwif, 0x0e + adj, + mwdma_timings[mode].reg0e); + set_indexed_reg(hwif, 0x0f + adj, + mwdma_timings[mode].reg0f); + break; + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + set_indexed_reg(hwif, 0x0c + adj, + pio_timings[mode].reg0c); + set_indexed_reg(hwif, 0x0d + adj, + pio_timings[mode].reg0d); + set_indexed_reg(hwif, 0x13 + adj, + pio_timings[mode].reg13); + break; + default: + printk(KERN_ERR "pdc202xx_new: " + "Unknown speed %d ignored\n", speed); } } else if (speed == XFER_UDMA_2) { /* Set tHOLD bit to 0 if using UDMA mode 2 */ @@ -185,14 +212,7 @@ static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio) { - ide_hwif_t *hwif = drive->hwif; - u8 adj = (drive->dn & 1) ? 0x08 : 0x00; - - if (max_dma_rate(hwif->pci_dev) == 4) { - set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c); - set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d); - set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13); - } + pdcnew_set_mode(drive, XFER_PIO_0 + pio); } static u8 pdcnew_cable_detect(ide_hwif_t *hwif) @@ -446,7 +466,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) { hwif->set_pio_mode = &pdcnew_set_pio_mode; - hwif->set_dma_mode = &pdcnew_set_dma_mode; + hwif->set_dma_mode = &pdcnew_set_mode; hwif->quirkproc = &pdcnew_quirkproc; hwif->resetproc = &pdcnew_reset; diff --git a/trunk/drivers/ide/pci/pdc202xx_old.c b/trunk/drivers/ide/pci/pdc202xx_old.c index 67b2781e2213..e09742e2ba59 100644 --- a/trunk/drivers/ide/pci/pdc202xx_old.c +++ b/trunk/drivers/ide/pci/pdc202xx_old.c @@ -162,7 +162,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) */ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) { - unsigned long clock_reg = hwif->extra_base + 0x01; + unsigned long clock_reg = hwif->dma_master + 0x11; u8 clock = inb(clock_reg); outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); @@ -170,7 +170,7 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) { - unsigned long clock_reg = hwif->extra_base + 0x01; + unsigned long clock_reg = hwif->dma_master + 0x11; u8 clock = inb(clock_reg); outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); @@ -193,7 +193,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) if (drive->media != ide_disk || drive->addressing == 1) { struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->extra_base - 16; + unsigned long high_16 = hwif->dma_master; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u32 word_count = 0; u8 clock = inb(high_16 + 0x11); @@ -212,7 +212,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) { if (drive->media != ide_disk || drive->addressing == 1) { ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->extra_base - 16; + unsigned long high_16 = hwif->dma_master; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u8 clock = 0; @@ -228,7 +228,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->extra_base - 16; + unsigned long high_16 = hwif->dma_master; u8 dma_stat = inb(hwif->dma_status); u8 sc1d = inb(high_16 + 0x001d); @@ -271,7 +271,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive) static void pdc202xx_reset_host (ide_hwif_t *hwif) { - unsigned long high_16 = hwif->extra_base - 16; + unsigned long high_16 = hwif->dma_master; u8 udma_speed_flag = inb(high_16 | 0x001f); outb(udma_speed_flag | 0x10, high_16 | 0x001f); @@ -375,11 +375,6 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev, } } -#define IDE_HFLAGS_PDC202XX \ - (IDE_HFLAG_ERROR_STOPS_FIFO | \ - IDE_HFLAG_ABUSE_SET_DMA_MODE | \ - IDE_HFLAG_OFF_BOARD) - #define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \ { \ .name = name_str, \ @@ -387,7 +382,9 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev, .init_hwif = init_hwif_pdc202xx, \ .init_dma = init_dma_pdc202xx, \ .extra = 48, \ - .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \ + .host_flags = IDE_HFLAG_ERROR_STOPS_FIFO | \ + extra_flags | \ + IDE_HFLAG_OFF_BOARD, \ .pio_mask = ATA_PIO4, \ .mwdma_mask = ATA_MWDMA2, \ .udma_mask = udma, \ @@ -400,7 +397,8 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = { .init_hwif = init_hwif_pdc202xx, .init_dma = init_dma_pdc202xx, .extra = 16, - .host_flags = IDE_HFLAGS_PDC202XX, + .host_flags = IDE_HFLAG_ERROR_STOPS_FIFO | + IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA2, diff --git a/trunk/drivers/ide/pci/piix.c b/trunk/drivers/ide/pci/piix.c index bd6d3f77d30c..27781d294cea 100644 --- a/trunk/drivers/ide/pci/piix.c +++ b/trunk/drivers/ide/pci/piix.c @@ -203,11 +203,20 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed) pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); - if (speed >= XFER_UDMA_0) { - u8 udma = speed - XFER_UDMA_0; - - u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); + switch(speed) { + case XFER_UDMA_4: + case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_5: + case XFER_UDMA_3: + case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_SW_DMA_2: break; + default: return; + } + if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_byte(dev, 0x48, reg48 | u_flag); if (speed == XFER_UDMA_5) { diff --git a/trunk/drivers/ide/pci/sc1200.c b/trunk/drivers/ide/pci/sc1200.c index fef20bd4aa78..707d5ff66b03 100644 --- a/trunk/drivers/ide/pci/sc1200.c +++ b/trunk/drivers/ide/pci/sc1200.c @@ -135,29 +135,59 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode) unsigned short pci_clock; unsigned int basereg = hwif->channel ? 0x50 : 0x40; - static const u32 udma_timing[3][3] = { - { 0x00921250, 0x00911140, 0x00911030 }, - { 0x00932470, 0x00922260, 0x00922140 }, - { 0x009436a1, 0x00933481, 0x00923261 }, - }; - - static const u32 mwdma_timing[3][3] = { - { 0x00077771, 0x00012121, 0x00002020 }, - { 0x000bbbb2, 0x00024241, 0x00013131 }, - { 0x000ffff3, 0x00035352, 0x00015151 }, - }; - pci_clock = sc1200_get_pci_clock(); /* * Note that each DMA mode has several timings associated with it. * The correct timing depends on the fast PCI clock freq. */ - - if (mode >= XFER_UDMA_0) - timings = udma_timing[pci_clock][mode - XFER_UDMA_0]; - else - timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0]; + timings = 0; + switch (mode) { + case XFER_UDMA_0: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00921250; break; + case PCI_CLK_48: timings = 0x00932470; break; + case PCI_CLK_66: timings = 0x009436a1; break; + } + break; + case XFER_UDMA_1: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00911140; break; + case PCI_CLK_48: timings = 0x00922260; break; + case PCI_CLK_66: timings = 0x00933481; break; + } + break; + case XFER_UDMA_2: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00911030; break; + case PCI_CLK_48: timings = 0x00922140; break; + case PCI_CLK_66: timings = 0x00923261; break; + } + break; + case XFER_MW_DMA_0: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00077771; break; + case PCI_CLK_48: timings = 0x000bbbb2; break; + case PCI_CLK_66: timings = 0x000ffff3; break; + } + break; + case XFER_MW_DMA_1: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00012121; break; + case PCI_CLK_48: timings = 0x00024241; break; + case PCI_CLK_66: timings = 0x00035352; break; + } + break; + case XFER_MW_DMA_2: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00002020; break; + case PCI_CLK_48: timings = 0x00013131; break; + case PCI_CLK_66: timings = 0x00015151; break; + } + break; + default: + return; + } if (unit == 0) { /* are we configuring drive0? */ pci_read_config_dword(hwif->pci_dev, basereg+4, ®); @@ -230,40 +260,67 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio) } #ifdef CONFIG_PM -struct sc1200_saved_state { - u32 regs[8]; -}; +static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev) +{ + int h; + + for (h = 0; h < MAX_HWIFS; h++) { + ide_hwif_t *hwif = &ide_hwifs[h]; + if (prev) { + if (hwif == prev) + prev = NULL; // found previous, now look for next match + } else { + if (hwif && hwif->pci_dev == dev) + return hwif; // found next match + } + } + return NULL; // not found +} + +typedef struct sc1200_saved_state_s { + __u32 regs[4]; +} sc1200_saved_state_t; + static int sc1200_suspend (struct pci_dev *dev, pm_message_t state) { + ide_hwif_t *hwif = NULL; + printk("SC1200: suspend(%u)\n", state.event); - /* - * we only save state when going from full power to less - */ if (state.event == PM_EVENT_ON) { - struct sc1200_saved_state *ss; - unsigned int r; - - /* - * allocate a permanent save area, if not already allocated - */ - ss = (struct sc1200_saved_state *)pci_get_drvdata(dev); - if (ss == NULL) { - ss = kmalloc(sizeof(*ss), GFP_KERNEL); - if (ss == NULL) - return -ENOMEM; - pci_set_drvdata(dev, ss); + // we only save state when going from full power to less + + // + // Loop over all interfaces that are part of this PCI device: + // + while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { + sc1200_saved_state_t *ss; + unsigned int basereg, r; + // + // allocate a permanent save area, if not already allocated + // + ss = (sc1200_saved_state_t *)hwif->config_data; + if (ss == NULL) { + ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL); + if (ss == NULL) + return -ENOMEM; + hwif->config_data = (unsigned long)ss; + } + ss = (sc1200_saved_state_t *)hwif->config_data; + // + // Save timing registers: this may be unnecessary if + // BIOS also does it + // + basereg = hwif->channel ? 0x50 : 0x40; + for (r = 0; r < 4; ++r) { + pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]); + } } - - /* - * save timing registers - * (this may be unnecessary if BIOS also does it) - */ - for (r = 0; r < 8; r++) - pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]); } + /* You don't need to iterate over disks -- sysfs should have done that for you already */ + pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; @@ -271,25 +328,30 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state) static int sc1200_resume (struct pci_dev *dev) { - struct sc1200_saved_state *ss; - unsigned int r; - int i; + ide_hwif_t *hwif = NULL; + int i; i = pci_enable_device(dev); if (i) return i; - ss = (struct sc1200_saved_state *)pci_get_drvdata(dev); - - /* - * restore timing registers - * (this may be unnecessary if BIOS also does it) - */ - if (ss) { - for (r = 0; r < 8; r++) - pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]); + // + // loop over all interfaces that are part of this pci device: + // + while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { + unsigned int basereg, r; + sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data; + + // + // Restore timing registers: this may be unnecessary if BIOS also does it + // + basereg = hwif->channel ? 0x50 : 0x40; + if (ss != NULL) { + for (r = 0; r < 4; ++r) { + pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]); + } + } } - return 0; } #endif diff --git a/trunk/drivers/ide/pci/scc_pata.c b/trunk/drivers/ide/pci/scc_pata.c index 24a85bbcd2a6..ebb7132b9b84 100644 --- a/trunk/drivers/ide/pci/scc_pata.c +++ b/trunk/drivers/ide/pci/scc_pata.c @@ -254,7 +254,19 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) offset = 0; /* 100MHz */ } - idx = speed - XFER_UDMA_0; + switch (speed) { + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + idx = speed - XFER_UDMA_0; + break; + default: + return; + } jcactsel = JCACTSELtbl[offset][idx]; if (is_slave) { diff --git a/trunk/drivers/ide/pci/serverworks.c b/trunk/drivers/ide/pci/serverworks.c index e9bd269547bb..a7280311357b 100644 --- a/trunk/drivers/ide/pci/serverworks.c +++ b/trunk/drivers/ide/pci/serverworks.c @@ -366,17 +366,12 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) } } -#define IDE_HFLAGS_SVWKS \ - (IDE_HFLAG_LEGACY_IRQS | \ - IDE_HFLAG_ABUSE_SET_DMA_MODE | \ - IDE_HFLAG_BOOTABLE) - static const struct ide_port_info serverworks_chipsets[] __devinitdata = { { /* 0 */ .name = "SvrWks OSB4", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAGS_SVWKS, + .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = 0x00, /* UDMA is problematic on OSB4 */ @@ -384,7 +379,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks CSB5", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAGS_SVWKS, + .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -392,7 +387,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks CSB6", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAGS_SVWKS, + .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -400,7 +395,8 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks CSB6", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE, + .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE | + IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -408,7 +404,8 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks HT1000", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE, + .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE | + IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, diff --git a/trunk/drivers/ide/pci/sgiioc4.c b/trunk/drivers/ide/pci/sgiioc4.c index 7e9dade5648d..de820aa58cd0 100644 --- a/trunk/drivers/ide/pci/sgiioc4.c +++ b/trunk/drivers/ide/pci/sgiioc4.c @@ -582,6 +582,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->pre_reset = NULL; /* No HBA specific pre_set needed */ hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine, clear interrupts */ + hwif->intrproc = NULL; /* Enable or Disable interrupt from drive */ hwif->maskproc = &sgiioc4_maskproc; /* Mask on/off NIEN register */ hwif->quirkproc = NULL; hwif->busproc = NULL; diff --git a/trunk/drivers/ide/pci/siimage.c b/trunk/drivers/ide/pci/siimage.c index 7b45eaf5afd9..5709c252543b 100644 --- a/trunk/drivers/ide/pci/siimage.c +++ b/trunk/drivers/ide/pci/siimage.c @@ -278,14 +278,27 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) scsc = is_sata(hwif) ? 1 : scsc; - if (speed >= XFER_UDMA_0) { - multi = dma[2]; - ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] : - ultra5[speed - XFER_UDMA_0]); - mode |= (unit ? 0x30 : 0x03); - } else { - multi = dma[speed - XFER_MW_DMA_0]; - mode |= (unit ? 0x20 : 0x02); + switch(speed) { + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + multi = dma[speed - XFER_MW_DMA_0]; + mode |= ((unit) ? 0x20 : 0x02); + break; + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + multi = dma[2]; + ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) : + (ultra5[speed - XFER_UDMA_0])); + mode |= ((unit) ? 0x30 : 0x03); + break; + default: + return; } if (hwif->mmio) { diff --git a/trunk/drivers/ide/pci/sis5513.c b/trunk/drivers/ide/pci/sis5513.c index 85d36996e6af..d90b42917775 100644 --- a/trunk/drivers/ide/pci/sis5513.c +++ b/trunk/drivers/ide/pci/sis5513.c @@ -305,56 +305,59 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) sis_program_timings(drive, XFER_PIO_0 + pio); } -static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - u32 regdw = 0; - u8 drive_pci = sis_ata133_get_base(drive), clk, idx; - - pci_read_config_dword(dev, drive_pci, ®dw); - - regdw |= 0x04; - regdw &= 0xfffff00f; - /* check if ATA133 enable */ - clk = (regdw & 0x08) ? ATA_133 : ATA_100; - idx = mode - XFER_UDMA_0; - regdw |= cycle_time_value[clk][idx] << 4; - regdw |= cvs_time_value[clk][idx] << 8; - - pci_write_config_dword(dev, drive_pci, regdw); -} - -static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family; - - pci_read_config_byte(dev, drive_pci + 1, ®); - - /* force the UDMA bit on if we want to use UDMA */ - reg |= 0x80; - /* clean reg cycle time bits */ - reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]); - /* set reg cycle time bits */ - reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i]; - - pci_write_config_byte(dev, drive_pci + 1, reg); -} - -static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode) -{ - if (chipset_family >= ATA_133) /* ATA_133 */ - sis_ata133_program_udma_timings(drive, mode); - else /* ATA_33/66/100a/100/133a */ - sis_ata33_program_udma_timings(drive, mode); -} - static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed) { - if (speed >= XFER_UDMA_0) - sis_program_udma_timings(drive, speed); - else - sis_program_timings(drive, speed); + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *dev = hwif->pci_dev; + + /* Config chip for mode */ + switch(speed) { + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + if (chipset_family >= ATA_133) { + u32 regdw = 0; + u8 drive_pci = sis_ata133_get_base(drive); + + pci_read_config_dword(dev, drive_pci, ®dw); + regdw |= 0x04; + regdw &= 0xfffff00f; + /* check if ATA133 enable */ + if (regdw & 0x08) { + regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; + } else { + regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; + regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; + } + pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); + } else { + u8 drive_pci = 0x40 + drive->dn * 2, reg = 0; + + pci_read_config_byte(dev, drive_pci+1, ®); + /* Force the UDMA bit on if we want to use UDMA */ + reg |= 0x80; + /* clean reg cycle time bits */ + reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) + << cycle_time_offset[chipset_family]); + /* set reg cycle time bits */ + reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0] + << cycle_time_offset[chipset_family]; + pci_write_config_byte(dev, drive_pci+1, reg); + } + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + sis_program_timings(drive, speed); + break; + default: + break; + } } static u8 sis5513_ata133_udma_filter(ide_drive_t *drive) diff --git a/trunk/drivers/ide/pci/sl82c105.c b/trunk/drivers/ide/pci/sl82c105.c index 069f104fdcea..147d783f7529 100644 --- a/trunk/drivers/ide/pci/sl82c105.c +++ b/trunk/drivers/ide/pci/sl82c105.c @@ -115,24 +115,32 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed) DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n", drive->name, ide_xfer_verbose(speed))); - drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0]; + switch (speed) { + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0]; - /* - * Store the DMA timings so that we can actually program - * them when DMA will be turned on... - */ - drive->drive_data &= 0x0000ffff; - drive->drive_data |= (unsigned long)drv_ctrl << 16; - - /* - * If we are already using DMA, we just reprogram - * the drive control register. - */ - if (drive->using_dma) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - int reg = 0x44 + drive->dn * 4; + /* + * Store the DMA timings so that we can actually program + * them when DMA will be turned on... + */ + drive->drive_data &= 0x0000ffff; + drive->drive_data |= (unsigned long)drv_ctrl << 16; - pci_write_config_word(dev, reg, drv_ctrl); + /* + * If we are already using DMA, we just reprogram + * the drive control register. + */ + if (drive->using_dma) { + struct pci_dev *dev = HWIF(drive)->pci_dev; + int reg = 0x44 + drive->dn * 4; + + pci_write_config_word(dev, reg, drv_ctrl); + } + break; + default: + return; } } diff --git a/trunk/drivers/ide/pci/slc90e66.c b/trunk/drivers/ide/pci/slc90e66.c index dbbb46819a2d..eb4445b229ed 100644 --- a/trunk/drivers/ide/pci/slc90e66.c +++ b/trunk/drivers/ide/pci/slc90e66.c @@ -91,9 +91,19 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) pci_read_config_word(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - if (speed >= XFER_UDMA_0) { - u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4); + switch(speed) { + case XFER_UDMA_4: u_speed = 4 << (drive->dn * 4); break; + case XFER_UDMA_3: u_speed = 3 << (drive->dn * 4); break; + case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; + case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; + case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_SW_DMA_2: break; + default: return; + } + if (speed >= XFER_UDMA_0) { if (!(reg48 & u_flag)) pci_write_config_word(dev, 0x48, reg48|u_flag); /* FIXME: (reg4a & a_speed) ? */ diff --git a/trunk/drivers/ide/pci/tc86c001.c b/trunk/drivers/ide/pci/tc86c001.c index e1faf6c2fe16..a66ebd14664e 100644 --- a/trunk/drivers/ide/pci/tc86c001.c +++ b/trunk/drivers/ide/pci/tc86c001.c @@ -222,8 +222,7 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = { .name = "TC86C001", .init_chipset = init_chipset_tc86c001, .init_hwif = init_hwif_tc86c001, - .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD | - IDE_HFLAG_ABUSE_SET_DMA_MODE, + .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA4, diff --git a/trunk/drivers/ide/pci/triflex.c b/trunk/drivers/ide/pci/triflex.c index ae52a96a1cf9..a227c41d23a3 100644 --- a/trunk/drivers/ide/pci/triflex.c +++ b/trunk/drivers/ide/pci/triflex.c @@ -81,6 +81,8 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed) case XFER_PIO_0: timing = 0x0808; break; + default: + return; } triflex_timings &= ~(0xFFFF << (16 * unit)); diff --git a/trunk/drivers/ide/pci/via82cxxx.c b/trunk/drivers/ide/pci/via82cxxx.c index 4b32c90f4896..a0d3c16b68ec 100644 --- a/trunk/drivers/ide/pci/via82cxxx.c +++ b/trunk/drivers/ide/pci/via82cxxx.c @@ -439,7 +439,6 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = { .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST | IDE_HFLAG_PIO_NO_DOWNGRADE | - IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_POST_SET_MODE | IDE_HFLAG_IO_32BIT | IDE_HFLAG_BOOTABLE, diff --git a/trunk/drivers/ide/ppc/pmac.c b/trunk/drivers/ide/ppc/pmac.c index 3dce80092fff..7f7a59885777 100644 --- a/trunk/drivers/ide/ppc/pmac.c +++ b/trunk/drivers/ide/ppc/pmac.c @@ -438,8 +438,13 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw, if (data_port == pmac_ide[ix].regbase) break; - if (ix >= MAX_HWIFS) - return; /* not an IDE PMAC interface */ + if (ix >= MAX_HWIFS) { + /* Probably a PCI interface... */ + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i) + hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET; + hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; + return; + } for (i = 0; i < 8; ++i) hw->io_ports[i] = data_port + i * 0x10; @@ -828,20 +833,38 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed) tl[0] = *timings; tl[1] = *timings2; + switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - if (speed >= XFER_UDMA_0) { - if (pmif->kind == controller_kl_ata4) - ret = set_timings_udma_ata4(&tl[0], speed); - else if (pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6) - ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); - else if (pmif->kind == controller_sh_ata6) - ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); - else - ret = -1; - } else - set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + if (pmif->kind == controller_kl_ata4) + ret = set_timings_udma_ata4(&tl[0], speed); + else if (pmif->kind == controller_un_ata6 + || pmif->kind == controller_k2_ata6) + ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); + else if (pmif->kind == controller_sh_ata6) + ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); + else + ret = 1; + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); + break; + case XFER_SW_DMA_2: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + return; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ + default: + ret = 1; + } if (ret) return; diff --git a/trunk/drivers/infiniband/core/cm.c b/trunk/drivers/infiniband/core/cm.c index c0150147d347..2e39236d189f 100644 --- a/trunk/drivers/infiniband/core/cm.c +++ b/trunk/drivers/infiniband/core/cm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2007 Intel Corporation. All rights reserved. + * Copyright (c) 2004-2006 Intel Corporation. All rights reserved. * Copyright (c) 2004 Topspin Corporation. All rights reserved. * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. @@ -37,14 +37,12 @@ #include #include -#include #include #include #include #include #include #include -#include #include #include @@ -80,94 +78,17 @@ static struct ib_cm { struct workqueue_struct *wq; } cm; -/* Counter indexes ordered by attribute ID */ -enum { - CM_REQ_COUNTER, - CM_MRA_COUNTER, - CM_REJ_COUNTER, - CM_REP_COUNTER, - CM_RTU_COUNTER, - CM_DREQ_COUNTER, - CM_DREP_COUNTER, - CM_SIDR_REQ_COUNTER, - CM_SIDR_REP_COUNTER, - CM_LAP_COUNTER, - CM_APR_COUNTER, - CM_ATTR_COUNT, - CM_ATTR_ID_OFFSET = 0x0010, -}; - -enum { - CM_XMIT, - CM_XMIT_RETRIES, - CM_RECV, - CM_RECV_DUPLICATES, - CM_COUNTER_GROUPS -}; - -static char const counter_group_names[CM_COUNTER_GROUPS] - [sizeof("cm_rx_duplicates")] = { - "cm_tx_msgs", "cm_tx_retries", - "cm_rx_msgs", "cm_rx_duplicates" -}; - -struct cm_counter_group { - struct kobject obj; - atomic_long_t counter[CM_ATTR_COUNT]; -}; - -struct cm_counter_attribute { - struct attribute attr; - int index; -}; - -#define CM_COUNTER_ATTR(_name, _index) \ -struct cm_counter_attribute cm_##_name##_counter_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \ - .index = _index \ -} - -static CM_COUNTER_ATTR(req, CM_REQ_COUNTER); -static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER); -static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER); -static CM_COUNTER_ATTR(rep, CM_REP_COUNTER); -static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER); -static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER); -static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER); -static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER); -static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER); -static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER); -static CM_COUNTER_ATTR(apr, CM_APR_COUNTER); - -static struct attribute *cm_counter_default_attrs[] = { - &cm_req_counter_attr.attr, - &cm_mra_counter_attr.attr, - &cm_rej_counter_attr.attr, - &cm_rep_counter_attr.attr, - &cm_rtu_counter_attr.attr, - &cm_dreq_counter_attr.attr, - &cm_drep_counter_attr.attr, - &cm_sidr_req_counter_attr.attr, - &cm_sidr_rep_counter_attr.attr, - &cm_lap_counter_attr.attr, - &cm_apr_counter_attr.attr, - NULL -}; - struct cm_port { struct cm_device *cm_dev; struct ib_mad_agent *mad_agent; - struct kobject port_obj; u8 port_num; - struct cm_counter_group counter_group[CM_COUNTER_GROUPS]; }; struct cm_device { struct list_head list; struct ib_device *device; - struct kobject dev_obj; u8 ack_delay; - struct cm_port *port[0]; + struct cm_port port[0]; }; struct cm_av { @@ -357,7 +278,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) list_for_each_entry(cm_dev, &cm.device_list, list) { if (!ib_find_cached_gid(cm_dev->device, &path->sgid, &p, NULL)) { - port = cm_dev->port[p-1]; + port = &cm_dev->port[p-1]; break; } } @@ -1349,9 +1270,6 @@ static void cm_dup_req_handler(struct cm_work *work, struct ib_mad_send_buf *msg = NULL; int ret; - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_REQ_COUNTER]); - /* Quick state check to discard duplicate REQs. */ if (cm_id_priv->id.state == IB_CM_REQ_RCVD) return; @@ -1698,8 +1616,6 @@ static void cm_dup_rep_handler(struct cm_work *work) if (!cm_id_priv) return; - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_REP_COUNTER]); ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); if (ret) goto deref; @@ -1865,8 +1781,6 @@ static int cm_rtu_handler(struct cm_work *work) if (cm_id_priv->id.state != IB_CM_REP_SENT && cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) { spin_unlock_irq(&cm_id_priv->lock); - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_RTU_COUNTER]); goto out; } cm_id_priv->id.state = IB_CM_ESTABLISHED; @@ -2044,8 +1958,6 @@ static int cm_dreq_handler(struct cm_work *work) cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, dreq_msg->local_comm_id); if (!cm_id_priv) { - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_DREQ_COUNTER]); cm_issue_drep(work->port, work->mad_recv_wc); return -EINVAL; } @@ -2065,8 +1977,6 @@ static int cm_dreq_handler(struct cm_work *work) case IB_CM_MRA_REP_RCVD: break; case IB_CM_TIMEWAIT: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_DREQ_COUNTER]); if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) goto unlock; @@ -2078,10 +1988,6 @@ static int cm_dreq_handler(struct cm_work *work) if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; - case IB_CM_DREQ_RCVD: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_DREQ_COUNTER]); - goto unlock; default: goto unlock; } @@ -2433,20 +2339,10 @@ static int cm_mra_handler(struct cm_work *work) if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER || cm_id_priv->id.lap_state != IB_CM_LAP_SENT || ib_modify_mad(cm_id_priv->av.port->mad_agent, - cm_id_priv->msg, timeout)) { - if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) - atomic_long_inc(&work->port-> - counter_group[CM_RECV_DUPLICATES]. - counter[CM_MRA_COUNTER]); + cm_id_priv->msg, timeout)) goto out; - } cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD; break; - case IB_CM_MRA_REQ_RCVD: - case IB_CM_MRA_REP_RCVD: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_MRA_COUNTER]); - /* fall through */ default: goto out; } @@ -2606,8 +2502,6 @@ static int cm_lap_handler(struct cm_work *work) case IB_CM_LAP_IDLE: break; case IB_CM_MRA_LAP_SENT: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_LAP_COUNTER]); if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) goto unlock; @@ -2621,10 +2515,6 @@ static int cm_lap_handler(struct cm_work *work) if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; - case IB_CM_LAP_RCVD: - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_LAP_COUNTER]); - goto unlock; default: goto unlock; } @@ -2906,8 +2796,6 @@ static int cm_sidr_req_handler(struct cm_work *work) cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv); if (cur_cm_id_priv) { spin_unlock_irq(&cm.lock); - atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. - counter[CM_SIDR_REQ_COUNTER]); goto out; /* Duplicate message. */ } cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; @@ -3102,27 +2990,6 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_send_wc) { struct ib_mad_send_buf *msg = mad_send_wc->send_buf; - struct cm_port *port; - u16 attr_index; - - port = mad_agent->context; - attr_index = be16_to_cpu(((struct ib_mad_hdr *) - msg->mad)->attr_id) - CM_ATTR_ID_OFFSET; - - /* - * If the send was in response to a received message (context[0] is not - * set to a cm_id), and is not a REJ, then it is a send that was - * manually retried. - */ - if (!msg->context[0] && (attr_index != CM_REJ_COUNTER)) - msg->retries = 1; - - atomic_long_add(1 + msg->retries, - &port->counter_group[CM_XMIT].counter[attr_index]); - if (msg->retries) - atomic_long_add(msg->retries, - &port->counter_group[CM_XMIT_RETRIES]. - counter[attr_index]); switch (mad_send_wc->status) { case IB_WC_SUCCESS: @@ -3281,10 +3148,8 @@ EXPORT_SYMBOL(ib_cm_notify); static void cm_recv_handler(struct ib_mad_agent *mad_agent, struct ib_mad_recv_wc *mad_recv_wc) { - struct cm_port *port = mad_agent->context; struct cm_work *work; enum ib_cm_event_type event; - u16 attr_id; int paths = 0; switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { @@ -3329,10 +3194,6 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, return; } - attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id); - atomic_long_inc(&port->counter_group[CM_RECV]. - counter[attr_id - CM_ATTR_ID_OFFSET]); - work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths, GFP_KERNEL); if (!work) { @@ -3343,7 +3204,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, INIT_DELAYED_WORK(&work->work, cm_work_handler); work->cm_event.event = event; work->mad_recv_wc = mad_recv_wc; - work->port = port; + work->port = (struct cm_port *)mad_agent->context; queue_delayed_work(cm.wq, &work->work, 0); } @@ -3518,108 +3379,6 @@ static void cm_get_ack_delay(struct cm_device *cm_dev) cm_dev->ack_delay = attr.local_ca_ack_delay; } -static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr, - char *buf) -{ - struct cm_counter_group *group; - struct cm_counter_attribute *cm_attr; - - group = container_of(obj, struct cm_counter_group, obj); - cm_attr = container_of(attr, struct cm_counter_attribute, attr); - - return sprintf(buf, "%ld\n", - atomic_long_read(&group->counter[cm_attr->index])); -} - -static struct sysfs_ops cm_counter_ops = { - .show = cm_show_counter -}; - -static struct kobj_type cm_counter_obj_type = { - .sysfs_ops = &cm_counter_ops, - .default_attrs = cm_counter_default_attrs -}; - -static void cm_release_port_obj(struct kobject *obj) -{ - struct cm_port *cm_port; - - printk(KERN_ERR "free cm port\n"); - - cm_port = container_of(obj, struct cm_port, port_obj); - kfree(cm_port); -} - -static struct kobj_type cm_port_obj_type = { - .release = cm_release_port_obj -}; - -static void cm_release_dev_obj(struct kobject *obj) -{ - struct cm_device *cm_dev; - - printk(KERN_ERR "free cm dev\n"); - - cm_dev = container_of(obj, struct cm_device, dev_obj); - kfree(cm_dev); -} - -static struct kobj_type cm_dev_obj_type = { - .release = cm_release_dev_obj -}; - -struct class cm_class = { - .name = "infiniband_cm", -}; -EXPORT_SYMBOL(cm_class); - -static void cm_remove_fs_obj(struct kobject *obj) -{ - kobject_put(obj->parent); - kobject_put(obj); -} - -static int cm_create_port_fs(struct cm_port *port) -{ - int i, ret; - - ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type, - kobject_get(&port->cm_dev->dev_obj), - "%d", port->port_num); - if (ret) { - kfree(port); - return ret; - } - - for (i = 0; i < CM_COUNTER_GROUPS; i++) { - ret = kobject_init_and_add(&port->counter_group[i].obj, - &cm_counter_obj_type, - kobject_get(&port->port_obj), - "%s", counter_group_names[i]); - if (ret) - goto error; - } - - return 0; - -error: - while (i--) - cm_remove_fs_obj(&port->counter_group[i].obj); - cm_remove_fs_obj(&port->port_obj); - return ret; - -} - -static void cm_remove_port_fs(struct cm_port *port) -{ - int i; - - for (i = 0; i < CM_COUNTER_GROUPS; i++) - cm_remove_fs_obj(&port->counter_group[i].obj); - - cm_remove_fs_obj(&port->port_obj); -} - static void cm_add_one(struct ib_device *device) { struct cm_device *cm_dev; @@ -3638,7 +3397,7 @@ static void cm_add_one(struct ib_device *device) if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) return; - cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) * + cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) * device->phys_port_cnt, GFP_KERNEL); if (!cm_dev) return; @@ -3646,27 +3405,11 @@ static void cm_add_one(struct ib_device *device) cm_dev->device = device; cm_get_ack_delay(cm_dev); - ret = kobject_init_and_add(&cm_dev->dev_obj, &cm_dev_obj_type, - &cm_class.subsys.kobj, "%s", device->name); - if (ret) { - kfree(cm_dev); - return; - } - set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask); for (i = 1; i <= device->phys_port_cnt; i++) { - port = kzalloc(sizeof *port, GFP_KERNEL); - if (!port) - goto error1; - - cm_dev->port[i-1] = port; + port = &cm_dev->port[i-1]; port->cm_dev = cm_dev; port->port_num = i; - - ret = cm_create_port_fs(port); - if (ret) - goto error1; - port->mad_agent = ib_register_mad_agent(device, i, IB_QPT_GSI, ®_req, @@ -3675,11 +3418,11 @@ static void cm_add_one(struct ib_device *device) cm_recv_handler, port); if (IS_ERR(port->mad_agent)) - goto error2; + goto error1; ret = ib_modify_port(device, i, 0, &port_modify); if (ret) - goto error3; + goto error2; } ib_set_client_data(device, &cm_client, cm_dev); @@ -3688,20 +3431,17 @@ static void cm_add_one(struct ib_device *device) write_unlock_irqrestore(&cm.device_lock, flags); return; -error3: - ib_unregister_mad_agent(port->mad_agent); error2: - cm_remove_port_fs(port); + ib_unregister_mad_agent(port->mad_agent); error1: port_modify.set_port_cap_mask = 0; port_modify.clr_port_cap_mask = IB_PORT_CM_SUP; while (--i) { - port = cm_dev->port[i-1]; + port = &cm_dev->port[i-1]; ib_modify_port(device, port->port_num, 0, &port_modify); ib_unregister_mad_agent(port->mad_agent); - cm_remove_port_fs(port); } - cm_remove_fs_obj(&cm_dev->dev_obj); + kfree(cm_dev); } static void cm_remove_one(struct ib_device *device) @@ -3723,12 +3463,11 @@ static void cm_remove_one(struct ib_device *device) write_unlock_irqrestore(&cm.device_lock, flags); for (i = 1; i <= device->phys_port_cnt; i++) { - port = cm_dev->port[i-1]; + port = &cm_dev->port[i-1]; ib_modify_port(device, port->port_num, 0, &port_modify); ib_unregister_mad_agent(port->mad_agent); - cm_remove_port_fs(port); } - cm_remove_fs_obj(&cm_dev->dev_obj); + kfree(cm_dev); } static int __init ib_cm_init(void) @@ -3749,25 +3488,17 @@ static int __init ib_cm_init(void) idr_pre_get(&cm.local_id_table, GFP_KERNEL); INIT_LIST_HEAD(&cm.timewait_list); - ret = class_register(&cm_class); - if (ret) - return -ENOMEM; - cm.wq = create_workqueue("ib_cm"); - if (!cm.wq) { - ret = -ENOMEM; - goto error1; - } + if (!cm.wq) + return -ENOMEM; ret = ib_register_client(&cm_client); if (ret) - goto error2; + goto error; return 0; -error2: +error: destroy_workqueue(cm.wq); -error1: - class_unregister(&cm_class); return ret; } @@ -3788,7 +3519,6 @@ static void __exit ib_cm_cleanup(void) } ib_unregister_client(&cm_client); - class_unregister(&cm_class); idr_destroy(&cm.local_id_table); } diff --git a/trunk/drivers/infiniband/core/cma.c b/trunk/drivers/infiniband/core/cma.c index 637efead97a0..0751697ef984 100644 --- a/trunk/drivers/infiniband/core/cma.c +++ b/trunk/drivers/infiniband/core/cma.c @@ -488,8 +488,7 @@ void rdma_destroy_qp(struct rdma_cm_id *id) } EXPORT_SYMBOL(rdma_destroy_qp); -static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, - struct rdma_conn_param *conn_param) +static int cma_modify_qp_rtr(struct rdma_id_private *id_priv) { struct ib_qp_attr qp_attr; int qp_attr_mask, ret; @@ -515,16 +514,13 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, if (ret) goto out; - if (conn_param) - qp_attr.max_dest_rd_atomic = conn_param->responder_resources; ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); out: mutex_unlock(&id_priv->qp_mutex); return ret; } -static int cma_modify_qp_rts(struct rdma_id_private *id_priv, - struct rdma_conn_param *conn_param) +static int cma_modify_qp_rts(struct rdma_id_private *id_priv) { struct ib_qp_attr qp_attr; int qp_attr_mask, ret; @@ -540,8 +536,6 @@ static int cma_modify_qp_rts(struct rdma_id_private *id_priv, if (ret) goto out; - if (conn_param) - qp_attr.max_rd_atomic = conn_param->initiator_depth; ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); out: mutex_unlock(&id_priv->qp_mutex); @@ -872,11 +866,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv) { int ret; - ret = cma_modify_qp_rtr(id_priv, NULL); + ret = cma_modify_qp_rtr(id_priv); if (ret) goto reject; - ret = cma_modify_qp_rts(id_priv, NULL); + ret = cma_modify_qp_rts(id_priv); if (ret) goto reject; @@ -1128,10 +1122,8 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) cm_id->cm_handler = cma_ib_handler; ret = conn_id->id.event_handler(&conn_id->id, &event); - if (!ret) { - cma_enable_remove(conn_id); + if (!ret) goto out; - } /* Destroy the CM ID by returning a non-zero value. */ conn_id->cm_id.ib = NULL; @@ -1270,7 +1262,6 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, struct net_device *dev = NULL; struct rdma_cm_event event; int ret; - struct ib_device_attr attr; listen_id = cm_id->context; if (cma_disable_remove(listen_id, CMA_LISTEN)) @@ -1320,19 +1311,10 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; *sin = iw_event->remote_addr; - ret = ib_query_device(conn_id->id.device, &attr); - if (ret) { - cma_enable_remove(conn_id); - rdma_destroy_id(new_cm_id); - goto out; - } - memset(&event, 0, sizeof event); event.event = RDMA_CM_EVENT_CONNECT_REQUEST; event.param.conn.private_data = iw_event->private_data; event.param.conn.private_data_len = iw_event->private_data_len; - event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; - event.param.conn.responder_resources = attr.max_qp_rd_atom; ret = conn_id->id.event_handler(&conn_id->id, &event); if (ret) { /* User wants to destroy the CM ID */ @@ -2290,7 +2272,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv, sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; cm_id->remote_addr = *sin; - ret = cma_modify_qp_rtr(id_priv, conn_param); + ret = cma_modify_qp_rtr(id_priv); if (ret) goto out; @@ -2353,15 +2335,25 @@ static int cma_accept_ib(struct rdma_id_private *id_priv, struct rdma_conn_param *conn_param) { struct ib_cm_rep_param rep; - int ret; + struct ib_qp_attr qp_attr; + int qp_attr_mask, ret; - ret = cma_modify_qp_rtr(id_priv, conn_param); - if (ret) - goto out; + if (id_priv->id.qp) { + ret = cma_modify_qp_rtr(id_priv); + if (ret) + goto out; - ret = cma_modify_qp_rts(id_priv, conn_param); - if (ret) - goto out; + qp_attr.qp_state = IB_QPS_RTS; + ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr, + &qp_attr_mask); + if (ret) + goto out; + + qp_attr.max_rd_atomic = conn_param->initiator_depth; + ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); + if (ret) + goto out; + } memset(&rep, 0, sizeof rep); rep.qp_num = id_priv->qp_num; @@ -2386,7 +2378,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv, struct iw_cm_conn_param iw_param; int ret; - ret = cma_modify_qp_rtr(id_priv, conn_param); + ret = cma_modify_qp_rtr(id_priv); if (ret) return ret; @@ -2606,9 +2598,11 @@ static void cma_set_mgid(struct rdma_id_private *id_priv, /* IPv6 address is an SA assigned MGID. */ memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); } else { - ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); + ip_ib_mc_map(sin->sin_addr.s_addr, mc_map); if (id_priv->id.ps == RDMA_PS_UDP) mc_map[7] = 0x01; /* Use RDMA CM signature */ + mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8; + mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr); *mgid = *(union ib_gid *) (mc_map + 4); } } diff --git a/trunk/drivers/infiniband/core/fmr_pool.c b/trunk/drivers/infiniband/core/fmr_pool.c index 6c7aa59794d4..e8d5f6b64998 100644 --- a/trunk/drivers/infiniband/core/fmr_pool.c +++ b/trunk/drivers/infiniband/core/fmr_pool.c @@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool, static void ib_fmr_batch_release(struct ib_fmr_pool *pool) { int ret; - struct ib_pool_fmr *fmr, *next; + struct ib_pool_fmr *fmr; LIST_HEAD(unmap_list); LIST_HEAD(fmr_list); @@ -158,20 +158,6 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) #endif } - /* - * The free_list may hold FMRs that have been put there - * because they haven't reached the max_remap count. - * Invalidate their mapping as well. - */ - list_for_each_entry_safe(fmr, next, &pool->free_list, list) { - if (fmr->remap_count == 0) - continue; - hlist_del_init(&fmr->cache_node); - fmr->remap_count = 0; - list_add_tail(&fmr->fmr->list, &fmr_list); - list_move(&fmr->list, &unmap_list); - } - list_splice(&pool->dirty_list, &unmap_list); INIT_LIST_HEAD(&pool->dirty_list); pool->dirty_len = 0; @@ -196,7 +182,8 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) struct ib_fmr_pool *pool = pool_ptr; do { - if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) { + if (pool->dirty_len >= pool->dirty_watermark || + atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) { ib_fmr_batch_release(pool); atomic_inc(&pool->flush_ser); @@ -207,7 +194,8 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) } set_current_state(TASK_INTERRUPTIBLE); - if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 && + if (pool->dirty_len < pool->dirty_watermark && + atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 && !kthread_should_stop()) schedule(); __set_current_state(TASK_RUNNING); @@ -381,6 +369,11 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool) i = 0; list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) { + if (fmr->remap_count) { + INIT_LIST_HEAD(&fmr_list); + list_add_tail(&fmr->fmr->list, &fmr_list); + ib_unmap_fmr(&fmr_list); + } ib_dealloc_fmr(fmr->fmr); list_del(&fmr->list); kfree(fmr); @@ -518,10 +511,8 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) list_add_tail(&fmr->list, &pool->free_list); } else { list_add_tail(&fmr->list, &pool->dirty_list); - if (++pool->dirty_len >= pool->dirty_watermark) { - atomic_inc(&pool->req_ser); - wake_up_process(pool->thread); - } + ++pool->dirty_len; + wake_up_process(pool->thread); } } diff --git a/trunk/drivers/infiniband/core/mad.c b/trunk/drivers/infiniband/core/mad.c index fbe16d5250a4..6f4287716ab1 100644 --- a/trunk/drivers/infiniband/core/mad.c +++ b/trunk/drivers/infiniband/core/mad.c @@ -701,8 +701,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, } /* Check to post send on QP or process locally */ - if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD && - smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD) + if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD) goto out; local = kmalloc(sizeof *local, GFP_ATOMIC); @@ -753,7 +752,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, port_priv = ib_get_mad_port(mad_agent_priv->agent.device, mad_agent_priv->agent.port_num); if (port_priv) { - memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad)); + mad_priv->mad.mad.mad_hdr.tid = + ((struct ib_mad *)smp)->mad_hdr.tid; recv_mad_agent = find_mad_agent(port_priv, &mad_priv->mad.mad); } @@ -1100,9 +1100,7 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf, mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid; /* Timeout will be updated after send completes */ mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms); - mad_send_wr->max_retries = send_buf->retries; - mad_send_wr->retries_left = send_buf->retries; - send_buf->retries = 0; + mad_send_wr->retries = send_buf->retries; /* Reference for work request to QP + response */ mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0); mad_send_wr->status = IB_WC_SUCCESS; @@ -1933,6 +1931,15 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv, if (port_priv->device->process_mad) { int ret; + if (!response) { + printk(KERN_ERR PFX "No memory for response MAD\n"); + /* + * Is it better to assume that + * it wouldn't be processed ? + */ + goto out; + } + ret = port_priv->device->process_mad(port_priv->device, 0, port_priv->port_num, wc, &recv->grh, @@ -2275,6 +2282,8 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv) /* Empty wait list to prevent receives from finding a request */ list_splice_init(&mad_agent_priv->wait_list, &cancel_list); + /* Empty local completion list as well */ + list_splice_init(&mad_agent_priv->local_list, &cancel_list); spin_unlock_irqrestore(&mad_agent_priv->lock, flags); /* Report all cancelled requests */ @@ -2436,12 +2445,9 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr) { int ret; - if (!mad_send_wr->retries_left) + if (!mad_send_wr->retries--) return -ETIMEDOUT; - mad_send_wr->retries_left--; - mad_send_wr->send_buf.retries++; - mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); if (mad_send_wr->mad_agent_priv->agent.rmpp_version) { diff --git a/trunk/drivers/infiniband/core/mad_priv.h b/trunk/drivers/infiniband/core/mad_priv.h index 8b75010016ec..9be5cc00a3a9 100644 --- a/trunk/drivers/infiniband/core/mad_priv.h +++ b/trunk/drivers/infiniband/core/mad_priv.h @@ -131,8 +131,7 @@ struct ib_mad_send_wr_private { struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; __be64 tid; unsigned long timeout; - int max_retries; - int retries_left; + int retries; int retry; int refcount; enum ib_wc_status status; diff --git a/trunk/drivers/infiniband/core/mad_rmpp.c b/trunk/drivers/infiniband/core/mad_rmpp.c index a5e2a310f312..d43bc62005b3 100644 --- a/trunk/drivers/infiniband/core/mad_rmpp.c +++ b/trunk/drivers/infiniband/core/mad_rmpp.c @@ -684,7 +684,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, if (seg_num > mad_send_wr->last_ack) { adjust_last_ack(mad_send_wr, seg_num); - mad_send_wr->retries_left = mad_send_wr->max_retries; + mad_send_wr->retries = mad_send_wr->send_buf.retries; } mad_send_wr->newwin = newwin; if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) { diff --git a/trunk/drivers/infiniband/core/multicast.c b/trunk/drivers/infiniband/core/multicast.c index 107f170c57cd..1bc1fe605282 100644 --- a/trunk/drivers/infiniband/core/multicast.c +++ b/trunk/drivers/infiniband/core/multicast.c @@ -73,20 +73,11 @@ struct mcast_device { }; enum mcast_state { + MCAST_IDLE, MCAST_JOINING, MCAST_MEMBER, - MCAST_ERROR, -}; - -enum mcast_group_state { - MCAST_IDLE, MCAST_BUSY, - MCAST_GROUP_ERROR, - MCAST_PKEY_EVENT -}; - -enum { - MCAST_INVALID_PKEY_INDEX = 0xFFFF + MCAST_ERROR }; struct mcast_member; @@ -102,10 +93,9 @@ struct mcast_group { struct mcast_member *last_join; int members[3]; atomic_t refcount; - enum mcast_group_state state; + enum mcast_state state; struct ib_sa_query *query; int query_id; - u16 pkey_index; }; struct mcast_member { @@ -388,19 +378,9 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member, static void process_group_error(struct mcast_group *group) { struct mcast_member *member; - int ret = 0; - u16 pkey_index; - - if (group->state == MCAST_PKEY_EVENT) - ret = ib_find_pkey(group->port->dev->device, - group->port->port_num, - be16_to_cpu(group->rec.pkey), &pkey_index); + int ret; spin_lock_irq(&group->lock); - if (group->state == MCAST_PKEY_EVENT && !ret && - group->pkey_index == pkey_index) - goto out; - while (!list_empty(&group->active_list)) { member = list_entry(group->active_list.next, struct mcast_member, list); @@ -419,7 +399,6 @@ static void process_group_error(struct mcast_group *group) } group->rec.join_state = 0; -out: group->state = MCAST_BUSY; spin_unlock_irq(&group->lock); } @@ -436,9 +415,9 @@ static void mcast_work_handler(struct work_struct *work) retest: spin_lock_irq(&group->lock); while (!list_empty(&group->pending_list) || - (group->state != MCAST_BUSY)) { + (group->state == MCAST_ERROR)) { - if (group->state != MCAST_BUSY) { + if (group->state == MCAST_ERROR) { spin_unlock_irq(&group->lock); process_group_error(group); goto retest; @@ -515,19 +494,12 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec, void *context) { struct mcast_group *group = context; - u16 pkey_index = MCAST_INVALID_PKEY_INDEX; if (status) process_join_error(group, status); else { - ib_find_pkey(group->port->dev->device, group->port->port_num, - be16_to_cpu(rec->pkey), &pkey_index); - spin_lock_irq(&group->port->lock); group->rec = *rec; - if (group->state == MCAST_BUSY && - group->pkey_index == MCAST_INVALID_PKEY_INDEX) - group->pkey_index = pkey_index; if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { rb_erase(&group->node, &group->port->table); mcast_insert(group->port, group, 1); @@ -567,7 +539,6 @@ static struct mcast_group *acquire_group(struct mcast_port *port, group->port = port; group->rec.mgid = *mgid; - group->pkey_index = MCAST_INVALID_PKEY_INDEX; INIT_LIST_HEAD(&group->pending_list); INIT_LIST_HEAD(&group->active_list); INIT_WORK(&group->work, mcast_work_handler); @@ -736,8 +707,7 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, } EXPORT_SYMBOL(ib_init_ah_from_mcmember); -static void mcast_groups_event(struct mcast_port *port, - enum mcast_group_state state) +static void mcast_groups_lost(struct mcast_port *port) { struct mcast_group *group; struct rb_node *node; @@ -751,8 +721,7 @@ static void mcast_groups_event(struct mcast_port *port, atomic_inc(&group->refcount); queue_work(mcast_wq, &group->work); } - if (group->state != MCAST_GROUP_ERROR) - group->state = state; + group->state = MCAST_ERROR; spin_unlock(&group->lock); } spin_unlock_irqrestore(&port->lock, flags); @@ -762,20 +731,16 @@ static void mcast_event_handler(struct ib_event_handler *handler, struct ib_event *event) { struct mcast_device *dev; - int index; dev = container_of(handler, struct mcast_device, event_handler); - index = event->element.port_num - dev->start_port; switch (event->event) { case IB_EVENT_PORT_ERR: case IB_EVENT_LID_CHANGE: case IB_EVENT_SM_CHANGE: case IB_EVENT_CLIENT_REREGISTER: - mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR); - break; - case IB_EVENT_PKEY_CHANGE: - mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT); + mcast_groups_lost(&dev->port[event->element.port_num - + dev->start_port]); break; default: break; diff --git a/trunk/drivers/infiniband/core/smi.h b/trunk/drivers/infiniband/core/smi.h index aff96bac49b4..1cfc2984434f 100644 --- a/trunk/drivers/infiniband/core/smi.h +++ b/trunk/drivers/infiniband/core/smi.h @@ -59,8 +59,7 @@ extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, u8 node_type, int port_num); /* - * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM - * via process_mad + * Return 1 if the SMP should be handled by the local SMA/SM via process_mad */ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp, struct ib_device *device) @@ -72,19 +71,4 @@ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp, (smp->hop_ptr == smp->hop_cnt + 1)) ? IB_SMI_HANDLE : IB_SMI_DISCARD); } - -/* - * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM - * via process_mad - */ -static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp, - struct ib_device *device) -{ - /* C14-13:3 -- We're at the end of the DR segment of path */ - /* C14-13:4 -- Hop Pointer == 0 -> give to SM */ - return ((device->process_mad && - ib_get_smp_direction(smp) && - !smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD); -} - #endif /* __SMI_H_ */ diff --git a/trunk/drivers/infiniband/core/ucm.c b/trunk/drivers/infiniband/core/ucm.c index 4291ab42a5b9..424983f5b1ee 100644 --- a/trunk/drivers/infiniband/core/ucm.c +++ b/trunk/drivers/infiniband/core/ucm.c @@ -106,9 +106,6 @@ enum { IB_UCM_MAX_DEVICES = 32 }; -/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */ -extern struct class cm_class; - #define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR) static void ib_ucm_add_one(struct ib_device *device); @@ -1202,7 +1199,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) return 0; } -static void ucm_release_class_dev(struct class_device *class_dev) +static void ib_ucm_release_class_dev(struct class_device *class_dev) { struct ib_ucm_device *dev; @@ -1220,6 +1217,11 @@ static const struct file_operations ucm_fops = { .poll = ib_ucm_poll, }; +static struct class ucm_class = { + .name = "infiniband_cm", + .release = ib_ucm_release_class_dev +}; + static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { struct ib_ucm_device *dev; @@ -1255,10 +1257,9 @@ static void ib_ucm_add_one(struct ib_device *device) if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1)) goto err; - ucm_dev->class_dev.class = &cm_class; + ucm_dev->class_dev.class = &ucm_class; ucm_dev->class_dev.dev = device->dma_device; ucm_dev->class_dev.devt = ucm_dev->dev.dev; - ucm_dev->class_dev.release = ucm_release_class_dev; snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d", ucm_dev->devnum); if (class_device_register(&ucm_dev->class_dev)) @@ -1305,34 +1306,40 @@ static int __init ib_ucm_init(void) "infiniband_cm"); if (ret) { printk(KERN_ERR "ucm: couldn't register device number\n"); - goto error1; + goto err; } - ret = class_create_file(&cm_class, &class_attr_abi_version); + ret = class_register(&ucm_class); + if (ret) { + printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n"); + goto err_chrdev; + } + + ret = class_create_file(&ucm_class, &class_attr_abi_version); if (ret) { printk(KERN_ERR "ucm: couldn't create abi_version attribute\n"); - goto error2; + goto err_class; } ret = ib_register_client(&ucm_client); if (ret) { printk(KERN_ERR "ucm: couldn't register client\n"); - goto error3; + goto err_class; } return 0; -error3: - class_remove_file(&cm_class, &class_attr_abi_version); -error2: +err_class: + class_unregister(&ucm_class); +err_chrdev: unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); -error1: +err: return ret; } static void __exit ib_ucm_cleanup(void) { ib_unregister_client(&ucm_client); - class_remove_file(&cm_class, &class_attr_abi_version); + class_unregister(&ucm_class); unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); idr_destroy(&ctx_id_table); } diff --git a/trunk/drivers/infiniband/core/ucma.c b/trunk/drivers/infiniband/core/ucma.c index 15937eb38aae..90d675ad9ec8 100644 --- a/trunk/drivers/infiniband/core/ucma.c +++ b/trunk/drivers/infiniband/core/ucma.c @@ -31,7 +31,6 @@ */ #include -#include #include #include #include @@ -992,96 +991,6 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file, return ret; } -static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2) -{ - /* Acquire mutex's based on pointer comparison to prevent deadlock. */ - if (file1 < file2) { - mutex_lock(&file1->mut); - mutex_lock(&file2->mut); - } else { - mutex_lock(&file2->mut); - mutex_lock(&file1->mut); - } -} - -static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2) -{ - if (file1 < file2) { - mutex_unlock(&file2->mut); - mutex_unlock(&file1->mut); - } else { - mutex_unlock(&file1->mut); - mutex_unlock(&file2->mut); - } -} - -static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file) -{ - struct ucma_event *uevent, *tmp; - - list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) - if (uevent->ctx == ctx) - list_move_tail(&uevent->list, &file->event_list); -} - -static ssize_t ucma_migrate_id(struct ucma_file *new_file, - const char __user *inbuf, - int in_len, int out_len) -{ - struct rdma_ucm_migrate_id cmd; - struct rdma_ucm_migrate_resp resp; - struct ucma_context *ctx; - struct file *filp; - struct ucma_file *cur_file; - int ret = 0; - - if (copy_from_user(&cmd, inbuf, sizeof(cmd))) - return -EFAULT; - - /* Get current fd to protect against it being closed */ - filp = fget(cmd.fd); - if (!filp) - return -ENOENT; - - /* Validate current fd and prevent destruction of id. */ - ctx = ucma_get_ctx(filp->private_data, cmd.id); - if (IS_ERR(ctx)) { - ret = PTR_ERR(ctx); - goto file_put; - } - - cur_file = ctx->file; - if (cur_file == new_file) { - resp.events_reported = ctx->events_reported; - goto response; - } - - /* - * Migrate events between fd's, maintaining order, and avoiding new - * events being added before existing events. - */ - ucma_lock_files(cur_file, new_file); - mutex_lock(&mut); - - list_move_tail(&ctx->list, &new_file->ctx_list); - ucma_move_events(ctx, new_file); - ctx->file = new_file; - resp.events_reported = ctx->events_reported; - - mutex_unlock(&mut); - ucma_unlock_files(cur_file, new_file); - -response: - if (copy_to_user((void __user *)(unsigned long)cmd.response, - &resp, sizeof(resp))) - ret = -EFAULT; - - ucma_put_ctx(ctx); -file_put: - fput(filp); - return ret; -} - static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) = { @@ -1103,7 +1012,6 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, - [RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id }; static ssize_t ucma_write(struct file *filp, const char __user *buf, diff --git a/trunk/drivers/infiniband/core/user_mad.c b/trunk/drivers/infiniband/core/user_mad.c index 4e915104ac4c..b53eac4611de 100644 --- a/trunk/drivers/infiniband/core/user_mad.c +++ b/trunk/drivers/infiniband/core/user_mad.c @@ -2,7 +2,6 @@ * Copyright (c) 2004 Topspin Communications. All rights reserved. * Copyright (c) 2005 Voltaire, Inc. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. - * Copyright (c) 2008 Cisco. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -43,7 +42,7 @@ #include #include #include -#include +#include #include #include @@ -95,7 +94,7 @@ struct ib_umad_port { struct class_device *sm_class_dev; struct semaphore sm_sem; - struct mutex file_mutex; + struct rw_semaphore mutex; struct list_head file_list; struct ib_device *ib_dev; @@ -111,11 +110,11 @@ struct ib_umad_device { }; struct ib_umad_file { - struct mutex mutex; struct ib_umad_port *port; struct list_head recv_list; struct list_head send_list; struct list_head port_list; + spinlock_t recv_lock; spinlock_t send_lock; wait_queue_head_t recv_wait; struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; @@ -157,7 +156,7 @@ static int hdr_size(struct ib_umad_file *file) sizeof (struct ib_user_mad_hdr_old); } -/* caller must hold file->mutex */ +/* caller must hold port->mutex at least for reading */ static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id) { return file->agents_dead ? NULL : file->agent[id]; @@ -169,30 +168,32 @@ static int queue_packet(struct ib_umad_file *file, { int ret = 1; - mutex_lock(&file->mutex); + down_read(&file->port->mutex); for (packet->mad.hdr.id = 0; packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; packet->mad.hdr.id++) if (agent == __get_agent(file, packet->mad.hdr.id)) { + spin_lock_irq(&file->recv_lock); list_add_tail(&packet->list, &file->recv_list); + spin_unlock_irq(&file->recv_lock); wake_up_interruptible(&file->recv_wait); ret = 0; break; } - mutex_unlock(&file->mutex); + up_read(&file->port->mutex); return ret; } static void dequeue_send(struct ib_umad_file *file, struct ib_umad_packet *packet) -{ + { spin_lock_irq(&file->send_lock); list_del(&packet->list); spin_unlock_irq(&file->send_lock); -} + } static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *send_wc) @@ -340,10 +341,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, if (count < hdr_size(file)) return -EINVAL; - mutex_lock(&file->mutex); + spin_lock_irq(&file->recv_lock); while (list_empty(&file->recv_list)) { - mutex_unlock(&file->mutex); + spin_unlock_irq(&file->recv_lock); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; @@ -352,13 +353,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, !list_empty(&file->recv_list))) return -ERESTARTSYS; - mutex_lock(&file->mutex); + spin_lock_irq(&file->recv_lock); } packet = list_entry(file->recv_list.next, struct ib_umad_packet, list); list_del(&packet->list); - mutex_unlock(&file->mutex); + spin_unlock_irq(&file->recv_lock); if (packet->recv_wc) ret = copy_recv_mad(file, buf, packet, count); @@ -367,9 +368,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, if (ret < 0) { /* Requeue packet */ - mutex_lock(&file->mutex); + spin_lock_irq(&file->recv_lock); list_add(&packet->list, &file->recv_list); - mutex_unlock(&file->mutex); + spin_unlock_irq(&file->recv_lock); } else { if (packet->recv_wc) ib_free_recv_mad(packet->recv_wc); @@ -480,7 +481,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err; } - mutex_lock(&file->mutex); + down_read(&file->port->mutex); agent = __get_agent(file, packet->mad.hdr.id); if (!agent) { @@ -576,7 +577,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, if (ret) goto err_send; - mutex_unlock(&file->mutex); + up_read(&file->port->mutex); return count; err_send: @@ -586,7 +587,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, err_ah: ib_destroy_ah(ah); err_up: - mutex_unlock(&file->mutex); + up_read(&file->port->mutex); err: kfree(packet); return ret; @@ -612,12 +613,11 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, { struct ib_user_mad_reg_req ureq; struct ib_mad_reg_req req; - struct ib_mad_agent *agent = NULL; + struct ib_mad_agent *agent; int agent_id; int ret; - mutex_lock(&file->port->file_mutex); - mutex_lock(&file->mutex); + down_write(&file->port->mutex); if (!file->port->ib_dev) { ret = -EPIPE; @@ -666,13 +666,13 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, send_handler, recv_handler, file); if (IS_ERR(agent)) { ret = PTR_ERR(agent); - agent = NULL; goto out; } if (put_user(agent_id, (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) { ret = -EFAULT; + ib_unregister_mad_agent(agent); goto out; } @@ -690,13 +690,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, ret = 0; out: - mutex_unlock(&file->mutex); - - if (ret && agent) - ib_unregister_mad_agent(agent); - - mutex_unlock(&file->port->file_mutex); - + up_write(&file->port->mutex); return ret; } @@ -709,8 +703,7 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) if (get_user(id, arg)) return -EFAULT; - mutex_lock(&file->port->file_mutex); - mutex_lock(&file->mutex); + down_write(&file->port->mutex); if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) { ret = -EINVAL; @@ -721,13 +714,11 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) file->agent[id] = NULL; out: - mutex_unlock(&file->mutex); + up_write(&file->port->mutex); if (agent) ib_unregister_mad_agent(agent); - mutex_unlock(&file->port->file_mutex); - return ret; } @@ -735,12 +726,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file) { int ret = 0; - mutex_lock(&file->mutex); + down_write(&file->port->mutex); if (file->already_used) ret = -EINVAL; else file->use_pkey_index = 1; - mutex_unlock(&file->mutex); + up_write(&file->port->mutex); return ret; } @@ -792,7 +783,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) if (!port) return -ENXIO; - mutex_lock(&port->file_mutex); + down_write(&port->mutex); if (!port->ib_dev) { ret = -ENXIO; @@ -806,7 +797,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) goto out; } - mutex_init(&file->mutex); + spin_lock_init(&file->recv_lock); spin_lock_init(&file->send_lock); INIT_LIST_HEAD(&file->recv_list); INIT_LIST_HEAD(&file->send_list); @@ -818,7 +809,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) list_add_tail(&file->port_list, &port->file_list); out: - mutex_unlock(&port->file_mutex); + up_write(&port->mutex); return ret; } @@ -830,8 +821,7 @@ static int ib_umad_close(struct inode *inode, struct file *filp) int already_dead; int i; - mutex_lock(&file->port->file_mutex); - mutex_lock(&file->mutex); + down_write(&file->port->mutex); already_dead = file->agents_dead; file->agents_dead = 1; @@ -844,14 +834,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp) list_del(&file->port_list); - mutex_unlock(&file->mutex); + downgrade_write(&file->port->mutex); if (!already_dead) for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) if (file->agent[i]) ib_unregister_mad_agent(file->agent[i]); - mutex_unlock(&file->port->file_mutex); + up_read(&file->port->mutex); kfree(file); kref_put(&dev->ref, ib_umad_release_dev); @@ -924,10 +914,10 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp) }; int ret = 0; - mutex_lock(&port->file_mutex); + down_write(&port->mutex); if (port->ib_dev) ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); - mutex_unlock(&port->file_mutex); + up_write(&port->mutex); up(&port->sm_sem); @@ -991,7 +981,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, port->ib_dev = device; port->port_num = port_num; init_MUTEX(&port->sm_sem); - mutex_init(&port->file_mutex); + init_rwsem(&port->mutex); INIT_LIST_HEAD(&port->file_list); port->dev = cdev_alloc(); @@ -1062,7 +1052,6 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, static void ib_umad_kill_port(struct ib_umad_port *port) { struct ib_umad_file *file; - int already_dead; int id; class_set_devdata(port->class_dev, NULL); @@ -1078,22 +1067,42 @@ static void ib_umad_kill_port(struct ib_umad_port *port) umad_port[port->dev_num] = NULL; spin_unlock(&port_lock); - mutex_lock(&port->file_mutex); + down_write(&port->mutex); port->ib_dev = NULL; - list_for_each_entry(file, &port->file_list, port_list) { - mutex_lock(&file->mutex); - already_dead = file->agents_dead; + /* + * Now go through the list of files attached to this port and + * unregister all of their MAD agents. We need to hold + * port->mutex while doing this to avoid racing with + * ib_umad_close(), but we can't hold the mutex for writing + * while calling ib_unregister_mad_agent(), since that might + * deadlock by calling back into queue_packet(). So we + * downgrade our lock to a read lock, and then drop and + * reacquire the write lock for the next iteration. + * + * We do list_del_init() on the file's list_head so that the + * list_del in ib_umad_close() is still OK, even after the + * file is removed from the list. + */ + while (!list_empty(&port->file_list)) { + file = list_entry(port->file_list.next, struct ib_umad_file, + port_list); + file->agents_dead = 1; - mutex_unlock(&file->mutex); + list_del_init(&file->port_list); + + downgrade_write(&port->mutex); for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) if (file->agent[id]) ib_unregister_mad_agent(file->agent[id]); + + up_read(&port->mutex); + down_write(&port->mutex); } - mutex_unlock(&port->file_mutex); + up_write(&port->mutex); clear_bit(port->dev_num, dev_map); } diff --git a/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c b/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c index 03c5ff62889a..eec6a30840ca 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/trunk/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -179,7 +179,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) setup.size = 1UL << cq->size_log2; setup.credits = 65535; setup.credit_thres = 1; - if (rdev_p->t3cdev_p->type != T3A) + if (rdev_p->t3cdev_p->type == T3B) setup.ovfl_mode = 0; else setup.ovfl_mode = 1; @@ -584,7 +584,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr, { u32 i, nr_wqe, copy_len; u8 *copy_data; - u8 wr_len, utx_len; /* length in 8 byte flit */ + u8 wr_len, utx_len; /* lenght in 8 byte flit */ enum t3_wr_flags flag; __be64 *wqe; u64 utx_cmd; diff --git a/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h b/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h index 969d4d928455..c84d4ac49355 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/trunk/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -315,7 +315,7 @@ struct t3_rdma_init_wr { __be32 ird; __be64 qp_dma_addr; /* 7 */ __be32 qp_dma_size; /* 8 */ - __be32 irs; + u32 irs; }; struct t3_genbit { @@ -324,8 +324,7 @@ struct t3_genbit { }; enum rdma_init_wr_flags { - RECVS_POSTED = (1<<0), - PRIV_QP = (1<<1), + RECVS_POSTED = 1, }; union t3_wr { diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c index f8cb0fe748c3..20ba372dd182 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1118,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) status2errno(rpl->status)); connect_reply_upcall(ep, status2errno(rpl->status)); state_set(&ep->com, DEAD); - if (ep->com.tdev->type != T3A && act_open_has_tid(rpl->status)) + if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status)) release_tid(ep->com.tdev, GET_TID(rpl), NULL); cxgb3_free_atid(ep->com.tdev, ep->atid); dst_release(ep->dst); @@ -1249,7 +1249,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip, skb_trim(skb, sizeof(struct cpl_tid_release)); skb_get(skb); - if (tdev->type != T3A) + if (tdev->type == T3B) release_tid(tdev, hwtid, skb); else { struct cpl_pass_accept_rpl *rpl; diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_mem.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_mem.c index 73bfd1656f86..a6c2c4ba29e6 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_mem.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_mem.c @@ -122,13 +122,6 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list, *total_size += buffer_list[i].size; if (i > 0) mask |= buffer_list[i].addr; - else - mask |= buffer_list[i].addr & PAGE_MASK; - if (i != num_phys_buf - 1) - mask |= buffer_list[i].addr + buffer_list[i].size; - else - mask |= (buffer_list[i].addr + buffer_list[i].size + - PAGE_SIZE - 1) & PAGE_MASK; } if (*total_size > 0xFFFFFFFFULL) diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c index df1838f8f94d..b5436ca92e68 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -646,7 +645,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (err) goto err; - if (udata && !t3a_device(rhp)) { + if (udata && t3b_device(rhp)) { uresp.pbl_addr = (mhp->attr.pbl_addr - rhp->rdev.rnic_info.pbl_base) >> 3; PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__, @@ -1054,9 +1053,7 @@ static ssize_t show_fw_ver(struct class_device *cdev, char *buf) struct net_device *lldev = dev->rdev.t3cdev_p->lldev; PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev); - rtnl_lock(); lldev->ethtool_ops->get_drvinfo(lldev, &info); - rtnl_unlock(); return sprintf(buf, "%s\n", info.fw_version); } @@ -1068,9 +1065,7 @@ static ssize_t show_hca(struct class_device *cdev, char *buf) struct net_device *lldev = dev->rdev.t3cdev_p->lldev; PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev); - rtnl_lock(); lldev->ethtool_ops->get_drvinfo(lldev, &info); - rtnl_unlock(); return sprintf(buf, "%s\n", info.driver); } diff --git a/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c b/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c index ea2cdd73dd85..dd89b6b91f9c 100644 --- a/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/trunk/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -208,19 +208,36 @@ static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list, static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe, struct ib_recv_wr *wr) { - int i; + int i, err = 0; + u32 pbl_addr[4]; + u8 page_size[4]; if (wr->num_sge > T3_MAX_SGE) return -EINVAL; + err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr, + page_size); + if (err) + return err; + wqe->recv.pagesz[0] = page_size[0]; + wqe->recv.pagesz[1] = page_size[1]; + wqe->recv.pagesz[2] = page_size[2]; + wqe->recv.pagesz[3] = page_size[3]; wqe->recv.num_sgle = cpu_to_be32(wr->num_sge); for (i = 0; i < wr->num_sge; i++) { wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey); wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length); - wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr); + + /* to in the WQE == the offset into the page */ + wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) % + (1UL << (12 + page_size[i]))); + + /* pbl_addr is the adapters address in the PBL */ + wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]); } for (; i < T3_MAX_SGE; i++) { wqe->recv.sgl[i].stag = 0; wqe->recv.sgl[i].len = 0; wqe->recv.sgl[i].to = 0; + wqe->recv.pbl_addr[i] = 0; } return 0; } @@ -642,7 +659,6 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) cxio_flush_rq(&qhp->wq, &rchp->cq, count); spin_unlock(&qhp->lock); spin_unlock_irqrestore(&rchp->lock, *flag); - (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); /* locking heirarchy: cq lock first, then qp lock. */ spin_lock_irqsave(&schp->lock, *flag); @@ -652,7 +668,6 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) cxio_flush_sq(&qhp->wq, &schp->cq, count); spin_unlock(&qhp->lock); spin_unlock_irqrestore(&schp->lock, *flag); - (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); /* deref */ if (atomic_dec_and_test(&qhp->refcnt)) @@ -663,7 +678,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) { - if (qhp->ibqp.uobject) + if (t3b_device(qhp->rhp)) cxio_set_wq_in_error(&qhp->wq); else __flush_qp(qhp, flag); @@ -717,7 +732,6 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, init_attr.qp_dma_addr = qhp->wq.dma_addr; init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0; - init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0; init_attr.irs = qhp->ep->rcv_seq; PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d " "flags 0x%x qpcaps 0x%x\n", __FUNCTION__, @@ -833,11 +847,10 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, disconnect = 1; ep = qhp->ep; } - flush_qp(qhp, &flag); break; case IWCH_QP_STATE_TERMINATE: qhp->attr.state = IWCH_QP_STATE_TERMINATE; - if (qhp->ibqp.uobject) + if (t3b_device(qhp->rhp)) cxio_set_wq_in_error(&qhp->wq); if (!internal) terminate = 1; diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_av.c b/trunk/drivers/infiniband/hw/ehca/ehca_av.c index 194c1c30cf63..f7782c882ab4 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_av.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_av.c @@ -1,7 +1,7 @@ /* * IBM eServer eHCA Infiniband device driver for Linux on POWER * - * address vector functions + * adress vector functions * * Authors: Hoang-Nam Nguyen * Khadija Souissi diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_classes.h b/trunk/drivers/infiniband/hw/ehca/ehca_classes.h index f281d16040f5..74d2b72a11d8 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/trunk/drivers/infiniband/hw/ehca/ehca_classes.h @@ -94,11 +94,7 @@ struct ehca_sma_attr { struct ehca_sport { struct ib_cq *ibcq_aqp1; - struct ib_qp *ibqp_sqp[2]; - /* lock to serialze modify_qp() calls for sqp in normal - * and irq path (when event PORT_ACTIVE is received first time) - */ - spinlock_t mod_sqp_lock; + struct ib_qp *ibqp_aqp1; enum ib_port_state port_state; struct ehca_sma_attr saved_attr; }; @@ -145,14 +141,6 @@ enum ehca_ext_qp_type { EQPT_SRQ = 3, }; -/* struct to cache modify_qp()'s parms for GSI/SMI qp */ -struct ehca_mod_qp_parm { - int mask; - struct ib_qp_attr attr; -}; - -#define EHCA_MOD_QP_PARM_MAX 4 - struct ehca_qp { union { struct ib_qp ib_qp; @@ -176,18 +164,10 @@ struct ehca_qp { struct ehca_cq *recv_cq; unsigned int sqerr_purgeflag; struct hlist_node list_entries; - /* array to cache modify_qp()'s parms for GSI/SMI qp */ - struct ehca_mod_qp_parm *mod_qp_parm; - int mod_qp_parm_idx; /* mmap counter for resources mapped into user space */ u32 mm_count_squeue; u32 mm_count_rqueue; u32 mm_count_galpa; - /* unsolicited ack circumvention */ - int unsol_ack_circ; - int mtu_shift; - u32 message_count; - u32 packet_count; }; #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ) @@ -343,7 +323,6 @@ extern int ehca_port_act_time; extern int ehca_use_hp_mr; extern int ehca_scaling_code; extern int ehca_lock_hcalls; -extern int ehca_nr_ports; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_cq.c b/trunk/drivers/infiniband/hw/ehca/ehca_cq.c index 0467c158d4a9..79c25f51c21e 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_cq.c @@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, } else { if (h_ret != H_PAGE_REGISTERED) { ehca_err(device, "Registration of page failed " - "ehca_cq=%p cq_num=%x h_ret=%li " + "ehca_cq=%p cq_num=%x h_ret=%li" "counter=%i act_pages=%i", my_cq, my_cq->cq_number, h_ret, counter, param.act_pages); diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_irq.c b/trunk/drivers/infiniband/hw/ehca/ehca_irq.c index 863b34fa9ff9..3f617b27b954 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_irq.c @@ -62,7 +62,6 @@ #define NEQE_PORT_NUMBER EHCA_BMASK_IBM( 8, 15) #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16) #define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16, 16) -#define NEQE_SPECIFIC_EVENT EHCA_BMASK_IBM(16, 23) #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52, 63) #define ERROR_DATA_TYPE EHCA_BMASK_IBM( 0, 7) @@ -355,34 +354,17 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) { u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); - u8 spec_event; - struct ehca_sport *sport = &shca->sport[port - 1]; - unsigned long flags; switch (ec) { case 0x30: /* port availability change */ if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { - int suppress_event; - /* replay modify_qp for sqps */ - spin_lock_irqsave(&sport->mod_sqp_lock, flags); - suppress_event = !sport->ibqp_sqp[IB_QPT_GSI]; - if (sport->ibqp_sqp[IB_QPT_SMI]) - ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]); - if (!suppress_event) - ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]); - spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); - - /* AQP1 was destroyed, ignore this event */ - if (suppress_event) - break; - - sport->port_state = IB_PORT_ACTIVE; + shca->sport[port - 1].port_state = IB_PORT_ACTIVE; dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, "is active"); ehca_query_sma_attr(shca, port, - &sport->saved_attr); + &shca->sport[port - 1].saved_attr); } else { - sport->port_state = IB_PORT_DOWN; + shca->sport[port - 1].port_state = IB_PORT_DOWN; dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, "is inactive"); } @@ -396,11 +378,11 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) ehca_warn(&shca->ib_device, "disruptive port " "%d configuration change", port); - sport->port_state = IB_PORT_DOWN; + shca->sport[port - 1].port_state = IB_PORT_DOWN; dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, "is inactive"); - sport->port_state = IB_PORT_ACTIVE; + shca->sport[port - 1].port_state = IB_PORT_ACTIVE; dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, "is active"); } else @@ -412,16 +394,6 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) case 0x33: /* trace stopped */ ehca_err(&shca->ib_device, "Traced stopped."); break; - case 0x34: /* util async event */ - spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe); - if (spec_event == 0x80) /* client reregister required */ - dispatch_port_event(shca, port, - IB_EVENT_CLIENT_REREGISTER, - "client reregister req."); - else - ehca_warn(&shca->ib_device, "Unknown util async " - "event %x on port %x", spec_event, port); - break; default: ehca_err(&shca->ib_device, "Unknown event code: %x on %s.", ec, shca->ib_device.name); diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h b/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h index c469bfde2708..5485799cdc8d 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/trunk/drivers/infiniband/hw/ehca/ehca_iverbs.h @@ -200,6 +200,4 @@ void ehca_free_fw_ctrlblock(void *ptr); #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr)) #endif -void ehca_recover_sqp(struct ib_qp *sqp); - #endif diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_main.c b/trunk/drivers/infiniband/hw/ehca/ehca_main.c index 84c9b7b8669b..c9e32b46387f 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_main.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_main.c @@ -90,8 +90,7 @@ MODULE_PARM_DESC(hw_level, "hardware level" " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)"); MODULE_PARM_DESC(nr_ports, - "number of connected ports (-1: autodetect, 1: port one only, " - "2: two ports (default)"); + "number of connected ports (default: 2)"); MODULE_PARM_DESC(use_hp_mr, "high performance MRs (0: no (default), 1: yes)"); MODULE_PARM_DESC(port_act_time, @@ -512,7 +511,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port) } sport->ibcq_aqp1 = ibcq; - if (sport->ibqp_sqp[IB_QPT_GSI]) { + if (sport->ibqp_aqp1) { ehca_err(&shca->ib_device, "AQP1 QP is already created."); ret = -EPERM; goto create_aqp1; @@ -538,7 +537,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port) ret = PTR_ERR(ibqp); goto create_aqp1; } - sport->ibqp_sqp[IB_QPT_GSI] = ibqp; + sport->ibqp_aqp1 = ibqp; return 0; @@ -551,7 +550,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport) { int ret; - ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]); + ret = ib_destroy_qp(sport->ibqp_aqp1); if (ret) { ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret); return ret; @@ -694,7 +693,7 @@ static int __devinit ehca_probe(struct of_device *dev, struct ehca_shca *shca; const u64 *handle; struct ib_pd *ibpd; - int ret, i; + int ret; handle = of_get_property(dev->node, "ibm,hca-handle", NULL); if (!handle) { @@ -715,8 +714,6 @@ static int __devinit ehca_probe(struct of_device *dev, return -ENOMEM; } mutex_init(&shca->modify_mutex); - for (i = 0; i < ARRAY_SIZE(shca->sport); i++) - spin_lock_init(&shca->sport[i].mod_sqp_lock); shca->ofdev = dev; shca->ipz_hca_handle.handle = *handle; @@ -937,7 +934,7 @@ void ehca_poll_eqs(unsigned long data) ehca_process_eq(shca, 0); } } - mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ)); + mod_timer(&poll_eqs_timer, jiffies + HZ); spin_unlock(&shca_list_lock); } diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_qp.c b/trunk/drivers/infiniband/hw/ehca/ehca_qp.c index 1012f15a7140..eff5fb55604b 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_qp.c @@ -592,8 +592,10 @@ static struct ehca_qp *internal_create_qp( goto create_qp_exit1; } - /* Always signal by WQE so we can hide circ. WQEs */ - parms.sigtype = HCALL_SIGT_BY_WQE; + if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) + parms.sigtype = HCALL_SIGT_EVERY; + else + parms.sigtype = HCALL_SIGT_BY_WQE; /* UD_AV CIRCUMVENTION */ max_send_sge = init_attr->cap.max_send_sge; @@ -616,10 +618,6 @@ static struct ehca_qp *internal_create_qp( parms.squeue.max_sge = max_send_sge; parms.rqueue.max_sge = max_recv_sge; - /* RC QPs need one more SWQE for unsolicited ack circumvention */ - if (qp_type == IB_QPT_RC) - parms.squeue.max_wr++; - if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) { if (HAS_SQ(my_qp)) ehca_determine_small_queue( @@ -652,8 +650,6 @@ static struct ehca_qp *internal_create_qp( parms.squeue.act_nr_sges = 1; parms.rqueue.act_nr_sges = 1; } - /* hide the extra WQE */ - parms.squeue.act_nr_wqes--; break; case IB_QPT_UD: case IB_QPT_GSI: @@ -733,31 +729,12 @@ static struct ehca_qp *internal_create_qp( init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes; my_qp->init_attr = *init_attr; - if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) { - shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] = - &my_qp->ib_qp; - if (ehca_nr_ports < 0) { - /* alloc array to cache subsequent modify qp parms - * for autodetect mode - */ - my_qp->mod_qp_parm = - kzalloc(EHCA_MOD_QP_PARM_MAX * - sizeof(*my_qp->mod_qp_parm), - GFP_KERNEL); - if (!my_qp->mod_qp_parm) { - ehca_err(pd->device, - "Could not alloc mod_qp_parm"); - goto create_qp_exit4; - } - } - } - /* NOTE: define_apq0() not supported yet */ if (qp_type == IB_QPT_GSI) { h_ret = ehca_define_sqp(shca, my_qp, init_attr); if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); - goto create_qp_exit5; + goto create_qp_exit4; } } @@ -766,7 +743,7 @@ static struct ehca_qp *internal_create_qp( if (ret) { ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%i", ret); - goto create_qp_exit5; + goto create_qp_exit4; } } @@ -792,18 +769,12 @@ static struct ehca_qp *internal_create_qp( if (ib_copy_to_udata(udata, &resp, sizeof resp)) { ehca_err(pd->device, "Copy to udata failed"); ret = -EINVAL; - goto create_qp_exit6; + goto create_qp_exit4; } } return my_qp; -create_qp_exit6: - ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num); - -create_qp_exit5: - kfree(my_qp->mod_qp_parm); - create_qp_exit4: if (HAS_RQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); @@ -887,7 +858,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, update_mask, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { - ehca_err(pd->device, "Could not modify SRQ to INIT " + ehca_err(pd->device, "Could not modify SRQ to INIT" "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; @@ -901,7 +872,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, update_mask, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { - ehca_err(pd->device, "Could not enable SRQ " + ehca_err(pd->device, "Could not enable SRQ" "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; @@ -915,7 +886,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, update_mask, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { - ehca_err(pd->device, "Could not modify SRQ to RTR " + ehca_err(pd->device, "Could not modify SRQ to RTR" "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; @@ -1021,7 +992,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, unsigned long flags = 0; /* do query_qp to obtain current attr values */ - mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC); + mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL); if (!mqpcb) { ehca_err(ibqp->device, "Could not get zeroed page for mqpcb " "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num); @@ -1209,8 +1180,6 @@ static int internal_modify_qp(struct ib_qp *ibqp, update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1); } if (attr_mask & IB_QP_PORT) { - struct ehca_sport *sport; - struct ehca_qp *aqp1; if (attr->port_num < 1 || attr->port_num > shca->num_ports) { ret = -EINVAL; ehca_err(ibqp->device, "Invalid port=%x. " @@ -1219,29 +1188,6 @@ static int internal_modify_qp(struct ib_qp *ibqp, shca->num_ports); goto modify_qp_exit2; } - sport = &shca->sport[attr->port_num - 1]; - if (!sport->ibqp_sqp[IB_QPT_GSI]) { - /* should not occur */ - ret = -EFAULT; - ehca_err(ibqp->device, "AQP1 was not created for " - "port=%x", attr->port_num); - goto modify_qp_exit2; - } - aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI], - struct ehca_qp, ib_qp); - if (ibqp->qp_type != IB_QPT_GSI && - ibqp->qp_type != IB_QPT_SMI && - aqp1->mod_qp_parm) { - /* - * firmware will reject this modify_qp() because - * port is not activated/initialized fully - */ - ret = -EFAULT; - ehca_warn(ibqp->device, "Couldn't modify qp port=%x: " - "either port is being activated (try again) " - "or cabling issue", attr->port_num); - goto modify_qp_exit2; - } mqpcb->prim_phys_port = attr->port_num; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1); } @@ -1298,8 +1244,6 @@ static int internal_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_PATH_MTU) { - /* store ld(MTU) */ - my_qp->mtu_shift = attr->path_mtu + 7; mqpcb->path_mtu = attr->path_mtu; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1); } @@ -1523,8 +1467,6 @@ static int internal_modify_qp(struct ib_qp *ibqp, int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata) { - struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, - ib_device); struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, ib_pd); @@ -1537,100 +1479,9 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, return -EINVAL; } - /* The if-block below caches qp_attr to be modified for GSI and SMI - * qps during the initialization by ib_mad. When the respective port - * is activated, ie we got an event PORT_ACTIVE, we'll replay the - * cached modify calls sequence, see ehca_recover_sqs() below. - * Why that is required: - * 1) If one port is connected, older code requires that port one - * to be connected and module option nr_ports=1 to be given by - * user, which is very inconvenient for end user. - * 2) Firmware accepts modify_qp() only if respective port has become - * active. Older code had a wait loop of 30sec create_qp()/ - * define_aqp1(), which is not appropriate in practice. This - * code now removes that wait loop, see define_aqp1(), and always - * reports all ports to ib_mad resp. users. Only activated ports - * will then usable for the users. - */ - if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) { - int port = my_qp->init_attr.port_num; - struct ehca_sport *sport = &shca->sport[port - 1]; - unsigned long flags; - spin_lock_irqsave(&sport->mod_sqp_lock, flags); - /* cache qp_attr only during init */ - if (my_qp->mod_qp_parm) { - struct ehca_mod_qp_parm *p; - if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) { - ehca_err(&shca->ib_device, - "mod_qp_parm overflow state=%x port=%x" - " type=%x", attr->qp_state, - my_qp->init_attr.port_num, - ibqp->qp_type); - spin_unlock_irqrestore(&sport->mod_sqp_lock, - flags); - return -EINVAL; - } - p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx]; - p->mask = attr_mask; - p->attr = *attr; - my_qp->mod_qp_parm_idx++; - ehca_dbg(&shca->ib_device, - "Saved qp_attr for state=%x port=%x type=%x", - attr->qp_state, my_qp->init_attr.port_num, - ibqp->qp_type); - spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); - return 0; - } - spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); - } - return internal_modify_qp(ibqp, attr, attr_mask, 0); } -void ehca_recover_sqp(struct ib_qp *sqp) -{ - struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp); - int port = my_sqp->init_attr.port_num; - struct ib_qp_attr attr; - struct ehca_mod_qp_parm *qp_parm; - int i, qp_parm_idx, ret; - unsigned long flags, wr_cnt; - - if (!my_sqp->mod_qp_parm) - return; - ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num); - - qp_parm = my_sqp->mod_qp_parm; - qp_parm_idx = my_sqp->mod_qp_parm_idx; - for (i = 0; i < qp_parm_idx; i++) { - attr = qp_parm[i].attr; - ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0); - if (ret) { - ehca_err(sqp->device, "Could not modify SQP port=%x " - "qp_num=%x ret=%x", port, sqp->qp_num, ret); - goto free_qp_parm; - } - ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x", - port, sqp->qp_num, attr.qp_state); - } - - /* re-trigger posted recv wrs */ - wr_cnt = my_sqp->ipz_rqueue.current_q_offset / - my_sqp->ipz_rqueue.qe_size; - if (wr_cnt) { - spin_lock_irqsave(&my_sqp->spinlock_r, flags); - hipz_update_rqa(my_sqp, wr_cnt); - spin_unlock_irqrestore(&my_sqp->spinlock_r, flags); - ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx", - port, sqp->qp_num, wr_cnt); - } - -free_qp_parm: - kfree(qp_parm); - /* this prevents subsequent calls to modify_qp() to cache qp_attr */ - my_sqp->mod_qp_parm = NULL; -} - int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr) @@ -1918,7 +1769,6 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device); struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, ib_pd); - struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1]; u32 cur_pid = current->tgid; u32 qp_num = my_qp->real_qp_num; int ret; @@ -1965,14 +1815,6 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, port_num = my_qp->init_attr.port_num; qp_type = my_qp->init_attr.qp_type; - if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) { - spin_lock_irqsave(&sport->mod_sqp_lock, flags); - kfree(my_qp->mod_qp_parm); - my_qp->mod_qp_parm = NULL; - shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL; - spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); - } - /* no support for IB_QPT_SMI yet */ if (qp_type == IB_QPT_GSI) { struct ib_event event; diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c b/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c index 3aacc8cf1e44..ea91360835d3 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -50,9 +50,6 @@ #include "hcp_if.h" #include "hipz_fns.h" -/* in RC traffic, insert an empty RDMA READ every this many packets */ -#define ACK_CIRC_THRESHOLD 2000000 - static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, struct ehca_wqe *wqe_p, struct ib_recv_wr *recv_wr) @@ -84,7 +81,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, if (ehca_debug_level) { ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue); - ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe"); + ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe"); } return 0; @@ -138,8 +135,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) static inline int ehca_write_swqe(struct ehca_qp *qp, struct ehca_wqe *wqe_p, - const struct ib_send_wr *send_wr, - int hidden) + const struct ib_send_wr *send_wr) { u32 idx; u64 dma_length; @@ -180,9 +176,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, wqe_p->wr_flag = 0; - if ((send_wr->send_flags & IB_SEND_SIGNALED || - qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR) - && !hidden) + if (send_wr->send_flags & IB_SEND_SIGNALED) wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM; if (send_wr->opcode == IB_WR_SEND_WITH_IMM || @@ -205,7 +199,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8; wqe_p->local_ee_context_qkey = remote_qkey; - if (unlikely(!send_wr->wr.ud.ah)) { + if (!send_wr->wr.ud.ah) { ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp); return -EINVAL; } @@ -261,15 +255,6 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, } /* eof idx */ wqe_p->u.nud.atomic_1st_op_dma_len = dma_length; - /* unsolicited ack circumvention */ - if (send_wr->opcode == IB_WR_RDMA_READ) { - /* on RDMA read, switch on and reset counters */ - qp->message_count = qp->packet_count = 0; - qp->unsol_ack_circ = 1; - } else - /* else estimate #packets */ - qp->packet_count += (dma_length >> qp->mtu_shift) + 1; - break; default: @@ -370,49 +355,13 @@ static inline void map_ib_wc_status(u32 cqe_status, *wc_status = IB_WC_SUCCESS; } -static inline int post_one_send(struct ehca_qp *my_qp, - struct ib_send_wr *cur_send_wr, - struct ib_send_wr **bad_send_wr, - int hidden) -{ - struct ehca_wqe *wqe_p; - int ret; - u64 start_offset = my_qp->ipz_squeue.current_q_offset; - - /* get pointer next to free WQE */ - wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue); - if (unlikely(!wqe_p)) { - /* too many posted work requests: queue overflow */ - if (bad_send_wr) - *bad_send_wr = cur_send_wr; - ehca_err(my_qp->ib_qp.device, "Too many posted WQEs " - "qp_num=%x", my_qp->ib_qp.qp_num); - return -ENOMEM; - } - /* write a SEND WQE into the QUEUE */ - ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden); - /* - * if something failed, - * reset the free entry pointer to the start value - */ - if (unlikely(ret)) { - my_qp->ipz_squeue.current_q_offset = start_offset; - if (bad_send_wr) - *bad_send_wr = cur_send_wr; - ehca_err(my_qp->ib_qp.device, "Could not write WQE " - "qp_num=%x", my_qp->ib_qp.qp_num); - return -EINVAL; - } - - return 0; -} - int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr, struct ib_send_wr **bad_send_wr) { struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp); struct ib_send_wr *cur_send_wr; + struct ehca_wqe *wqe_p; int wqe_cnt = 0; int ret = 0; unsigned long flags; @@ -420,33 +369,37 @@ int ehca_post_send(struct ib_qp *qp, /* LOCK the QUEUE */ spin_lock_irqsave(&my_qp->spinlock_s, flags); - /* Send an empty extra RDMA read if: - * 1) there has been an RDMA read on this connection before - * 2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets - * 3) we can be sure that any previous extra RDMA read has been - * processed so we don't overflow the SQ - */ - if (unlikely(my_qp->unsol_ack_circ && - my_qp->packet_count > ACK_CIRC_THRESHOLD && - my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) { - /* insert an empty RDMA READ to fix up the remote QP state */ - struct ib_send_wr circ_wr; - memset(&circ_wr, 0, sizeof(circ_wr)); - circ_wr.opcode = IB_WR_RDMA_READ; - post_one_send(my_qp, &circ_wr, NULL, 1); /* ignore retcode */ - wqe_cnt++; - ehca_dbg(qp->device, "posted circ wr qp_num=%x", qp->qp_num); - my_qp->message_count = my_qp->packet_count = 0; - } - /* loop processes list of send reqs */ for (cur_send_wr = send_wr; cur_send_wr != NULL; cur_send_wr = cur_send_wr->next) { - ret = post_one_send(my_qp, cur_send_wr, bad_send_wr, 0); + u64 start_offset = my_qp->ipz_squeue.current_q_offset; + /* get pointer next to free WQE */ + wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue); + if (unlikely(!wqe_p)) { + /* too many posted work requests: queue overflow */ + if (bad_send_wr) + *bad_send_wr = cur_send_wr; + if (wqe_cnt == 0) { + ret = -ENOMEM; + ehca_err(qp->device, "Too many posted WQEs " + "qp_num=%x", qp->qp_num); + } + goto post_send_exit0; + } + /* write a SEND WQE into the QUEUE */ + ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr); + /* + * if something failed, + * reset the free entry pointer to the start value + */ if (unlikely(ret)) { - /* if one or more WQEs were successful, don't fail */ - if (wqe_cnt) - ret = 0; + my_qp->ipz_squeue.current_q_offset = start_offset; + *bad_send_wr = cur_send_wr; + if (wqe_cnt == 0) { + ret = -EINVAL; + ehca_err(qp->device, "Could not write WQE " + "qp_num=%x", qp->qp_num); + } goto post_send_exit0; } wqe_cnt++; @@ -457,7 +410,6 @@ int ehca_post_send(struct ib_qp *qp, post_send_exit0: iosync(); /* serialize GAL register access */ hipz_update_sqa(my_qp, wqe_cnt); - my_qp->message_count += wqe_cnt; spin_unlock_irqrestore(&my_qp->spinlock_s, flags); return ret; } diff --git a/trunk/drivers/infiniband/hw/ehca/ehca_sqp.c b/trunk/drivers/infiniband/hw/ehca/ehca_sqp.c index 79e72b25b252..f0792e5fbd02 100644 --- a/trunk/drivers/infiniband/hw/ehca/ehca_sqp.c +++ b/trunk/drivers/infiniband/hw/ehca/ehca_sqp.c @@ -40,8 +40,11 @@ */ +#include +#include #include "ehca_classes.h" #include "ehca_tools.h" +#include "ehca_qes.h" #include "ehca_iverbs.h" #include "hcp_if.h" @@ -90,9 +93,6 @@ u64 ehca_define_sqp(struct ehca_shca *shca, return H_PARAMETER; } - if (ehca_nr_ports < 0) /* autodetect mode */ - return H_SUCCESS; - for (counter = 0; shca->sport[port - 1].port_state != IB_PORT_ACTIVE && counter < ehca_port_act_time; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_common.h b/trunk/drivers/infiniband/hw/ipath/ipath_common.h index 414621095540..851df8a75e79 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_common.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_common.h @@ -81,16 +81,6 @@ #define IPATH_IB_LINK_LOOPBACK 6 /* enable local loopback */ #define IPATH_IB_LINK_EXTERNAL 7 /* normal, disable local loopback */ -/* - * These 3 values (SDR and DDR may be ORed for auto-speed - * negotiation) are used for the 3rd argument to path_f_set_ib_cfg - * with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs. They - * are also the the possible values for ipath_link_speed_enabled and active - * The values were chosen to match values used within the IB spec. - */ -#define IPATH_IB_SDR 1 -#define IPATH_IB_DDR 2 - /* * stats maintained by the driver. For now, at least, this is global * to all minor devices. @@ -443,9 +433,8 @@ struct ipath_user_info { #define IPATH_CMD_UNUSED_2 26 #define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */ #define IPATH_CMD_POLL_TYPE 28 /* set the kind of polling we want */ -#define IPATH_CMD_ARMLAUNCH_CTRL 29 /* armlaunch detection control */ -#define IPATH_CMD_MAX 29 +#define IPATH_CMD_MAX 28 /* * Poll types @@ -488,8 +477,6 @@ struct ipath_cmd { __u64 port_info; /* enable/disable receipt of packets */ __u32 recv_ctrl; - /* enable/disable armlaunch errors (non-zero to enable) */ - __u32 armlaunch_ctrl; /* partition key to set */ __u16 part_key; /* user address of __u32 bitmask of active slaves */ @@ -592,7 +579,7 @@ struct ipath_flash { struct infinipath_counters { __u64 LBIntCnt; __u64 LBFlowStallCnt; - __u64 TxSDmaDescCnt; /* was Reserved1 */ + __u64 Reserved1; __u64 TxUnsupVLErrCnt; __u64 TxDataPktCnt; __u64 TxFlowPktCnt; @@ -628,26 +615,12 @@ struct infinipath_counters { __u64 RxP6HdrEgrOvflCnt; __u64 RxP7HdrEgrOvflCnt; __u64 RxP8HdrEgrOvflCnt; - __u64 RxP9HdrEgrOvflCnt; /* was Reserved6 */ - __u64 RxP10HdrEgrOvflCnt; /* was Reserved7 */ - __u64 RxP11HdrEgrOvflCnt; /* new for IBA7220 */ - __u64 RxP12HdrEgrOvflCnt; /* new for IBA7220 */ - __u64 RxP13HdrEgrOvflCnt; /* new for IBA7220 */ - __u64 RxP14HdrEgrOvflCnt; /* new for IBA7220 */ - __u64 RxP15HdrEgrOvflCnt; /* new for IBA7220 */ - __u64 RxP16HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 Reserved6; + __u64 Reserved7; __u64 IBStatusChangeCnt; __u64 IBLinkErrRecoveryCnt; __u64 IBLinkDownedCnt; __u64 IBSymbolErrCnt; - /* The following are new for IBA7220 */ - __u64 RxVL15DroppedPktCnt; - __u64 RxOtherLocalPhyErrCnt; - __u64 PcieRetryBufDiagQwordCnt; - __u64 ExcessBufferOvflCnt; - __u64 LocalLinkIntegrityErrCnt; - __u64 RxVlErrCnt; - __u64 RxDlidFltrCnt; }; /* diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_cq.c b/trunk/drivers/infiniband/hw/ipath/ipath_cq.c index a03bd28d9b48..d1380c7a1703 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_cq.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_cq.c @@ -421,7 +421,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) else n = head - tail; if (unlikely((u32)cqe < n)) { - ret = -EINVAL; + ret = -EOVERFLOW; goto bail_unlock; } for (n = 0; tail != head; n++) { diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_debug.h b/trunk/drivers/infiniband/hw/ipath/ipath_debug.h index d6f69532d83f..19c56e6491eb 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_debug.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_debug.h @@ -55,7 +55,7 @@ #define __IPATH_PKTDBG 0x80 /* print packet data */ /* print process startup (init)/exit messages */ #define __IPATH_PROCDBG 0x100 -/* print mmap/fault stuff, not using VDBG any more */ +/* print mmap/nopage stuff, not using VDBG any more */ #define __IPATH_MMDBG 0x200 #define __IPATH_ERRPKTDBG 0x400 #define __IPATH_USER_SEND 0x1000 /* use user mode send */ @@ -81,7 +81,7 @@ #define __IPATH_VERBDBG 0x0 /* very verbose debug */ #define __IPATH_PKTDBG 0x0 /* print packet data */ #define __IPATH_PROCDBG 0x0 /* process startup (init)/exit messages */ -/* print mmap/fault stuff, not using VDBG any more */ +/* print mmap/nopage stuff, not using VDBG any more */ #define __IPATH_MMDBG 0x0 #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ #define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_driver.c b/trunk/drivers/infiniband/hw/ipath/ipath_driver.c index d5ff6ca2db30..fc355981bbab 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_driver.c @@ -334,8 +334,6 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd) udelay(1); } - ipath_disable_armlaunch(dd); - writeq(0, piobuf); /* length 0, no dwords actually sent */ ipath_flush_wc(); @@ -367,7 +365,6 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd) done: /* disarm piobuf, so it's available again */ ipath_disarm_piobufs(dd, pbnum, 1); - ipath_enable_armlaunch(dd); } static int __devinit ipath_init_one(struct pci_dev *pdev, @@ -806,37 +803,31 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first, unsigned cnt) { unsigned i, last = first + cnt; - unsigned long flags; + u64 sendctrl, sendorig; ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first); + sendorig = dd->ipath_sendctrl; for (i = first; i < last; i++) { - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); - /* - * The disarm-related bits are write-only, so it - * is ok to OR them in with our copy of sendctrl - * while we hold the lock. - */ + sendctrl = sendorig | INFINIPATH_S_DISARM | + (i << INFINIPATH_S_DISARMPIOBUF_SHIFT); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - dd->ipath_sendctrl | INFINIPATH_S_DISARM | - (i << INFINIPATH_S_DISARMPIOBUF_SHIFT)); - /* can't disarm bufs back-to-back per iba7220 spec */ - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); + sendctrl); } /* - * Disable PIOAVAILUPD, then re-enable, reading scratch in + * Write it again with current value, in case ipath_sendctrl changed + * while we were looping; no critical bits that would require + * locking. + * + * disable PIOAVAILUPD, then re-enable, reading scratch in * between. This seems to avoid a chip timing race that causes - * pioavail updates to memory to stop. We xor as we don't - * know the state of the bit when we're called. + * pioavail updates to memory to stop. */ - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD); + sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); } /** @@ -1012,10 +1003,12 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len) * ipath_get_egrbuf - get an eager buffer * @dd: the infinipath device * @bufnum: the eager buffer to get + * @err: unused * * must only be called if ipath_pd[port] is known to be allocated */ -static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum) +static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum, + int err) { return dd->ipath_port0_skbinfo ? (void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL; @@ -1107,14 +1100,13 @@ static void ipath_rcv_hdrerr(struct ipath_devdata *dd, /* * ipath_kreceive - receive a packet - * @pd: the infinipath port + * @dd: the infinipath device * * called from interrupt handler for errors or receive interrupt */ -void ipath_kreceive(struct ipath_portdata *pd) +void ipath_kreceive(struct ipath_devdata *dd) { u64 *rc; - struct ipath_devdata *dd = pd->port_dd; void *ebuf; const u32 rsize = dd->ipath_rcvhdrentsize; /* words */ const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */ @@ -1129,8 +1121,8 @@ void ipath_kreceive(struct ipath_portdata *pd) goto bail; } - l = pd->port_head; - hdrqtail = ipath_get_rcvhdrtail(pd); + l = dd->ipath_port0head; + hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr); if (l == hdrqtail) goto bail; @@ -1139,7 +1131,7 @@ void ipath_kreceive(struct ipath_portdata *pd) u32 qp; u8 *bthbytes; - rc = (u64 *) (pd->port_rcvhdrq + (l << 2)); + rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2)); hdr = (struct ipath_message_header *)&rc[1]; /* * could make a network order version of IPATH_KD_QP, and @@ -1164,7 +1156,7 @@ void ipath_kreceive(struct ipath_portdata *pd) etail = ipath_hdrget_index((__le32 *) rc); if (tlen > sizeof(*hdr) || etype == RCVHQ_RCV_TYPE_NON_KD) - ebuf = ipath_get_egrbuf(dd, etail); + ebuf = ipath_get_egrbuf(dd, etail, 0); } /* @@ -1199,7 +1191,7 @@ void ipath_kreceive(struct ipath_portdata *pd) be32_to_cpu(hdr->bth[0]) & 0xff); else { /* - * error packet, type of error unknown. + * error packet, type of error unknown. * Probably type 3, but we don't know, so don't * even try to print the opcode, etc. */ @@ -1249,7 +1241,7 @@ void ipath_kreceive(struct ipath_portdata *pd) * earlier packets, we "almost" guarantee we have covered * that case. */ - u32 hqtail = ipath_get_rcvhdrtail(pd); + u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr); if (hqtail != hdrqtail) { hdrqtail = hqtail; reloop = 1; /* loop 1 extra time at most */ @@ -1259,7 +1251,7 @@ void ipath_kreceive(struct ipath_portdata *pd) pkttot += i; - pd->port_head = l; + dd->ipath_port0head = l; if (pkttot > ipath_stats.sps_maxpkts_call) ipath_stats.sps_maxpkts_call = pkttot; @@ -1343,9 +1335,14 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd) /* * Chip Errata: bug 6641; even and odd qwords>3 are swapped */ - if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) - piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]); - else + if (i > 3) { + if (i & 1) + piov = le64_to_cpu( + dd->ipath_pioavailregs_dma[i - 1]); + else + piov = le64_to_cpu( + dd->ipath_pioavailregs_dma[i + 1]); + } else piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]); pchg = _IPATH_ALL_CHECKBITS & ~(dd->ipath_pioavailshadow[i] ^ piov); @@ -1604,8 +1601,7 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd, /* clear for security and sanity on each use */ memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size); - if (pd->port_rcvhdrtail_kvaddr) - memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE); + memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE); /* * tell chip each time we init it, even if we are re-using previous @@ -1621,6 +1617,77 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd, return ret; } +int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id, + u64 bits_to_wait_for, u64 * valp) +{ + unsigned long timeout; + u64 lastval, val; + int ret; + + lastval = ipath_read_kreg64(dd, reg_id); + /* wait a ridiculously long time */ + timeout = jiffies + msecs_to_jiffies(5); + do { + val = ipath_read_kreg64(dd, reg_id); + /* set so they have something, even on failures. */ + *valp = val; + if ((val & bits_to_wait_for) == bits_to_wait_for) { + ret = 0; + break; + } + if (val != lastval) + ipath_cdbg(VERBOSE, "Changed from %llx to %llx, " + "waiting for %llx bits\n", + (unsigned long long) lastval, + (unsigned long long) val, + (unsigned long long) bits_to_wait_for); + cond_resched(); + if (time_after(jiffies, timeout)) { + ipath_dbg("Didn't get bits %llx in register 0x%x, " + "got %llx\n", + (unsigned long long) bits_to_wait_for, + reg_id, (unsigned long long) *valp); + ret = -ENODEV; + break; + } + } while (1); + + return ret; +} + +/** + * ipath_waitfor_mdio_cmdready - wait for last command to complete + * @dd: the infinipath device + * + * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go + * away indicating the last command has completed. It doesn't return data + */ +int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd) +{ + unsigned long timeout; + u64 val; + int ret; + + /* wait a ridiculously long time */ + timeout = jiffies + msecs_to_jiffies(5); + do { + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio); + if (!(val & IPATH_MDIO_CMDVALID)) { + ret = 0; + break; + } + cond_resched(); + if (time_after(jiffies, timeout)) { + ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n", + (unsigned long long) val); + ret = -ENODEV; + break; + } + } while (1); + + return ret; +} + /* * Flush all sends that might be in the ready to send state, as well as any @@ -1989,8 +2056,6 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val) */ void ipath_shutdown_device(struct ipath_devdata *dd) { - unsigned long flags; - ipath_dbg("Shutting down the device\n"); dd->ipath_flags |= IPATH_LINKUNK; @@ -2011,13 +2076,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd) * gracefully stop all sends allowing any in progress to trickle out * first. */ - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); - dd->ipath_sendctrl = 0; - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL); /* flush it */ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); - /* * enough for anything that's going to trickle out to have actually * done so. @@ -2274,34 +2335,5 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv) } return 0; } - -/* - * Disable and enable the armlaunch error. Used for PIO bandwidth testing on - * the 7220, which is count-based, rather than trigger-based. Safe for the - * driver check, since it's at init. Not completely safe when used for - * user-mode checking, since some error checking can be lost, but not - * particularly risky, and only has problematic side-effects in the face of - * very buggy user code. There is no reference counting, but that's also - * fine, given the intended use. - */ -void ipath_enable_armlaunch(struct ipath_devdata *dd) -{ - dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH; - ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, - INFINIPATH_E_SPIOARMLAUNCH); - dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH; - ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, - dd->ipath_errormask); -} - -void ipath_disable_armlaunch(struct ipath_devdata *dd) -{ - /* so don't re-enable if already set */ - dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH; - dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH; - ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, - dd->ipath_errormask); -} - module_init(infinipath_init); module_exit(infinipath_cleanup); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c b/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c index e28a42f53769..e7c25dbbcdc9 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_eeprom.c @@ -510,10 +510,10 @@ int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset, { int ret; - ret = mutex_lock_interruptible(&dd->ipath_eep_lock); + ret = down_interruptible(&dd->ipath_eep_sem); if (!ret) { ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len); - mutex_unlock(&dd->ipath_eep_lock); + up(&dd->ipath_eep_sem); } return ret; @@ -524,10 +524,10 @@ int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset, { int ret; - ret = mutex_lock_interruptible(&dd->ipath_eep_lock); + ret = down_interruptible(&dd->ipath_eep_sem); if (!ret) { ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len); - mutex_unlock(&dd->ipath_eep_lock); + up(&dd->ipath_eep_sem); } return ret; @@ -574,7 +574,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) struct ipath_devdata *dd0 = ipath_lookup(0); if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) { - u8 oguid; + u8 *bguid, oguid; dd->ipath_guid = dd0->ipath_guid; bguid = (u8 *) & dd->ipath_guid; @@ -616,9 +616,9 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) goto bail; } - mutex_lock(&dd->ipath_eep_lock); + down(&dd->ipath_eep_sem); eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len); - mutex_unlock(&dd->ipath_eep_lock); + up(&dd->ipath_eep_sem); if (eep_stat) { ipath_dev_err(dd, "Failed reading GUID from eeprom\n"); @@ -674,6 +674,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) * elsewhere for backward-compatibility. */ char *snp = dd->ipath_serial; + int len; memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix); snp[sizeof ifp->if_sprefix] = '\0'; len = strlen(snp); @@ -763,14 +764,14 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) /* Grab semaphore and read current EEPROM. If we get an * error, let go, but if not, keep it until we finish write. */ - ret = mutex_lock_interruptible(&dd->ipath_eep_lock); + ret = down_interruptible(&dd->ipath_eep_sem); if (ret) { ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n"); goto free_bail; } ret = ipath_eeprom_internal_read(dd, 0, buf, len); if (ret) { - mutex_unlock(&dd->ipath_eep_lock); + up(&dd->ipath_eep_sem); ipath_dev_err(dd, "Unable read EEPROM for logging\n"); goto free_bail; } @@ -778,7 +779,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) csum = flash_csum(ifp, 0); if (csum != ifp->if_csum) { - mutex_unlock(&dd->ipath_eep_lock); + up(&dd->ipath_eep_sem); ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n", csum, ifp->if_csum); ret = 1; @@ -848,7 +849,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) csum = flash_csum(ifp, 1); ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1); } - mutex_unlock(&dd->ipath_eep_lock); + up(&dd->ipath_eep_sem); if (ret) ipath_dev_err(dd, "Failed updating EEPROM\n"); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c b/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c index 7e025c8e01b6..5de3243a47c3 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -169,7 +169,7 @@ static int ipath_get_base_info(struct file *fp, kinfo->spi_piocnt = dd->ipath_pbufsport; kinfo->spi_piobufbase = (u64) pd->port_piobufs; kinfo->__spi_uregbase = (u64) dd->ipath_uregbase + - dd->ipath_ureg_align * pd->port_port; + dd->ipath_palign * pd->port_port; } else if (master) { kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) + (dd->ipath_pbufsport % subport_cnt); @@ -186,7 +186,7 @@ static int ipath_get_base_info(struct file *fp, } if (shared) { kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase + - dd->ipath_ureg_align * pd->port_port; + dd->ipath_palign * pd->port_port; kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs; kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base; kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr; @@ -742,12 +742,11 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport, * updated and correct itself, even in the face of software * bugs. */ - if (pd->port_rcvhdrtail_kvaddr) - ipath_clear_rcvhdrtail(pd); - set_bit(dd->ipath_r_portenable_shift + pd->port_port, + *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0; + set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, &dd->ipath_rcvctrl); } else - clear_bit(dd->ipath_r_portenable_shift + pd->port_port, + clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, &dd->ipath_rcvctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); @@ -882,7 +881,7 @@ static int ipath_create_user_egr(struct ipath_portdata *pd) egrcnt = dd->ipath_rcvegrcnt; /* TID number offset for this port */ - egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt; + egroff = pd->port_port * egrcnt; egrsize = dd->ipath_rcvegrbufsize; ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid " "offset %x, egrsize %u\n", egrcnt, egroff, egrsize); @@ -1050,6 +1049,11 @@ static int mmap_piobufs(struct vm_area_struct *vma, phys = dd->ipath_physaddr + piobufs; + /* + * Don't mark this as non-cached, or we don't get the + * write combining behavior we want on the PIO buffers! + */ + #if defined(__powerpc__) /* There isn't a generic way to specify writethrough mappings */ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; @@ -1116,24 +1120,33 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma, } /* - * ipath_file_vma_fault - handle a VMA page fault. + * ipath_file_vma_nopage - handle a VMA page fault. */ -static int ipath_file_vma_fault(struct vm_area_struct *vma, - struct vm_fault *vmf) +static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) { - struct page *page; + unsigned long offset = address - vma->vm_start; + struct page *page = NOPAGE_SIGBUS; + void *pageptr; - page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT)); + /* + * Convert the vmalloc address into a struct page. + */ + pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT)); + page = vmalloc_to_page(pageptr); if (!page) - return VM_FAULT_SIGBUS; - get_page(page); - vmf->page = page; + goto out; - return 0; + /* Increment the reference count. */ + get_page(page); + if (type) + *type = VM_FAULT_MINOR; +out: + return page; } static struct vm_operations_struct ipath_file_vm_ops = { - .fault = ipath_file_vma_fault, + .nopage = ipath_file_vma_nopage, }; static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr, @@ -1271,7 +1284,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma) goto bail; } - ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port; + ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port; if (!pd->port_subport_cnt) { /* port is not shared */ piocnt = dd->ipath_pbufsport; @@ -1387,10 +1400,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd, pollflag = ipath_poll_hdrqfull(pd); head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); - if (pd->port_rcvhdrtail_kvaddr) - tail = ipath_get_rcvhdrtail(pd); - else - tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port); + tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr; if (head != tail) pollflag |= POLLIN | POLLRDNORM; @@ -1400,7 +1410,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd, /* flush waiting flag so we don't miss an event */ wmb(); - set_bit(pd->port_port + dd->ipath_r_intravail_shift, + set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, &dd->ipath_rcvctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, @@ -1780,7 +1790,6 @@ static int find_shared_port(struct file *fp, } port_fp(fp) = pd; subport_fp(fp) = pd->port_cnt++; - pd->port_subpid[subport_fp(fp)] = current->pid; tidcursor_fp(fp) = 0; pd->active_slaves |= 1 << subport_fp(fp); ipath_cdbg(PROC, @@ -1911,7 +1920,8 @@ static int ipath_do_user_init(struct file *fp, */ head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port); ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port); - pd->port_lastrcvhdrqtail = -1; + dd->ipath_lastegrheads[pd->port_port] = -1; + dd->ipath_lastrcvhdrqtails[pd->port_port] = -1; ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n", pd->port_port, head32); pd->port_tidcursor = 0; /* start at beginning after open */ @@ -1931,13 +1941,11 @@ static int ipath_do_user_init(struct file *fp, * We explictly set the in-memory copy to 0 beforehand, so we don't * have to wait to be sure the DMA update has happened. */ - if (pd->port_rcvhdrtail_kvaddr) - ipath_clear_rcvhdrtail(pd); - set_bit(dd->ipath_r_portenable_shift + pd->port_port, + *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL; + set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, &dd->ipath_rcvctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, - dd->ipath_rcvctrl & - ~(1ULL << dd->ipath_r_tailupd_shift)); + dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); /* Notify any waiting slaves */ @@ -2014,7 +2022,6 @@ static int ipath_close(struct inode *in, struct file *fp) * the slave(s) don't wait for receive data forever. */ pd->active_slaves &= ~(1 << fd->subport); - pd->port_subpid[fd->subport] = 0; mutex_unlock(&ipath_mutex); goto bail; } @@ -2047,9 +2054,9 @@ static int ipath_close(struct inode *in, struct file *fp) if (dd->ipath_kregbase) { int i; /* atomically clear receive enable port and intr avail. */ - clear_bit(dd->ipath_r_portenable_shift + port, + clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, &dd->ipath_rcvctrl); - clear_bit(pd->port_port + dd->ipath_r_intravail_shift, + clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, &dd->ipath_rcvctrl); ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); @@ -2142,15 +2149,11 @@ static int ipath_get_slave_info(struct ipath_portdata *pd, static int ipath_force_pio_avail_update(struct ipath_devdata *dd) { - unsigned long flags; + u64 reg = dd->ipath_sendctrl; - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + clear_bit(IPATH_S_PIOBUFAVAILUPD, ®); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); return 0; } @@ -2224,11 +2227,6 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, dest = &cmd.cmd.poll_type; src = &ucmd->cmd.poll_type; break; - case IPATH_CMD_ARMLAUNCH_CTRL: - copy = sizeof(cmd.cmd.armlaunch_ctrl); - dest = &cmd.cmd.armlaunch_ctrl; - src = &ucmd->cmd.armlaunch_ctrl; - break; default: ret = -EINVAL; goto bail; @@ -2304,12 +2302,6 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, case IPATH_CMD_POLL_TYPE: pd->poll_type = cmd.cmd.poll_type; break; - case IPATH_CMD_ARMLAUNCH_CTRL: - if (cmd.cmd.armlaunch_ctrl) - ipath_enable_armlaunch(pd->port_dd); - else - ipath_disable_armlaunch(pd->port_dd); - break; } if (ret >= 0) diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_fs.c b/trunk/drivers/infiniband/hw/ipath/ipath_fs.c index 23faba9d21eb..262c25db05cd 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_fs.c @@ -108,16 +108,21 @@ static const struct file_operations atomic_stats_ops = { .read = atomic_stats_read, }; +#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64) + static ssize_t atomic_counters_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct infinipath_counters counters; + u64 counters[NUM_COUNTERS]; + u16 i; struct ipath_devdata *dd; dd = file->f_path.dentry->d_inode->i_private; - dd->ipath_f_read_counters(dd, &counters); - return simple_read_from_buffer(buf, count, ppos, &counters, + for (i = 0; i < NUM_COUNTERS; i++) + counters[i] = ipath_snap_cntr(dd, i); + + return simple_read_from_buffer(buf, count, ppos, counters, sizeof counters); } @@ -238,7 +243,8 @@ static int create_device_files(struct super_block *sb, snprintf(unit, sizeof unit, "%02d", dd->ipath_unit); ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir, - &simple_dir_operations, dd); + (struct file_operations *) &simple_dir_operations, + dd); if (ret) { printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret); goto bail; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c b/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c index 9e2ced3cdc5e..ddbebe4bdb27 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -148,57 +148,10 @@ struct _infinipath_do_not_use_kernel_regs { unsigned long long ReservedSW2[4]; }; -struct _infinipath_do_not_use_counters { - __u64 LBIntCnt; - __u64 LBFlowStallCnt; - __u64 Reserved1; - __u64 TxUnsupVLErrCnt; - __u64 TxDataPktCnt; - __u64 TxFlowPktCnt; - __u64 TxDwordCnt; - __u64 TxLenErrCnt; - __u64 TxMaxMinLenErrCnt; - __u64 TxUnderrunCnt; - __u64 TxFlowStallCnt; - __u64 TxDroppedPktCnt; - __u64 RxDroppedPktCnt; - __u64 RxDataPktCnt; - __u64 RxFlowPktCnt; - __u64 RxDwordCnt; - __u64 RxLenErrCnt; - __u64 RxMaxMinLenErrCnt; - __u64 RxICRCErrCnt; - __u64 RxVCRCErrCnt; - __u64 RxFlowCtrlErrCnt; - __u64 RxBadFormatCnt; - __u64 RxLinkProblemCnt; - __u64 RxEBPCnt; - __u64 RxLPCRCErrCnt; - __u64 RxBufOvflCnt; - __u64 RxTIDFullErrCnt; - __u64 RxTIDValidErrCnt; - __u64 RxPKeyMismatchCnt; - __u64 RxP0HdrEgrOvflCnt; - __u64 RxP1HdrEgrOvflCnt; - __u64 RxP2HdrEgrOvflCnt; - __u64 RxP3HdrEgrOvflCnt; - __u64 RxP4HdrEgrOvflCnt; - __u64 RxP5HdrEgrOvflCnt; - __u64 RxP6HdrEgrOvflCnt; - __u64 RxP7HdrEgrOvflCnt; - __u64 RxP8HdrEgrOvflCnt; - __u64 Reserved6; - __u64 Reserved7; - __u64 IBStatusChangeCnt; - __u64 IBLinkErrRecoveryCnt; - __u64 IBLinkDownedCnt; - __u64 IBSymbolErrCnt; -}; - -#define IPATH_KREG_OFFSET(field) (offsetof( \ - struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) +#define IPATH_KREG_OFFSET(field) (offsetof(struct \ + _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) #define IPATH_CREG_OFFSET(field) (offsetof( \ - struct _infinipath_do_not_use_counters, field) / sizeof(u64)) + struct infinipath_counters, field) / sizeof(u64)) static const struct ipath_kregs ipath_ht_kregs = { .kr_control = IPATH_KREG_OFFSET(Control), @@ -329,9 +282,6 @@ static const struct ipath_cregs ipath_ht_cregs = { #define INFINIPATH_HWE_HTAPLL_RFSLIP 0x1000000000000000ULL #define INFINIPATH_HWE_SERDESPLLFAILED 0x2000000000000000ULL -#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf -#define IBA6110_IBCS_LINKSTATE_SHIFT 4 - /* kr_extstatus bits */ #define INFINIPATH_EXTS_FREQSEL 0x2 #define INFINIPATH_EXTS_SERDESSEL 0x4 @@ -346,12 +296,6 @@ static const struct ipath_cregs ipath_ht_cregs = { #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL #define INFINIPATH_RT_BUFSIZE_SHIFT 48 -#define INFINIPATH_R_INTRAVAIL_SHIFT 16 -#define INFINIPATH_R_TAILUPD_SHIFT 31 - -/* kr_xgxsconfig bits */ -#define INFINIPATH_XGXS_RESET 0x7ULL - /* * masks and bits that are different in different chips, or present only * in one @@ -708,6 +652,7 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, "with ID %u\n", boardrev); snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u", boardrev); + ret = 1; break; } if (n) @@ -741,13 +686,6 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, dd->ipath_htspeed); ret = 0; - /* - * set here, not in ipath_init_*_funcs because we have to do - * it after we can read chip registers. - */ - dd->ipath_ureg_align = - ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign); - bail: return ret; } @@ -1031,8 +969,7 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd, do { u8 cap_type; - /* - * The HT capability type byte is 3 bytes after the + /* the HT capability type byte is 3 bytes after the * capability byte. */ if (pci_read_config_byte(pdev, pos + 3, &cap_type)) { @@ -1045,8 +982,6 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd, } while ((pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_HT))); - dd->ipath_flags |= IPATH_SWAP_PIOBUFS; - bail: return ret; } @@ -1139,55 +1074,11 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd, static void ipath_init_ht_variables(struct ipath_devdata *dd) { - /* - * setup the register offsets, since they are different for each - * chip - */ - dd->ipath_kregs = &ipath_ht_kregs; - dd->ipath_cregs = &ipath_ht_cregs; - dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM; dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM; dd->ipath_gpio_sda = IPATH_GPIO_SDA; dd->ipath_gpio_scl = IPATH_GPIO_SCL; - /* - * Fill in data for field-values that change in newer chips. - * We dynamically specify only the mask for LINKTRAININGSTATE - * and only the shift for LINKSTATE, as they are the only ones - * that change. Also precalculate the 3 link states of interest - * and the combined mask. - */ - dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT; - dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK; - dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK << - dd->ibcs_ls_shift) | dd->ibcs_lts_mask; - dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP << - INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | - (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift); - dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP << - INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | - (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift); - dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP << - INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | - (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift); - - /* - * Fill in data for ibcc field-values that change in newer chips. - * We dynamically specify only the mask for LINKINITCMD - * and only the shift for LINKCMD and MAXPKTLEN, as they are - * the only ones that change. - */ - dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK; - dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT; - dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT; - - /* Fill in shifts for RcvCtrl. */ - dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT; - dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT; - dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT; - dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */ - dd->ipath_i_bitsextant = (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) | (INFINIPATH_I_RCVAVAIL_MASK << @@ -1244,8 +1135,6 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd) dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK; - dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT; - dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT; /* * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity. @@ -1259,17 +1148,9 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd) INFINIPATH_HWE_RXEMEMPARITYERR_MASK << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT; - dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET; + dd->ipath_eep_st_masks[2].errs_to_log = + INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET; - dd->delay_mult = 2; /* SDR, 4X, can't change */ - - dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X; - dd->ipath_link_speed_supported = IPATH_IB_SDR; - dd->ipath_link_width_enabled = IB_WIDTH_4X; - dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported; - /* these can't change for this chip, so set once */ - dd->ipath_link_width_active = dd->ipath_link_width_enabled; - dd->ipath_link_speed_active = dd->ipath_link_speed_enabled; } /** @@ -1324,16 +1205,14 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd) val &= ~INFINIPATH_HWE_HTCMISCERR4; /* - * PLL ignored because unused MDIO interface has a logic problem + * PLL ignored because MDIO interface has a logic problem + * for reads, on Comstock and Ponderosa. BRINGUP */ if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9) val &= ~INFINIPATH_HWE_SERDESPLLFAILED; dd->ipath_hwerrmask = val; } - - - /** * ipath_ht_bringup_serdes - bring up the serdes * @dd: the infinipath device @@ -1405,6 +1284,16 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd) } val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); + if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & + INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { + val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK << + INFINIPATH_XGXS_MDIOADDR_SHIFT); + /* + * we use address 3 + */ + val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; + change = 1; + } if (val & INFINIPATH_XGXS_RESET) { /* normally true after boot */ val &= ~INFINIPATH_XGXS_RESET; @@ -1440,6 +1329,21 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd) (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); + if (!ipath_waitfor_mdio_cmdready(dd)) { + ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio, + ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, + IPATH_MDIO_CTRL_XGXS_REG_8, + 0)); + if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, + IPATH_MDIO_DATAVALID, &val)) + ipath_dbg("Never got MDIO data for XGXS status " + "read\n"); + else + ipath_cdbg(VERBOSE, "MDIO Read reg8, " + "'bank' 31 %x\n", (u32) val); + } else + ipath_dbg("Never got MDIO cmdready for XGXS status read\n"); + return ret; /* for now, say we always succeeded */ } @@ -1492,7 +1396,6 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd, pa |= lenvalid | INFINIPATH_RT_VALID; } } - writeq(pa, tidptr); } @@ -1623,7 +1526,8 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) } ipath_get_eeprom_info(dd); - if (dd->ipath_boardrev == 5) { + if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' && + dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') { /* * Later production QHT7040 has same changes as QHT7140, so * can use GPIO interrupts. They have serial #'s starting @@ -1698,210 +1602,6 @@ static void ipath_ht_free_irq(struct ipath_devdata *dd) dd->ipath_intconfig = 0; } -static struct ipath_message_header * -ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr) -{ - return (struct ipath_message_header *) - &rhf_addr[sizeof(u64) / sizeof(u32)]; -} - -static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports) -{ - dd->ipath_portcnt = - ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); - dd->ipath_p0_rcvegrcnt = - ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt); -} - -static void ipath_ht_read_counters(struct ipath_devdata *dd, - struct infinipath_counters *cntrs) -{ - cntrs->LBIntCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt)); - cntrs->LBFlowStallCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt)); - cntrs->TxSDmaDescCnt = 0; - cntrs->TxUnsupVLErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt)); - cntrs->TxDataPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt)); - cntrs->TxFlowPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt)); - cntrs->TxDwordCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt)); - cntrs->TxLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt)); - cntrs->TxMaxMinLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt)); - cntrs->TxUnderrunCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt)); - cntrs->TxFlowStallCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt)); - cntrs->TxDroppedPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt)); - cntrs->RxDroppedPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt)); - cntrs->RxDataPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt)); - cntrs->RxFlowPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt)); - cntrs->RxDwordCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt)); - cntrs->RxLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt)); - cntrs->RxMaxMinLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt)); - cntrs->RxICRCErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt)); - cntrs->RxVCRCErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt)); - cntrs->RxFlowCtrlErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt)); - cntrs->RxBadFormatCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt)); - cntrs->RxLinkProblemCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt)); - cntrs->RxEBPCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt)); - cntrs->RxLPCRCErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt)); - cntrs->RxBufOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt)); - cntrs->RxTIDFullErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt)); - cntrs->RxTIDValidErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt)); - cntrs->RxPKeyMismatchCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt)); - cntrs->RxP0HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt)); - cntrs->RxP1HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt)); - cntrs->RxP2HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt)); - cntrs->RxP3HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt)); - cntrs->RxP4HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt)); - cntrs->RxP5HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt)); - cntrs->RxP6HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt)); - cntrs->RxP7HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt)); - cntrs->RxP8HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt)); - cntrs->RxP9HdrEgrOvflCnt = 0; - cntrs->RxP10HdrEgrOvflCnt = 0; - cntrs->RxP11HdrEgrOvflCnt = 0; - cntrs->RxP12HdrEgrOvflCnt = 0; - cntrs->RxP13HdrEgrOvflCnt = 0; - cntrs->RxP14HdrEgrOvflCnt = 0; - cntrs->RxP15HdrEgrOvflCnt = 0; - cntrs->RxP16HdrEgrOvflCnt = 0; - cntrs->IBStatusChangeCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt)); - cntrs->IBLinkErrRecoveryCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt)); - cntrs->IBLinkDownedCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt)); - cntrs->IBSymbolErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt)); - cntrs->RxVL15DroppedPktCnt = 0; - cntrs->RxOtherLocalPhyErrCnt = 0; - cntrs->PcieRetryBufDiagQwordCnt = 0; - cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs; - cntrs->LocalLinkIntegrityErrCnt = - (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ? - dd->ipath_lli_errs : dd->ipath_lli_errors; - cntrs->RxVlErrCnt = 0; - cntrs->RxDlidFltrCnt = 0; -} - - -/* no interrupt fallback for these chips */ -static int ipath_ht_nointr_fallback(struct ipath_devdata *dd) -{ - return 0; -} - - -/* - * reset the XGXS (between serdes and IBC). Slightly less intrusive - * than resetting the IBC or external link state, and useful in some - * cases to cause some retraining. To do this right, we reset IBC - * as well. - */ -static void ipath_ht_xgxs_reset(struct ipath_devdata *dd) -{ - u64 val, prev_val; - - prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); - val = prev_val | INFINIPATH_XGXS_RESET; - prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */ - ipath_write_kreg(dd, dd->ipath_kregs->kr_control, - dd->ipath_control & ~INFINIPATH_C_LINKENABLE); - ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); - ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch); - ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val); - ipath_write_kreg(dd, dd->ipath_kregs->kr_control, - dd->ipath_control); -} - - -static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which) -{ - int ret; - - switch (which) { - case IPATH_IB_CFG_LWID: - ret = dd->ipath_link_width_active; - break; - case IPATH_IB_CFG_SPD: - ret = dd->ipath_link_speed_active; - break; - case IPATH_IB_CFG_LWID_ENB: - ret = dd->ipath_link_width_enabled; - break; - case IPATH_IB_CFG_SPD_ENB: - ret = dd->ipath_link_speed_enabled; - break; - default: - ret = -ENOTSUPP; - break; - } - return ret; -} - - -/* we assume range checking is already done, if needed */ -static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val) -{ - int ret = 0; - - if (which == IPATH_IB_CFG_LWID_ENB) - dd->ipath_link_width_enabled = val; - else if (which == IPATH_IB_CFG_SPD_ENB) - dd->ipath_link_speed_enabled = val; - else - ret = -ENOTSUPP; - return ret; -} - - -static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b) -{ -} - - -static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) -{ - ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs), - ipath_ib_linktrstate(dd, ibcs)); - return 0; -} - - /** * ipath_init_iba6110_funcs - set up the chip-specific function pointers * @dd: the infinipath device @@ -1926,19 +1626,22 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd) dd->ipath_f_setextled = ipath_setup_ht_setextled; dd->ipath_f_get_base_info = ipath_ht_get_base_info; dd->ipath_f_free_irq = ipath_ht_free_irq; - dd->ipath_f_tidtemplate = ipath_ht_tidtemplate; - dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback; - dd->ipath_f_get_msgheader = ipath_ht_get_msgheader; - dd->ipath_f_config_ports = ipath_ht_config_ports; - dd->ipath_f_read_counters = ipath_ht_read_counters; - dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset; - dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg; - dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg; - dd->ipath_f_config_jint = ipath_ht_config_jint; - dd->ipath_f_ib_updown = ipath_ht_ib_updown; /* * initialize chip-specific variables */ + dd->ipath_f_tidtemplate = ipath_ht_tidtemplate; + + /* + * setup the register offsets, since they are different for each + * chip + */ + dd->ipath_kregs = &ipath_ht_kregs; + dd->ipath_cregs = &ipath_ht_cregs; + + /* + * do very early init that is needed before ipath_f_bus is + * called + */ ipath_init_ht_variables(dd); } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c b/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c index c7a2f50824c0..0103d6f4847b 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -145,57 +145,10 @@ struct _infinipath_do_not_use_kernel_regs { unsigned long long Reserved12; }; -struct _infinipath_do_not_use_counters { - __u64 LBIntCnt; - __u64 LBFlowStallCnt; - __u64 Reserved1; - __u64 TxUnsupVLErrCnt; - __u64 TxDataPktCnt; - __u64 TxFlowPktCnt; - __u64 TxDwordCnt; - __u64 TxLenErrCnt; - __u64 TxMaxMinLenErrCnt; - __u64 TxUnderrunCnt; - __u64 TxFlowStallCnt; - __u64 TxDroppedPktCnt; - __u64 RxDroppedPktCnt; - __u64 RxDataPktCnt; - __u64 RxFlowPktCnt; - __u64 RxDwordCnt; - __u64 RxLenErrCnt; - __u64 RxMaxMinLenErrCnt; - __u64 RxICRCErrCnt; - __u64 RxVCRCErrCnt; - __u64 RxFlowCtrlErrCnt; - __u64 RxBadFormatCnt; - __u64 RxLinkProblemCnt; - __u64 RxEBPCnt; - __u64 RxLPCRCErrCnt; - __u64 RxBufOvflCnt; - __u64 RxTIDFullErrCnt; - __u64 RxTIDValidErrCnt; - __u64 RxPKeyMismatchCnt; - __u64 RxP0HdrEgrOvflCnt; - __u64 RxP1HdrEgrOvflCnt; - __u64 RxP2HdrEgrOvflCnt; - __u64 RxP3HdrEgrOvflCnt; - __u64 RxP4HdrEgrOvflCnt; - __u64 RxP5HdrEgrOvflCnt; - __u64 RxP6HdrEgrOvflCnt; - __u64 RxP7HdrEgrOvflCnt; - __u64 RxP8HdrEgrOvflCnt; - __u64 Reserved6; - __u64 Reserved7; - __u64 IBStatusChangeCnt; - __u64 IBLinkErrRecoveryCnt; - __u64 IBLinkDownedCnt; - __u64 IBSymbolErrCnt; -}; - -#define IPATH_KREG_OFFSET(field) (offsetof( \ - struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) +#define IPATH_KREG_OFFSET(field) (offsetof(struct \ + _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) #define IPATH_CREG_OFFSET(field) (offsetof( \ - struct _infinipath_do_not_use_counters, field) / sizeof(u64)) + struct infinipath_counters, field) / sizeof(u64)) static const struct ipath_kregs ipath_pe_kregs = { .kr_control = IPATH_KREG_OFFSET(Control), @@ -329,9 +282,6 @@ static const struct ipath_cregs ipath_pe_cregs = { #define INFINIPATH_HWE_PCIE0PLLFAILED 0x0800000000000000ULL #define INFINIPATH_HWE_SERDESPLLFAILED 0x1000000000000000ULL -#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf -#define IBA6120_IBCS_LINKSTATE_SHIFT 4 - /* kr_extstatus bits */ #define INFINIPATH_EXTS_FREQSEL 0x2 #define INFINIPATH_EXTS_SERDESSEL 0x4 @@ -346,9 +296,6 @@ static const struct ipath_cregs ipath_pe_cregs = { #define IPATH_GPIO_SCL (1ULL << \ (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) -#define INFINIPATH_R_INTRAVAIL_SHIFT 16 -#define INFINIPATH_R_TAILUPD_SHIFT 31 - /* 6120 specific hardware errors... */ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = { INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"), @@ -373,28 +320,10 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = { INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) +static int ipath_pe_txe_recover(struct ipath_devdata *); static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *, u32, unsigned long); -/* - * On platforms using this chip, and not having ordered WC stores, we - * can get TXE parity errors due to speculative reads to the PIO buffers, - * and this, due to a chip bug can result in (many) false parity error - * reports. So it's a debug print on those, and an info print on systems - * where the speculative reads don't occur. - */ -static void ipath_pe_txe_recover(struct ipath_devdata *dd) -{ - if (ipath_unordered_wc()) - ipath_dbg("Recovering from TXE PIO parity error\n"); - else { - ++ipath_stats.sps_txeparity; - dev_info(&dd->pcidev->dev, - "Recovering from TXE PIO parity error\n"); - } -} - - /** * ipath_pe_handle_hwerrors - display hardware errors. * @dd: the infinipath device @@ -474,11 +403,35 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, * occur if a processor speculative read is done to the PIO * buffer while we are sending a packet, for example. */ - if (hwerrs & TXE_PIO_PARITY) { - ipath_pe_txe_recover(dd); + if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd)) hwerrs &= ~TXE_PIO_PARITY; - } - if (!hwerrs) { + if (hwerrs) { + /* + * if any set that we aren't ignoring only make the + * complaint once, in case it's stuck or recurring, + * and we get here multiple times + * Force link down, so switch knows, and + * LEDs are turned off + */ + if (dd->ipath_flags & IPATH_INITTED) { + ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); + ipath_setup_pe_setextled(dd, + INFINIPATH_IBCS_L_STATE_DOWN, + INFINIPATH_IBCS_LT_STATE_DISABLED); + ipath_dev_err(dd, "Fatal Hardware Error (freeze " + "mode), no longer usable, SN %.16s\n", + dd->ipath_serial); + isfatal = 1; + } + /* + * Mark as having had an error for driver, and also + * for /sys and status word mapped to user programs. + * This marks unit as not usable, until reset + */ + *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; + *dd->ipath_statusp |= IPATH_STATUS_HWERROR; + dd->ipath_flags &= ~IPATH_INITTED; + } else { static u32 freeze_cnt; freeze_cnt++; @@ -532,7 +485,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) { /* - * If it occurs, it is left masked since the external + * If it occurs, it is left masked since the eternal * interface is unused */ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED; @@ -610,14 +563,6 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name, dd->ipath_f_put_tid = ipath_pe_put_tid_2; } - - /* - * set here, not in ipath_init_*_funcs because we have to do - * it after we can read chip registers. - */ - dd->ipath_ureg_align = - ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign); - return ret; } @@ -722,8 +667,17 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); prev_val = val; - if (val & INFINIPATH_XGXS_RESET) + if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & + INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { + val &= + ~(INFINIPATH_XGXS_MDIOADDR_MASK << + INFINIPATH_XGXS_MDIOADDR_SHIFT); + /* MDIO address 3 */ + val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; + } + if (val & INFINIPATH_XGXS_RESET) { val &= ~INFINIPATH_XGXS_RESET; + } if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { /* need to compensate for Tx inversion in partner */ @@ -753,6 +707,21 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); + if (!ipath_waitfor_mdio_cmdready(dd)) { + ipath_write_kreg( + dd, dd->ipath_kregs->kr_mdio, + ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, + IPATH_MDIO_CTRL_XGXS_REG_8, 0)); + if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, + IPATH_MDIO_DATAVALID, &val)) + ipath_dbg("Never got MDIO data for XGXS " + "status read\n"); + else + ipath_cdbg(VERBOSE, "MDIO Read reg8, " + "'bank' 31 %x\n", (u32) val); + } else + ipath_dbg("Never got MDIO cmdready for XGXS status read\n"); + return ret; } @@ -933,26 +902,11 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd, else ipath_dev_err(dd, "Can't find PCI Express " "capability!\n"); - - dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X; - dd->ipath_link_speed_supported = IPATH_IB_SDR; - dd->ipath_link_width_enabled = IB_WIDTH_4X; - dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported; - /* these can't change for this chip, so set once */ - dd->ipath_link_width_active = dd->ipath_link_width_enabled; - dd->ipath_link_speed_active = dd->ipath_link_speed_enabled; return 0; } static void ipath_init_pe_variables(struct ipath_devdata *dd) { - /* - * setup the register offsets, since they are different for each - * chip - */ - dd->ipath_kregs = &ipath_pe_kregs; - dd->ipath_cregs = &ipath_pe_cregs; - /* * bits for selecting i2c direction and values, * used for I2C serial flash @@ -962,43 +916,6 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd) dd->ipath_gpio_sda = IPATH_GPIO_SDA; dd->ipath_gpio_scl = IPATH_GPIO_SCL; - /* - * Fill in data for field-values that change in newer chips. - * We dynamically specify only the mask for LINKTRAININGSTATE - * and only the shift for LINKSTATE, as they are the only ones - * that change. Also precalculate the 3 link states of interest - * and the combined mask. - */ - dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT; - dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK; - dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK << - dd->ibcs_ls_shift) | dd->ibcs_lts_mask; - dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP << - INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | - (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift); - dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP << - INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | - (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift); - dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP << - INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | - (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift); - - /* - * Fill in data for ibcc field-values that change in newer chips. - * We dynamically specify only the mask for LINKINITCMD - * and only the shift for LINKCMD and MAXPKTLEN, as they are - * the only ones that change. - */ - dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK; - dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT; - dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT; - - /* Fill in shifts for RcvCtrl. */ - dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT; - dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT; - dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT; - dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */ - /* variables for sanity checking interrupt and errors */ dd->ipath_hwe_bitsextant = (INFINIPATH_HWE_RXEMEMPARITYERR_MASK << @@ -1046,8 +963,6 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd) dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK; - dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT; - dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT; /* * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity. @@ -1069,7 +984,6 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd) INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET; - dd->delay_mult = 2; /* SDR, 4X, can't change */ } /* setup the MSI stuff again after a reset. I'd like to just call @@ -1375,9 +1289,6 @@ static int ipath_pe_early_init(struct ipath_devdata *dd) */ dd->ipath_rcvhdrentsize = 24; dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; - dd->ipath_rhf_offset = 0; - dd->ipath_egrtidbase = (u64 __iomem *) - ((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase); /* * To truly support a 4KB MTU (for usermode), we need to @@ -1448,204 +1359,34 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd) dd->ipath_irq = 0; } - -static struct ipath_message_header * -ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr) -{ - return (struct ipath_message_header *) - &rhf_addr[sizeof(u64) / sizeof(u32)]; -} - -static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports) -{ - dd->ipath_portcnt = - ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); - dd->ipath_p0_rcvegrcnt = - ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt); -} - -static void ipath_pe_read_counters(struct ipath_devdata *dd, - struct infinipath_counters *cntrs) -{ - cntrs->LBIntCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt)); - cntrs->LBFlowStallCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt)); - cntrs->TxSDmaDescCnt = 0; - cntrs->TxUnsupVLErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt)); - cntrs->TxDataPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt)); - cntrs->TxFlowPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt)); - cntrs->TxDwordCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt)); - cntrs->TxLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt)); - cntrs->TxMaxMinLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt)); - cntrs->TxUnderrunCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt)); - cntrs->TxFlowStallCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt)); - cntrs->TxDroppedPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt)); - cntrs->RxDroppedPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt)); - cntrs->RxDataPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt)); - cntrs->RxFlowPktCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt)); - cntrs->RxDwordCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt)); - cntrs->RxLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt)); - cntrs->RxMaxMinLenErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt)); - cntrs->RxICRCErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt)); - cntrs->RxVCRCErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt)); - cntrs->RxFlowCtrlErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt)); - cntrs->RxBadFormatCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt)); - cntrs->RxLinkProblemCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt)); - cntrs->RxEBPCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt)); - cntrs->RxLPCRCErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt)); - cntrs->RxBufOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt)); - cntrs->RxTIDFullErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt)); - cntrs->RxTIDValidErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt)); - cntrs->RxPKeyMismatchCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt)); - cntrs->RxP0HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt)); - cntrs->RxP1HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt)); - cntrs->RxP2HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt)); - cntrs->RxP3HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt)); - cntrs->RxP4HdrEgrOvflCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt)); - cntrs->RxP5HdrEgrOvflCnt = 0; - cntrs->RxP6HdrEgrOvflCnt = 0; - cntrs->RxP7HdrEgrOvflCnt = 0; - cntrs->RxP8HdrEgrOvflCnt = 0; - cntrs->RxP9HdrEgrOvflCnt = 0; - cntrs->RxP10HdrEgrOvflCnt = 0; - cntrs->RxP11HdrEgrOvflCnt = 0; - cntrs->RxP12HdrEgrOvflCnt = 0; - cntrs->RxP13HdrEgrOvflCnt = 0; - cntrs->RxP14HdrEgrOvflCnt = 0; - cntrs->RxP15HdrEgrOvflCnt = 0; - cntrs->RxP16HdrEgrOvflCnt = 0; - cntrs->IBStatusChangeCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt)); - cntrs->IBLinkErrRecoveryCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt)); - cntrs->IBLinkDownedCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt)); - cntrs->IBSymbolErrCnt = - ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt)); - cntrs->RxVL15DroppedPktCnt = 0; - cntrs->RxOtherLocalPhyErrCnt = 0; - cntrs->PcieRetryBufDiagQwordCnt = 0; - cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs; - cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs; - cntrs->RxVlErrCnt = 0; - cntrs->RxDlidFltrCnt = 0; -} - - -/* no interrupt fallback for these chips */ -static int ipath_pe_nointr_fallback(struct ipath_devdata *dd) -{ - return 0; -} - - /* - * reset the XGXS (between serdes and IBC). Slightly less intrusive - * than resetting the IBC or external link state, and useful in some - * cases to cause some retraining. To do this right, we reset IBC - * as well. + * On platforms using this chip, and not having ordered WC stores, we + * can get TXE parity errors due to speculative reads to the PIO buffers, + * and this, due to a chip bug can result in (many) false parity error + * reports. So it's a debug print on those, and an info print on systems + * where the speculative reads don't occur. + * Because we can get lots of false errors, we have no upper limit + * on recovery attempts on those platforms. */ -static void ipath_pe_xgxs_reset(struct ipath_devdata *dd) -{ - u64 val, prev_val; - - prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); - val = prev_val | INFINIPATH_XGXS_RESET; - prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */ - ipath_write_kreg(dd, dd->ipath_kregs->kr_control, - dd->ipath_control & ~INFINIPATH_C_LINKENABLE); - ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); - ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch); - ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val); - ipath_write_kreg(dd, dd->ipath_kregs->kr_control, - dd->ipath_control); -} - - -static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which) +static int ipath_pe_txe_recover(struct ipath_devdata *dd) { - int ret; - - switch (which) { - case IPATH_IB_CFG_LWID: - ret = dd->ipath_link_width_active; - break; - case IPATH_IB_CFG_SPD: - ret = dd->ipath_link_speed_active; - break; - case IPATH_IB_CFG_LWID_ENB: - ret = dd->ipath_link_width_enabled; - break; - case IPATH_IB_CFG_SPD_ENB: - ret = dd->ipath_link_speed_enabled; - break; - default: - ret = -ENOTSUPP; - break; + if (ipath_unordered_wc()) + ipath_dbg("Recovering from TXE PIO parity error\n"); + else { + int cnt = ++ipath_stats.sps_txeparity; + if (cnt >= IPATH_MAX_PARITY_ATTEMPTS) { + if (cnt == IPATH_MAX_PARITY_ATTEMPTS) + ipath_dev_err(dd, + "Too many attempts to recover from " + "TXE parity, giving up\n"); + return 0; + } + dev_info(&dd->pcidev->dev, + "Recovering from TXE PIO parity error\n"); } - return ret; -} - - -/* we assume range checking is already done, if needed */ -static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val) -{ - int ret = 0; - - if (which == IPATH_IB_CFG_LWID_ENB) - dd->ipath_link_width_enabled = val; - else if (which == IPATH_IB_CFG_SPD_ENB) - dd->ipath_link_speed_enabled = val; - else - ret = -ENOTSUPP; - return ret; + return 1; } -static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b) -{ -} - - -static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) -{ - ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs), - ipath_ib_linktrstate(dd, ibcs)); - return 0; -} - - /** * ipath_init_iba6120_funcs - set up the chip-specific function pointers * @dd: the infinipath device @@ -1666,7 +1407,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd) dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes; dd->ipath_f_clear_tids = ipath_pe_clear_tids; /* - * _f_put_tid may get changed after we read the chip revision, + * this may get changed after we read the chip revision, * but we start with the safe version for all revs */ dd->ipath_f_put_tid = ipath_pe_put_tid; @@ -1674,19 +1415,17 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd) dd->ipath_f_setextled = ipath_setup_pe_setextled; dd->ipath_f_get_base_info = ipath_pe_get_base_info; dd->ipath_f_free_irq = ipath_pe_free_irq; + + /* initialize chip-specific variables */ dd->ipath_f_tidtemplate = ipath_pe_tidtemplate; - dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback; - dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset; - dd->ipath_f_get_msgheader = ipath_pe_get_msgheader; - dd->ipath_f_config_ports = ipath_pe_config_ports; - dd->ipath_f_read_counters = ipath_pe_read_counters; - dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg; - dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg; - dd->ipath_f_config_jint = ipath_pe_config_jint; - dd->ipath_f_ib_updown = ipath_pe_ib_updown; + /* + * setup the register offsets, since they are different for each + * chip + */ + dd->ipath_kregs = &ipath_pe_kregs; + dd->ipath_cregs = &ipath_pe_cregs; - /* initialize chip-specific variables */ ipath_init_pe_variables(dd); } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c b/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c index 4471674975cd..9dd0bacf8461 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -91,7 +91,7 @@ static int create_port0_egr(struct ipath_devdata *dd) struct ipath_skbinfo *skbinfo; int ret; - egrcnt = dd->ipath_p0_rcvegrcnt; + egrcnt = dd->ipath_rcvegrcnt; skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt); if (skbinfo == NULL) { @@ -244,7 +244,8 @@ static int init_chip_first(struct ipath_devdata *dd, * cfgports. We do still check and report a difference, if * not same (should be impossible). */ - dd->ipath_f_config_ports(dd, ipath_cfgports); + dd->ipath_portcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); if (!ipath_cfgports) dd->ipath_cfgports = dd->ipath_portcnt; else if (ipath_cfgports <= dd->ipath_portcnt) { @@ -271,7 +272,22 @@ static int init_chip_first(struct ipath_devdata *dd, goto done; } + dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads) + * dd->ipath_cfgports, + GFP_KERNEL); + dd->ipath_lastrcvhdrqtails = + kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails) + * dd->ipath_cfgports, GFP_KERNEL); + + if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) { + ipath_dev_err(dd, "Unable to allocate head arrays, " + "failing\n"); + ret = -ENOMEM; + goto done; + } + pd = create_portdata0(dd); + if (!pd) { ipath_dev_err(dd, "Unable to allocate portdata for port " "0, failing\n"); @@ -329,10 +345,10 @@ static int init_chip_first(struct ipath_devdata *dd, dd->ipath_piobcnt2k, dd->ipath_pio2kbase); spin_lock_init(&dd->ipath_tid_lock); - spin_lock_init(&dd->ipath_sendctrl_lock); + spin_lock_init(&dd->ipath_gpio_lock); spin_lock_init(&dd->ipath_eep_st_lock); - mutex_init(&dd->ipath_eep_lock); + sema_init(&dd->ipath_eep_sem, 1); done: *pdp = pd; @@ -356,9 +372,9 @@ static int init_chip_reset(struct ipath_devdata *dd, *pdp = dd->ipath_pd[0]; /* ensure chip does no sends or receives while we re-initialize */ dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U; - ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0); + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0); rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); if (dd->ipath_portcnt != rtmp) @@ -471,7 +487,6 @@ static void enable_chip(struct ipath_devdata *dd, struct ipath_portdata *pd, int reinit) { u32 val; - unsigned long flags; int i; if (!reinit) @@ -480,21 +495,19 @@ static void enable_chip(struct ipath_devdata *dd, ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); /* Enable PIO send, and update of PIOavail regs to memory. */ dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE | INFINIPATH_S_PIOBUFAVAILUPD; - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl); /* * enable port 0 receive, and receive interrupt. other ports * done as user opens and inits them. */ - dd->ipath_rcvctrl = (1ULL << dd->ipath_r_tailupd_shift) | - (1ULL << dd->ipath_r_portenable_shift) | - (1ULL << dd->ipath_r_intravail_shift); + dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD | + (1ULL << INFINIPATH_R_PORTENABLE_SHIFT) | + (1ULL << INFINIPATH_R_INTRAVAIL_SHIFT); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); @@ -510,11 +523,12 @@ static void enable_chip(struct ipath_devdata *dd, */ val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0); (void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0); + dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0); /* Initialize so we interrupt on next packet received */ (void)ipath_write_ureg(dd, ur_rcvhdrhead, dd->ipath_rhdrhead_intr_off | - dd->ipath_pd[0]->port_head, 0); + dd->ipath_port0head, 0); /* * by now pioavail updates to memory should have occurred, so @@ -528,8 +542,12 @@ static void enable_chip(struct ipath_devdata *dd, /* * Chip Errata bug 6641; even and odd qwords>3 are swapped. */ - if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) - val = dd->ipath_pioavailregs_dma[i ^ 1]; + if (i > 3) { + if (i & 1) + val = dd->ipath_pioavailregs_dma[i - 1]; + else + val = dd->ipath_pioavailregs_dma[i + 1]; + } else val = dd->ipath_pioavailregs_dma[i]; dd->ipath_pioavailshadow[i] = le64_to_cpu(val); @@ -672,13 +690,12 @@ static int init_housekeeping(struct ipath_devdata *dd, */ int ipath_init_chip(struct ipath_devdata *dd, int reinit) { - int ret = 0; + int ret = 0, i; u32 val32, kpiobufs; u32 piobufs, uports; u64 val; struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ gfp_t gfp_flags = GFP_USER | __GFP_COMP; - unsigned long flags; ret = init_housekeeping(dd, &pd, reinit); if (ret) @@ -729,7 +746,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) kpiobufs = ipath_kpiobufs; if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) { - int i = (int) piobufs - + i = (int) piobufs - (int) (uports * IPATH_MIN_USER_PORT_BUFCNT); if (i < 0) i = 0; @@ -810,12 +827,8 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED); ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL); - - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); - dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE; - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + INFINIPATH_S_PIOENABLE); /* * before error clears, since we expect serdes pll errors during diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_intr.c b/trunk/drivers/infiniband/hw/ipath/ipath_intr.c index 92e58c921522..c61f9da2964a 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_intr.c @@ -683,7 +683,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) for (i = 0; i < dd->ipath_cfgports; i++) { struct ipath_portdata *pd = dd->ipath_pd[i]; if (i == 0) { - hd = pd->port_head; + hd = dd->ipath_port0head; tl = (u32) le64_to_cpu( *dd->ipath_hdrqtailptr); } else if (pd && pd->port_cnt && @@ -693,7 +693,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) * except kernel */ tl = *(u64 *) pd->port_rcvhdrtail_kvaddr; - if (tl == pd->port_lastrcvhdrqtail) + if (tl == dd->ipath_lastrcvhdrqtails[i]) continue; hd = ipath_read_ureg32(dd, ur_rcvhdrhead, i); @@ -703,7 +703,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) (!hd && tl == dd->ipath_hdrqlast)) { if (i == 0) chkerrpkts = 1; - pd->port_lastrcvhdrqtail = tl; + dd->ipath_lastrcvhdrqtails[i] = tl; pd->port_hdrqfull++; /* flush hdrqfull so that poll() sees it */ wmb(); @@ -712,8 +712,6 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) } } if (errs & INFINIPATH_E_RRCVEGRFULL) { - struct ipath_portdata *pd = dd->ipath_pd[0]; - /* * since this is of less importance and not likely to * happen without also getting hdrfull, only count @@ -721,7 +719,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) * vs user) */ ipath_stats.sps_etidfull++; - if (pd->port_head != + if (dd->ipath_port0head != (u32) le64_to_cpu(*dd->ipath_hdrqtailptr)) chkerrpkts = 1; } @@ -797,7 +795,6 @@ void ipath_clear_freeze(struct ipath_devdata *dd) { int i, im; __le64 val; - unsigned long flags; /* disable error interrupts, to avoid confusion */ ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL); @@ -816,14 +813,11 @@ void ipath_clear_freeze(struct ipath_devdata *dd) dd->ipath_control); /* ensure pio avail updates continue */ - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD); ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - dd->ipath_sendctrl); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); + dd->ipath_sendctrl); /* * We just enabled pioavailupdate, so dma copy is almost certainly @@ -831,8 +825,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd) */ for (i = 0; i < dd->ipath_pioavregs; i++) { /* deal with 6110 chip bug */ - im = i > 3 ? i ^ 1 : i; - val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im); + im = i > 3 ? ((i&1) ? i-1 : i+1) : i; + val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im); dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i] = le64_to_cpu(val); } @@ -855,7 +849,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd) /* this is separate to allow for better optimization of ipath_intr() */ -static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp) +static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp) { /* * sometimes happen during driver init and unload, don't want @@ -883,7 +877,7 @@ static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp) dd->ipath_f_free_irq(dd); } } - if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) { + if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) { ipath_dev_err(dd, "%u unexpected interrupts, " "disabling interrupts completely\n", *unexpectp); @@ -898,7 +892,7 @@ static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp) "ignoring\n"); } -static noinline void ipath_bad_regread(struct ipath_devdata *dd) +static void ipath_bad_regread(struct ipath_devdata *dd) { static int allbits; @@ -926,9 +920,31 @@ static noinline void ipath_bad_regread(struct ipath_devdata *dd) } } +static void handle_port_pioavail(struct ipath_devdata *dd) +{ + u32 i; + /* + * start from port 1, since for now port 0 is never using + * wait_event for PIO + */ + for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) { + struct ipath_portdata *pd = dd->ipath_pd[i]; + + if (pd && pd->port_cnt && + dd->ipath_portpiowait & (1U << i)) { + clear_bit(i, &dd->ipath_portpiowait); + if (test_bit(IPATH_PORT_WAITING_PIO, + &pd->port_flag)) { + clear_bit(IPATH_PORT_WAITING_PIO, + &pd->port_flag); + wake_up_interruptible(&pd->port_wait); + } + } + } +} + static void handle_layer_pioavail(struct ipath_devdata *dd) { - unsigned long flags; int ret; ret = ipath_ib_piobufavail(dd->verbs_dev); @@ -937,12 +953,9 @@ static void handle_layer_pioavail(struct ipath_devdata *dd) return; set: - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); - dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL; + set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); } /* @@ -956,15 +969,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) int i; int rcvdint = 0; - /* - * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and - * test_and_clear_bit(IPATH_PORT_WAITING_URG) below - * would both like timely updates of the bits so that - * we don't pass them by unnecessarily. the rmb() - * here ensures that we see them promptly -- the - * corresponding wmb()'s are in ipath_poll_urgent() - * and ipath_poll_next()... - */ + /* test_bit below needs this... */ rmb(); portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & dd->ipath_i_rcvavail_mask) @@ -975,7 +980,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) if (portr & (1 << i) && pd && pd->port_cnt) { if (test_and_clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) { - clear_bit(i + dd->ipath_r_intravail_shift, + clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, &dd->ipath_rcvctrl); wake_up_interruptible(&pd->port_wait); rcvdint = 1; @@ -1034,7 +1039,7 @@ irqreturn_t ipath_intr(int irq, void *data) goto bail; } - istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus); + istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); if (unlikely(!istat)) { ipath_stats.sps_nullintr++; @@ -1175,7 +1180,7 @@ irqreturn_t ipath_intr(int irq, void *data) * for receive are at the bottom. */ if (chk0rcv) { - ipath_kreceive(dd->ipath_pd[0]); + ipath_kreceive(dd); istat &= ~port0rbits; } @@ -1186,14 +1191,12 @@ irqreturn_t ipath_intr(int irq, void *data) handle_urcv(dd, istat); if (istat & INFINIPATH_I_SPIOBUFAVAIL) { - unsigned long flags; - - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); - dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL; + clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); + + if (dd->ipath_portpiowait) + handle_port_pioavail(dd); handle_layer_pioavail(dd); } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h b/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h index 4cc0f95ea877..bb1dc075f1d1 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -141,11 +140,6 @@ struct ipath_portdata { u32 port_pionowait; /* total number of rcvhdrqfull errors */ u32 port_hdrqfull; - /* - * Used to suppress multiple instances of same - * port staying stuck at same point. - */ - u32 port_lastrcvhdrqtail; /* saved total number of rcvhdrqfull errors for poll edge trigger */ u32 port_hdrqfull_poll; /* total number of polled urgent packets */ @@ -154,7 +148,6 @@ struct ipath_portdata { u32 port_urgent_poll; /* pid of process using this port */ pid_t port_pid; - pid_t port_subpid[INFINIPATH_MAX_SUBPORT]; /* same size as task_struct .comm[] */ char port_comm[16]; /* pkeys set by this use of this port */ @@ -173,8 +166,6 @@ struct ipath_portdata { u32 active_slaves; /* Type of packets or conditions we want to poll for */ u16 poll_type; - /* port rcvhdrq head offset */ - u32 port_head; }; struct sk_buff; @@ -191,22 +182,6 @@ struct ipath_skbinfo { dma_addr_t phys; }; -/* - * Possible IB config parameters for ipath_f_get/set_ib_cfg() - */ -#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */ -#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */ -#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */ -#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */ -#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */ -#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */ -#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */ -#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */ -#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */ -#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */ -#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */ - - struct ipath_devdata { struct list_head ipath_list; @@ -247,8 +222,6 @@ struct ipath_devdata { struct _ipath_layer ipath_layer; /* setup intr */ int (*ipath_f_intrsetup)(struct ipath_devdata *); - /* fallback to alternate interrupt type if possible */ - int (*ipath_f_intr_fallback)(struct ipath_devdata *); /* setup on-chip bus config */ int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *); /* hard reset chip */ @@ -271,18 +244,6 @@ struct ipath_devdata { int (*ipath_f_get_base_info)(struct ipath_portdata *, void *); /* free irq */ void (*ipath_f_free_irq)(struct ipath_devdata *); - struct ipath_message_header *(*ipath_f_get_msgheader) - (struct ipath_devdata *, __le32 *); - void (*ipath_f_config_ports)(struct ipath_devdata *, ushort); - int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int); - int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32); - void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16); - void (*ipath_f_read_counters)(struct ipath_devdata *, - struct infinipath_counters *); - void (*ipath_f_xgxs_reset)(struct ipath_devdata *); - /* per chip actions needed for IB Link up/down changes */ - int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64); - struct ipath_ibdev *verbs_dev; struct timer_list verbs_timer; /* total dwords sent (summed from counter) */ @@ -352,11 +313,21 @@ struct ipath_devdata { * supports, less gives more pio bufs/port, etc. */ u32 ipath_cfgports; + /* port0 rcvhdrq head offset */ + u32 ipath_port0head; /* count of port 0 hdrqfull errors */ u32 ipath_p0_hdrqfull; - /* port 0 number of receive eager buffers */ - u32 ipath_p0_rcvegrcnt; + /* + * (*cfgports) used to suppress multiple instances of same + * port staying stuck at same point + */ + u32 *ipath_lastrcvhdrqtails; + /* + * (*cfgports) used to suppress multiple instances of same + * port staying stuck at same point + */ + u32 *ipath_lastegrheads; /* * index of last piobuffer we used. Speeds up searching, by * starting at this point. Doesn't matter if multiple cpu's use and @@ -396,15 +367,14 @@ struct ipath_devdata { unsigned long ipath_wc_len; /* ref count for each pkey */ atomic_t ipath_pkeyrefs[4]; + /* shadow copy of all exptids physaddr; used only by funcsim */ + u64 *ipath_tidsimshadow; /* shadow copy of struct page *'s for exp tid pages */ struct page **ipath_pageshadow; /* shadow copy of dma handles for exp tid pages */ dma_addr_t *ipath_physshadow; - u64 __iomem *ipath_egrtidbase; - /* lock to workaround chip bug 9437 and others */ - spinlock_t ipath_kernel_tid_lock; + /* lock to workaround chip bug 9437 */ spinlock_t ipath_tid_lock; - spinlock_t ipath_sendctrl_lock; /* * IPATH_STATUS_*, @@ -425,8 +395,6 @@ struct ipath_devdata { void *ipath_dummy_hdrq; /* used after port close */ dma_addr_t ipath_dummy_hdrq_phys; - unsigned long ipath_ureg_align; /* user register alignment */ - /* * Shadow copies of registers; size indicates read access size. * Most of them are readonly, but some are write-only register, @@ -488,6 +456,8 @@ struct ipath_devdata { unsigned long ipath_rcvctrl; /* shadow kr_sendctrl */ unsigned long ipath_sendctrl; + /* ports waiting for PIOavail intr */ + unsigned long ipath_portpiowait; unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */ /* value we put in kr_rcvhdrcnt */ @@ -580,26 +550,12 @@ struct ipath_devdata { u8 ipath_minrev; /* board rev, from ipath_revision */ u8 ipath_boardrev; - - u8 ipath_r_portenable_shift; - u8 ipath_r_intravail_shift; - u8 ipath_r_tailupd_shift; - u8 ipath_r_portcfg_shift; - /* unit # of this chip, if present */ int ipath_unit; /* saved for restore after reset */ u8 ipath_pci_cacheline; /* LID mask control */ u8 ipath_lmc; - /* link width supported */ - u8 ipath_link_width_supported; - /* link speed supported */ - u8 ipath_link_speed_supported; - u8 ipath_link_width_enabled; - u8 ipath_link_speed_enabled; - u8 ipath_link_width_active; - u8 ipath_link_speed_active; /* Rx Polarity inversion (compensate for ~tx on partner) */ u8 ipath_rx_pol_inv; @@ -634,8 +590,6 @@ struct ipath_devdata { */ u32 ipath_i_rcvavail_mask; u32 ipath_i_rcvurg_mask; - u16 ipath_i_rcvurg_shift; - u16 ipath_i_rcvavail_shift; /* * Register bits for selecting i2c direction and values, used for @@ -649,29 +603,6 @@ struct ipath_devdata { /* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */ spinlock_t ipath_gpio_lock; - /* - * IB link and linktraining states and masks that vary per chip in - * some way. Set at init, to avoid each IB status change interrupt - */ - u8 ibcs_ls_shift; - u8 ibcs_lts_mask; - u32 ibcs_mask; - u32 ib_init; - u32 ib_arm; - u32 ib_active; - - u16 ipath_rhf_offset; /* offset of RHF within receive header entry */ - - /* - * shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol - * reg. Changes for IBA7220 - */ - u8 ibcc_lic_mask; /* LinkInitCmd */ - u8 ibcc_lc_shift; /* LinkCmd */ - u8 ibcc_mpl_shift; /* Maxpktlen */ - - u8 delay_mult; - /* used to override LED behavior */ u8 ipath_led_override; /* Substituted for normal value, if non-zero */ u16 ipath_led_override_timeoff; /* delta to next timer event */ @@ -685,7 +616,7 @@ struct ipath_devdata { /* control access to actual counters, timer */ spinlock_t ipath_eep_st_lock; /* control high-level access to EEPROM */ - struct mutex ipath_eep_lock; + struct semaphore ipath_eep_sem; /* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */ uint64_t ipath_traffic_wds; /* active time is kept in seconds, but logged in hours */ @@ -699,10 +630,6 @@ struct ipath_devdata { * each of the counters to increment. */ struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT]; - - /* interrupt mitigation reload register info */ - u16 ipath_jint_idle_ticks; /* idle clock ticks */ - u16 ipath_jint_max_packets; /* max packets across all ports */ }; /* Private data for file operations */ @@ -763,7 +690,7 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *); int ipath_parse_ushort(const char *str, unsigned short *valp); -void ipath_kreceive(struct ipath_portdata *); +void ipath_kreceive(struct ipath_devdata *); int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); int ipath_reset_device(int); void ipath_get_faststats(unsigned long); @@ -771,8 +698,6 @@ int ipath_set_linkstate(struct ipath_devdata *, u8); int ipath_set_mtu(struct ipath_devdata *, u16); int ipath_set_lid(struct ipath_devdata *, u32, u8); int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); -void ipath_enable_armlaunch(struct ipath_devdata *); -void ipath_disable_armlaunch(struct ipath_devdata *); /* for use in system calls, where we want to know device type, etc. */ #define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd @@ -819,15 +744,9 @@ void ipath_disable_armlaunch(struct ipath_devdata *); * are 64bit */ #define IPATH_32BITCOUNTERS 0x20000 /* can miss port0 rx interrupts */ - /* Interrupt register is 64 bits */ -#define IPATH_INTREG_64 0x40000 #define IPATH_DISABLED 0x80000 /* administratively disabled */ /* Use GPIO interrupts for new counters */ #define IPATH_GPIO_ERRINTRS 0x100000 -#define IPATH_SWAP_PIOBUFS 0x200000 - /* Suppress heartbeat, even if turning off loopback */ -#define IPATH_NO_HRTBT 0x1000000 -#define IPATH_HAS_MULT_IB_SPEED 0x8000000 /* Bits in GPIO for the added interrupts */ #define IPATH_GPIO_PORT0_BIT 2 @@ -839,6 +758,8 @@ void ipath_disable_armlaunch(struct ipath_devdata *); /* portdata flag bit offsets */ /* waiting for a packet to arrive */ #define IPATH_PORT_WAITING_RCV 2 + /* waiting for a PIO buffer to be available */ +#define IPATH_PORT_WAITING_PIO 3 /* master has not finished initializing */ #define IPATH_PORT_MASTER_UNINIT 4 /* waiting for an urgent packet to arrive */ @@ -846,6 +767,8 @@ void ipath_disable_armlaunch(struct ipath_devdata *); /* free up any allocated data at closes */ void ipath_free_data(struct ipath_portdata *dd); +int ipath_waitfor_mdio_cmdready(struct ipath_devdata *); +int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *); u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *); void ipath_init_iba6120_funcs(struct ipath_devdata *); void ipath_init_iba6110_funcs(struct ipath_devdata *); @@ -869,6 +792,33 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val); */ #define IPATH_DFLT_RCVHDRSIZE 9 +#define IPATH_MDIO_CMD_WRITE 1 +#define IPATH_MDIO_CMD_READ 2 +#define IPATH_MDIO_CLD_DIV 25 /* to get 2.5 Mhz mdio clock */ +#define IPATH_MDIO_CMDVALID 0x40000000 /* bit 30 */ +#define IPATH_MDIO_DATAVALID 0x80000000 /* bit 31 */ +#define IPATH_MDIO_CTRL_STD 0x0 + +static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data) +{ + return (((u64) IPATH_MDIO_CLD_DIV) << 32) | + (cmd << 26) | + (dev << 21) | + (reg << 16) | + (data & 0xFFFF); +} + + /* signal and fifo status, in bank 31 */ +#define IPATH_MDIO_CTRL_XGXS_REG_8 0x8 + /* controls loopback, redundancy */ +#define IPATH_MDIO_CTRL_8355_REG_1 0x10 + /* premph, encdec, etc. */ +#define IPATH_MDIO_CTRL_8355_REG_2 0x11 + /* Kchars, etc. */ +#define IPATH_MDIO_CTRL_8355_REG_6 0x15 +#define IPATH_MDIO_CTRL_8355_REG_9 0x18 +#define IPATH_MDIO_CTRL_8355_REG_10 0x1D + int ipath_get_user_pages(unsigned long, size_t, struct page **); void ipath_release_user_pages(struct page **, size_t); void ipath_release_user_pages_on_close(struct page **, size_t); @@ -913,7 +863,7 @@ static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd, return readl(regno + (u64 __iomem *) (dd->ipath_uregbase + (char __iomem *)dd->ipath_kregbase + - dd->ipath_ureg_align * port)); + dd->ipath_palign * port)); } /** @@ -930,7 +880,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd, { u64 __iomem *ubase = (u64 __iomem *) (dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase + - dd->ipath_ureg_align * port); + dd->ipath_palign * port); if (dd->ipath_kregbase) writeq(value, &ubase[regno]); } @@ -980,53 +930,6 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd, (char __iomem *)dd->ipath_kregbase)); } -static inline void ipath_write_creg(const struct ipath_devdata *dd, - ipath_creg regno, u64 value) -{ - if (dd->ipath_kregbase) - writeq(value, regno + (u64 __iomem *) - (dd->ipath_cregbase + - (char __iomem *)dd->ipath_kregbase)); -} - -static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd) -{ - *((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL; -} - -static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd) -{ - return (u32) le64_to_cpu(*((volatile __le64 *) - pd->port_rcvhdrtail_kvaddr)); -} - -static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r) -{ - return (dd->ipath_flags & IPATH_INTREG_64) ? - ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r); -} - -/* - * from contents of IBCStatus (or a saved copy), return linkstate - * Report ACTIVE_DEFER as ACTIVE, because we treat them the same - * everywhere, anyway (and should be, for almost all purposes). - */ -static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs) -{ - u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) & - INFINIPATH_IBCS_LINKSTATE_MASK; - if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER) - state = INFINIPATH_IBCS_L_STATE_ACTIVE; - return state; -} - -/* from contents of IBCStatus (or a saved copy), return linktrainingstate */ -static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs) -{ - return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & - dd->ibcs_lts_mask; -} - /* * sysfs interface. */ diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_keys.c b/trunk/drivers/infiniband/hw/ipath/ipath_keys.c index 8f32b17a5eed..85a4aefc6c03 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_keys.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_keys.c @@ -128,8 +128,9 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge, int ret; /* - * We use LKEY == zero for kernel virtual addresses - * (see ipath_get_dma_mr and ipath_dma.c). + * We use LKEY == zero to mean a physical kmalloc() address. + * This is a bit of a hack since we rely on dma_map_single() + * being reversible by calling bus_to_virt(). */ if (sge->lkey == 0) { struct ipath_pd *pd = to_ipd(qp->ibqp.pd); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_mad.c b/trunk/drivers/infiniband/hw/ipath/ipath_mad.c index d98d5f103700..3d1432d1e3f4 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_mad.c @@ -934,7 +934,6 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp, struct ib_pma_portsamplescontrol *p = (struct ib_pma_portsamplescontrol *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); - struct ipath_cregs const *crp = dev->dd->ipath_cregs; unsigned long flags; u8 port_select = p->port_select; @@ -956,10 +955,7 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp, p->counter_width = 4; /* 32 bit counters */ p->counter_mask0_9 = COUNTER_MASK0_9; spin_lock_irqsave(&dev->pending_lock, flags); - if (crp->cr_psstat) - p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat); - else - p->sample_status = dev->pma_sample_status; + p->sample_status = dev->pma_sample_status; p->sample_start = cpu_to_be32(dev->pma_sample_start); p->sample_interval = cpu_to_be32(dev->pma_sample_interval); p->tag = cpu_to_be16(dev->pma_tag); @@ -979,9 +975,8 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp, struct ib_pma_portsamplescontrol *p = (struct ib_pma_portsamplescontrol *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); - struct ipath_cregs const *crp = dev->dd->ipath_cregs; unsigned long flags; - u8 status; + u32 start; int ret; if (pmp->attr_mod != 0 || @@ -991,67 +986,59 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp, goto bail; } - spin_lock_irqsave(&dev->pending_lock, flags); - if (crp->cr_psstat) - status = ipath_read_creg32(dev->dd, crp->cr_psstat); - else - status = dev->pma_sample_status; - if (status == IB_PMA_SAMPLE_STATUS_DONE) { - dev->pma_sample_start = be32_to_cpu(p->sample_start); - dev->pma_sample_interval = be32_to_cpu(p->sample_interval); - dev->pma_tag = be16_to_cpu(p->tag); - dev->pma_counter_select[0] = p->counter_select[0]; - dev->pma_counter_select[1] = p->counter_select[1]; - dev->pma_counter_select[2] = p->counter_select[2]; - dev->pma_counter_select[3] = p->counter_select[3]; - dev->pma_counter_select[4] = p->counter_select[4]; - if (crp->cr_psstat) { - ipath_write_creg(dev->dd, crp->cr_psinterval, - dev->pma_sample_interval); - ipath_write_creg(dev->dd, crp->cr_psstart, - dev->pma_sample_start); - } else - dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED; + start = be32_to_cpu(p->sample_start); + if (start != 0) { + spin_lock_irqsave(&dev->pending_lock, flags); + if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) { + dev->pma_sample_status = + IB_PMA_SAMPLE_STATUS_STARTED; + dev->pma_sample_start = start; + dev->pma_sample_interval = + be32_to_cpu(p->sample_interval); + dev->pma_tag = be16_to_cpu(p->tag); + if (p->counter_select[0]) + dev->pma_counter_select[0] = + p->counter_select[0]; + if (p->counter_select[1]) + dev->pma_counter_select[1] = + p->counter_select[1]; + if (p->counter_select[2]) + dev->pma_counter_select[2] = + p->counter_select[2]; + if (p->counter_select[3]) + dev->pma_counter_select[3] = + p->counter_select[3]; + if (p->counter_select[4]) + dev->pma_counter_select[4] = + p->counter_select[4]; + } + spin_unlock_irqrestore(&dev->pending_lock, flags); } - spin_unlock_irqrestore(&dev->pending_lock, flags); - ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port); bail: return ret; } -static u64 get_counter(struct ipath_ibdev *dev, - struct ipath_cregs const *crp, - __be16 sel) +static u64 get_counter(struct ipath_ibdev *dev, __be16 sel) { u64 ret; switch (sel) { case IB_PMA_PORT_XMIT_DATA: - ret = (crp->cr_psxmitdatacount) ? - ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) : - dev->ipath_sword; + ret = dev->ipath_sword; break; case IB_PMA_PORT_RCV_DATA: - ret = (crp->cr_psrcvdatacount) ? - ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) : - dev->ipath_rword; + ret = dev->ipath_rword; break; case IB_PMA_PORT_XMIT_PKTS: - ret = (crp->cr_psxmitpktscount) ? - ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) : - dev->ipath_spkts; + ret = dev->ipath_spkts; break; case IB_PMA_PORT_RCV_PKTS: - ret = (crp->cr_psrcvpktscount) ? - ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) : - dev->ipath_rpkts; + ret = dev->ipath_rpkts; break; case IB_PMA_PORT_XMIT_WAIT: - ret = (crp->cr_psxmitwaitcount) ? - ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) : - dev->ipath_xmit_wait; + ret = dev->ipath_xmit_wait; break; default: ret = 0; @@ -1066,21 +1053,14 @@ static int recv_pma_get_portsamplesresult(struct ib_perf *pmp, struct ib_pma_portsamplesresult *p = (struct ib_pma_portsamplesresult *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); - struct ipath_cregs const *crp = dev->dd->ipath_cregs; - u8 status; int i; memset(pmp->data, 0, sizeof(pmp->data)); p->tag = cpu_to_be16(dev->pma_tag); - if (crp->cr_psstat) - status = ipath_read_creg32(dev->dd, crp->cr_psstat); - else - status = dev->pma_sample_status; - p->sample_status = cpu_to_be16(status); + p->sample_status = cpu_to_be16(dev->pma_sample_status); for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++) - p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 : - cpu_to_be32( - get_counter(dev, crp, dev->pma_counter_select[i])); + p->counter[i] = cpu_to_be32( + get_counter(dev, dev->pma_counter_select[i])); return reply((struct ib_smp *) pmp); } @@ -1091,23 +1071,16 @@ static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp, struct ib_pma_portsamplesresult_ext *p = (struct ib_pma_portsamplesresult_ext *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); - struct ipath_cregs const *crp = dev->dd->ipath_cregs; - u8 status; int i; memset(pmp->data, 0, sizeof(pmp->data)); p->tag = cpu_to_be16(dev->pma_tag); - if (crp->cr_psstat) - status = ipath_read_creg32(dev->dd, crp->cr_psstat); - else - status = dev->pma_sample_status; - p->sample_status = cpu_to_be16(status); + p->sample_status = cpu_to_be16(dev->pma_sample_status); /* 64 bits */ p->extended_width = __constant_cpu_to_be32(0x80000000); for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++) - p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 : - cpu_to_be64( - get_counter(dev, crp, dev->pma_counter_select[i])); + p->counter[i] = cpu_to_be64( + get_counter(dev, dev->pma_counter_select[i])); return reply((struct ib_smp *) pmp); } @@ -1140,8 +1113,6 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp, dev->z_local_link_integrity_errors; cntrs.excessive_buffer_overrun_errors -= dev->z_excessive_buffer_overrun_errors; - cntrs.vl15_dropped -= dev->z_vl15_dropped; - cntrs.vl15_dropped += dev->n_vl15_dropped; memset(pmp->data, 0, sizeof(pmp->data)); @@ -1185,10 +1156,10 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp, cntrs.excessive_buffer_overrun_errors = 0xFUL; p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) | cntrs.excessive_buffer_overrun_errors; - if (cntrs.vl15_dropped > 0xFFFFUL) + if (dev->n_vl15_dropped > 0xFFFFUL) p->vl15_dropped = __constant_cpu_to_be16(0xFFFF); else - p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped); + p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped); if (cntrs.port_xmit_data > 0xFFFFFFFFUL) p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF); else @@ -1291,10 +1262,8 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp, dev->z_excessive_buffer_overrun_errors = cntrs.excessive_buffer_overrun_errors; - if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) { + if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) dev->n_vl15_dropped = 0; - dev->z_vl15_dropped = cntrs.vl15_dropped; - } if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA) dev->z_port_xmit_data = cntrs.port_xmit_data; @@ -1465,7 +1434,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags, * before checking for other consumers. * Just tell the caller to process it normally. */ - ret = IB_MAD_RESULT_SUCCESS; + ret = IB_MAD_RESULT_FAILURE; goto bail; default: smp->status |= IB_SMP_UNSUP_METHOD; @@ -1547,7 +1516,7 @@ static int process_perf(struct ib_device *ibdev, u8 port_num, * before checking for other consumers. * Just tell the caller to process it normally. */ - ret = IB_MAD_RESULT_SUCCESS; + ret = IB_MAD_RESULT_FAILURE; goto bail; default: pmp->status |= IB_SMP_UNSUP_METHOD; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_qp.c b/trunk/drivers/infiniband/hw/ipath/ipath_qp.c index 80dc623cee40..b997ff88401b 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_qp.c @@ -387,8 +387,8 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) struct ib_wc wc; int ret = 0; - ipath_dbg("QP%d/%d in error state (%d)\n", - qp->ibqp.qp_num, qp->remote_qpn, err); + ipath_dbg("QP%d/%d in error state\n", + qp->ibqp.qp_num, qp->remote_qpn); spin_lock(&dev->pending_lock); /* XXX What if its already removed by the timeout code? */ @@ -855,6 +855,8 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, * See ipath_mmap() for details. */ if (udata && udata->outlen >= sizeof(__u64)) { + int err; + if (!qp->r_rq.wq) { __u64 offset = 0; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_rc.c b/trunk/drivers/infiniband/hw/ipath/ipath_rc.c index 459e46e2c016..120a61b03bc4 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_rc.c @@ -647,7 +647,6 @@ static void send_rc_ack(struct ipath_qp *qp) queue_ack: spin_lock_irqsave(&qp->s_lock, flags); - dev->n_rc_qacks++; qp->s_flags |= IPATH_S_ACK_PENDING; qp->s_nak_state = qp->r_nak_state; qp->s_ack_psn = qp->r_ack_psn; @@ -799,13 +798,11 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc) static inline void update_last_psn(struct ipath_qp *qp, u32 psn) { - if (qp->s_last_psn != psn) { - qp->s_last_psn = psn; - if (qp->s_wait_credit) { - qp->s_wait_credit = 0; - tasklet_hi_schedule(&qp->s_task); - } + if (qp->s_wait_credit) { + qp->s_wait_credit = 0; + tasklet_hi_schedule(&qp->s_task); } + qp->s_last_psn = psn; } /** @@ -1656,6 +1653,13 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, case OP(SEND_FIRST): if (!ipath_get_rwqe(qp, 0)) { rnr_nak: + /* + * A RNR NAK will ACK earlier sends and RDMA writes. + * Don't queue the NAK if a RDMA read or atomic + * is pending though. + */ + if (qp->r_nak_state) + goto done; qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer; qp->r_ack_psn = qp->r_psn; goto send_ack; diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_registers.h b/trunk/drivers/infiniband/hw/ipath/ipath_registers.h index 6d2a17f9c1da..708eba3165d7 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_registers.h @@ -82,7 +82,8 @@ /* kr_rcvctrl bits */ #define INFINIPATH_R_PORTENABLE_SHIFT 0 -#define INFINIPATH_R_QPMAP_ENABLE (1ULL << 38) +#define INFINIPATH_R_INTRAVAIL_SHIFT 16 +#define INFINIPATH_R_TAILUPD 0x80000000 /* kr_intstatus, kr_intclear, kr_intmask bits */ #define INFINIPATH_I_RCVURG_SHIFT 0 @@ -271,6 +272,20 @@ #define INFINIPATH_EXTC_LEDGBLOK_ON 0x00000002ULL #define INFINIPATH_EXTC_LEDGBLERR_OFF 0x00000001ULL +/* kr_mdio bits */ +#define INFINIPATH_MDIO_CLKDIV_MASK 0x7FULL +#define INFINIPATH_MDIO_CLKDIV_SHIFT 32 +#define INFINIPATH_MDIO_COMMAND_MASK 0x7ULL +#define INFINIPATH_MDIO_COMMAND_SHIFT 26 +#define INFINIPATH_MDIO_DEVADDR_MASK 0x1FULL +#define INFINIPATH_MDIO_DEVADDR_SHIFT 21 +#define INFINIPATH_MDIO_REGADDR_MASK 0x1FULL +#define INFINIPATH_MDIO_REGADDR_SHIFT 16 +#define INFINIPATH_MDIO_DATA_MASK 0xFFFFULL +#define INFINIPATH_MDIO_DATA_SHIFT 0 +#define INFINIPATH_MDIO_CMDVALID 0x0000000040000000ULL +#define INFINIPATH_MDIO_RDDATAVALID 0x0000000080000000ULL + /* kr_partitionkey bits */ #define INFINIPATH_PKEY_SIZE 16 #define INFINIPATH_PKEY_MASK 0xFFFF @@ -288,6 +303,8 @@ /* kr_xgxsconfig bits */ #define INFINIPATH_XGXS_RESET 0x7ULL +#define INFINIPATH_XGXS_MDIOADDR_MASK 0xfULL +#define INFINIPATH_XGXS_MDIOADDR_SHIFT 4 #define INFINIPATH_XGXS_RX_POL_SHIFT 19 #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL @@ -453,20 +470,6 @@ struct ipath_cregs { ipath_creg cr_unsupvlcnt; ipath_creg cr_wordrcvcnt; ipath_creg cr_wordsendcnt; - ipath_creg cr_vl15droppedpktcnt; - ipath_creg cr_rxotherlocalphyerrcnt; - ipath_creg cr_excessbufferovflcnt; - ipath_creg cr_locallinkintegrityerrcnt; - ipath_creg cr_rxvlerrcnt; - ipath_creg cr_rxdlidfltrcnt; - ipath_creg cr_psstat; - ipath_creg cr_psstart; - ipath_creg cr_psinterval; - ipath_creg cr_psrcvdatacount; - ipath_creg cr_psrcvpktscount; - ipath_creg cr_psxmitdatacount; - ipath_creg cr_psxmitpktscount; - ipath_creg cr_psxmitwaitcount; }; #endif /* _IPATH_REGISTERS_H */ diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c b/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c index a59bdbd0ed87..54c61a972de2 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -98,15 +98,11 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp) while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) { qp->s_rnr_timeout -= nqp->s_rnr_timeout; l = l->next; - if (l->next == &dev->rnrwait) { - nqp = NULL; + if (l->next == &dev->rnrwait) break; - } nqp = list_entry(l->next, struct ipath_qp, timerwait); } - if (nqp) - nqp->s_rnr_timeout -= qp->s_rnr_timeout; list_add(&qp->timerwait, l); } spin_unlock_irqrestore(&dev->pending_lock, flags); @@ -483,14 +479,9 @@ static void ipath_ruc_loopback(struct ipath_qp *sqp) static void want_buffer(struct ipath_devdata *dd) { - unsigned long flags; - - spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); - dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL; + set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); - spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); } /** diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_srq.c b/trunk/drivers/infiniband/hw/ipath/ipath_srq.c index f772102e4713..2fef36f4b675 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_srq.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_srq.c @@ -94,8 +94,8 @@ int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, /** * ipath_create_srq - create a shared receive queue * @ibpd: the protection domain of the SRQ to create - * @srq_init_attr: the attributes of the SRQ - * @udata: data from libipathverbs when creating a user SRQ + * @attr: the attributes of the SRQ + * @udata: not used by the InfiniPath verbs driver */ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, struct ib_srq_init_attr *srq_init_attr, diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_stats.c b/trunk/drivers/infiniband/hw/ipath/ipath_stats.c index d2725cd11bdc..f0271415cd5b 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_stats.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_stats.c @@ -133,16 +133,15 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg) static void ipath_qcheck(struct ipath_devdata *dd) { static u64 last_tot_hdrqfull; - struct ipath_portdata *pd = dd->ipath_pd[0]; size_t blen = 0; char buf[128]; *buf = 0; - if (pd->port_hdrqfull != dd->ipath_p0_hdrqfull) { + if (dd->ipath_pd[0]->port_hdrqfull != dd->ipath_p0_hdrqfull) { blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u", - pd->port_hdrqfull - + dd->ipath_pd[0]->port_hdrqfull - dd->ipath_p0_hdrqfull); - dd->ipath_p0_hdrqfull = pd->port_hdrqfull; + dd->ipath_p0_hdrqfull = dd->ipath_pd[0]->port_hdrqfull; } if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) { blen += snprintf(buf + blen, sizeof buf - blen, @@ -174,7 +173,7 @@ static void ipath_qcheck(struct ipath_devdata *dd) if (blen) ipath_dbg("%s\n", buf); - if (pd->port_head != (u32) + if (dd->ipath_port0head != (u32) le64_to_cpu(*dd->ipath_hdrqtailptr)) { if (dd->ipath_lastport0rcv_cnt == ipath_stats.sps_port0pkts) { @@ -182,7 +181,7 @@ static void ipath_qcheck(struct ipath_devdata *dd) "port0 hd=%llx tl=%x; port0pkts %llx\n", (unsigned long long) le64_to_cpu(*dd->ipath_hdrqtailptr), - pd->port_head, + dd->ipath_port0head, (unsigned long long) ipath_stats.sps_port0pkts); } @@ -238,7 +237,7 @@ static void ipath_chk_errormask(struct ipath_devdata *dd) void ipath_get_faststats(unsigned long opaque) { struct ipath_devdata *dd = (struct ipath_devdata *) opaque; - int i; + u32 val; static unsigned cnt; unsigned long flags; u64 traffic_wds; @@ -322,11 +321,12 @@ void ipath_get_faststats(unsigned long opaque) /* limit qfull messages to ~one per minute per port */ if ((++cnt & 0x10)) { - for (i = (int) dd->ipath_cfgports; --i >= 0; ) { - struct ipath_portdata *pd = dd->ipath_pd[i]; - - if (pd && pd->port_lastrcvhdrqtail != -1) - pd->port_lastrcvhdrqtail = -1; + for (val = dd->ipath_cfgports - 1; ((int)val) >= 0; + val--) { + if (dd->ipath_lastegrheads[val] != -1) + dd->ipath_lastegrheads[val] = -1; + if (dd->ipath_lastrcvhdrqtails[val] != -1) + dd->ipath_lastrcvhdrqtails[val] = -1; } } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c b/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c index 56dfc8a2344c..aa27ca9f03b1 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -363,60 +363,6 @@ static ssize_t show_unit(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit); } -static ssize_t show_jint_max_packets(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - - return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets); -} - -static ssize_t store_jint_max_packets(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - u16 v = 0; - int ret; - - ret = ipath_parse_ushort(buf, &v); - if (ret < 0) - ipath_dev_err(dd, "invalid jint_max_packets.\n"); - else - dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v); - - return ret; -} - -static ssize_t show_jint_idle_ticks(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - - return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks); -} - -static ssize_t store_jint_idle_ticks(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - u16 v = 0; - int ret; - - ret = ipath_parse_ushort(buf, &v); - if (ret < 0) - ipath_dev_err(dd, "invalid jint_idle_ticks.\n"); - else - dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets); - - return ret; -} - #define DEVICE_COUNTER(name, attr) \ static ssize_t show_counter_##name(struct device *dev, \ struct device_attribute *attr, \ @@ -724,257 +670,6 @@ static ssize_t show_logged_errs(struct device *dev, return count; } -/* - * New sysfs entries to control various IB config. These all turn into - * accesses via ipath_f_get/set_ib_cfg. - * - * Get/Set heartbeat enable. Or of 1=enabled, 2=auto - */ -static ssize_t show_hrtbt_enb(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret; - - ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT); - if (ret >= 0) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); - return ret; -} - -static ssize_t store_hrtbt_enb(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret, r; - u16 val; - - ret = ipath_parse_ushort(buf, &val); - if (ret >= 0 && val > 3) - ret = -EINVAL; - if (ret < 0) { - ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n"); - goto bail; - } - - /* - * Set the "intentional" heartbeat enable per either of - * "Enable" and "Auto", as these are normally set together. - * This bit is consulted when leaving loopback mode, - * because entering loopback mode overrides it and automatically - * disables heartbeat. - */ - r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val); - if (r < 0) - ret = r; - else if (val == IPATH_IB_HRTBT_OFF) - dd->ipath_flags |= IPATH_NO_HRTBT; - else - dd->ipath_flags &= ~IPATH_NO_HRTBT; - -bail: - return ret; -} - -/* - * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric, - * _not_ the particular encoding of any given chip) - */ -static ssize_t show_lwid_enb(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret; - - ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB); - if (ret >= 0) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); - return ret; -} - -static ssize_t store_lwid_enb(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret, r; - u16 val; - - ret = ipath_parse_ushort(buf, &val); - if (ret >= 0 && (val == 0 || val > 3)) - ret = -EINVAL; - if (ret < 0) { - ipath_dev_err(dd, - "attempt to set invalid Link Width (enable)\n"); - goto bail; - } - - r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val); - if (r < 0) - ret = r; - -bail: - return ret; -} - -/* Get current link width */ -static ssize_t show_lwid(struct device *dev, - struct device_attribute *attr, - char *buf) - -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret; - - ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID); - if (ret >= 0) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); - return ret; -} - -/* - * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR. - */ -static ssize_t show_spd_enb(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret; - - ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB); - if (ret >= 0) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); - return ret; -} - -static ssize_t store_spd_enb(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret, r; - u16 val; - - ret = ipath_parse_ushort(buf, &val); - if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR))) - ret = -EINVAL; - if (ret < 0) { - ipath_dev_err(dd, - "attempt to set invalid Link Speed (enable)\n"); - goto bail; - } - - r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val); - if (r < 0) - ret = r; - -bail: - return ret; -} - -/* Get current link speed */ -static ssize_t show_spd(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret; - - ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD); - if (ret >= 0) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); - return ret; -} - -/* - * Get/Set RX polarity-invert enable. 0=no, 1=yes. - */ -static ssize_t show_rx_polinv_enb(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret; - - ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB); - if (ret >= 0) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); - return ret; -} - -static ssize_t store_rx_polinv_enb(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret, r; - u16 val; - - ret = ipath_parse_ushort(buf, &val); - if (ret < 0 || val > 1) - goto invalid; - - r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val); - if (r < 0) { - ret = r; - goto bail; - } - - goto bail; -invalid: - ipath_dev_err(dd, "attempt to set invalid Rx Polarity (enable)\n"); -bail: - return ret; -} -/* - * Get/Set RX lane-reversal enable. 0=no, 1=yes. - */ -static ssize_t show_lanerev_enb(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret; - - ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB); - if (ret >= 0) - ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); - return ret; -} - -static ssize_t store_lanerev_enb(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct ipath_devdata *dd = dev_get_drvdata(dev); - int ret, r; - u16 val; - - ret = ipath_parse_ushort(buf, &val); - if (ret >= 0 && val > 1) { - ret = -EINVAL; - ipath_dev_err(dd, - "attempt to set invalid Lane reversal (enable)\n"); - goto bail; - } - - r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val); - if (r < 0) - ret = r; - -bail: - return ret; -} - static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); @@ -1011,10 +706,6 @@ static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv); static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override); static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL); -static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO, - show_jint_max_packets, store_jint_max_packets); -static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO, - show_jint_idle_ticks, store_jint_idle_ticks); static struct attribute *dev_attributes[] = { &dev_attr_guid.attr, @@ -1041,34 +732,6 @@ static struct attribute_group dev_attr_group = { .attrs = dev_attributes }; -static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb, - store_hrtbt_enb); -static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb, - store_lwid_enb); -static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL); -static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb, - store_spd_enb); -static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL); -static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb, - store_rx_polinv_enb); -static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb, - store_lanerev_enb); - -static struct attribute *dev_ibcfg_attributes[] = { - &dev_attr_hrtbt_enable.attr, - &dev_attr_link_width_enable.attr, - &dev_attr_link_width.attr, - &dev_attr_link_speed_enable.attr, - &dev_attr_link_speed.attr, - &dev_attr_rx_pol_inv_enable.attr, - &dev_attr_rx_lane_rev_enable.attr, - NULL -}; - -static struct attribute_group dev_ibcfg_attr_group = { - .attrs = dev_ibcfg_attributes -}; - /** * ipath_expose_reset - create a device reset file * @dev: the device structure @@ -1107,26 +770,6 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) if (ret) goto bail_attrs; - if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) { - ret = device_create_file(dev, &dev_attr_jint_idle_ticks); - if (ret) - goto bail_counter; - ret = device_create_file(dev, &dev_attr_jint_max_packets); - if (ret) - goto bail_idle; - - ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group); - if (ret) - goto bail_max; - } - - return 0; - -bail_max: - device_remove_file(dev, &dev_attr_jint_max_packets); -bail_idle: - device_remove_file(dev, &dev_attr_jint_idle_ticks); -bail_counter: sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); bail_attrs: sysfs_remove_group(&dev->kobj, &dev_attr_group); @@ -1137,13 +780,6 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd) { sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); - - if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) { - sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group); - device_remove_file(dev, &dev_attr_jint_idle_ticks); - device_remove_file(dev, &dev_attr_jint_max_packets); - } - sysfs_remove_group(&dev->kobj, &dev_attr_group); device_remove_file(dev, &dev_attr_reset); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_ud.c b/trunk/drivers/infiniband/hw/ipath/ipath_ud.c index de67eed08ed0..b3df6f3c705e 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_ud.c @@ -301,6 +301,8 @@ int ipath_make_ud_req(struct ipath_qp *qp) /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ qp->s_hdrwords = 7; + if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) + qp->s_hdrwords++; qp->s_cur_size = wqe->length; qp->s_cur_sge = &qp->s_sge; qp->s_wqe = wqe; @@ -325,7 +327,6 @@ int ipath_make_ud_req(struct ipath_qp *qp) ohdr = &qp->s_hdr.u.oth; } if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) { - qp->s_hdrwords++; ohdr->u.ud.imm_data = wqe->wr.imm_data; bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24; } else diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c index 32d8f882e56c..c4c998446c7b 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -943,7 +943,7 @@ static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords, * ipath_verbs_send - send a packet * @qp: the QP to send on * @hdr: the packet header - * @hdrwords: the number of 32-bit words in the header + * @hdrwords: the number of words in the header * @ss: the SGE to send * @len: the length of the packet in bytes */ @@ -955,10 +955,7 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, int ret; u32 dwords = (len + 3) >> 2; - /* - * Calculate the send buffer trigger address. - * The +1 counts for the pbc control dword following the pbc length. - */ + /* +1 is for the qword padding of pbc */ plen = hdrwords + dwords + 1; /* Drop non-VL15 packets if we are not in the active state */ @@ -1133,34 +1130,20 @@ static int ipath_query_device(struct ib_device *ibdev, return 0; } -const u8 ipath_cvt_physportstate[32] = { - [INFINIPATH_IBCS_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED, - [INFINIPATH_IBCS_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP, - [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL, - [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL, - [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP, - [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP, - [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = - IB_PHYSPORTSTATE_CFG_TRAIN, - [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = - IB_PHYSPORTSTATE_CFG_TRAIN, - [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = - IB_PHYSPORTSTATE_CFG_TRAIN, - [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN, - [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = - IB_PHYSPORTSTATE_LINK_ERR_RECOVER, - [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = - IB_PHYSPORTSTATE_LINK_ERR_RECOVER, - [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = - IB_PHYSPORTSTATE_LINK_ERR_RECOVER, - [0x10] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x11] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x13] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN, - [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN +const u8 ipath_cvt_physportstate[16] = { + [INFINIPATH_IBCS_LT_STATE_DISABLED] = 3, + [INFINIPATH_IBCS_LT_STATE_LINKUP] = 5, + [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2, + [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2, + [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1, + [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1, + [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4, + [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4, + [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4, + [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4, + [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6, + [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6, + [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6, }; u32 ipath_get_cr_errpkey(struct ipath_devdata *dd) @@ -1185,9 +1168,8 @@ static int ipath_query_port(struct ib_device *ibdev, ibcstat = dd->ipath_lastibcstat; props->state = ((ibcstat >> 4) & 0x3) + 1; /* See phys_state_show() */ - props->phys_state = /* MEA: assumes shift == 0 */ - ipath_cvt_physportstate[dd->ipath_lastibcstat & - dd->ibcs_lts_mask]; + props->phys_state = ipath_cvt_physportstate[ + dd->ipath_lastibcstat & 0xf]; props->port_cap_flags = dev->port_cap_flags; props->gid_tbl_len = 1; props->max_msg_sz = 0x80000000; @@ -1659,7 +1641,6 @@ int ipath_register_ib_device(struct ipath_devdata *dd) cntrs.local_link_integrity_errors; idev->z_excessive_buffer_overrun_errors = cntrs.excessive_buffer_overrun_errors; - idev->z_vl15_dropped = cntrs.vl15_dropped; /* * The system image GUID is supposed to be the same for all diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h index 3d59736b49b2..6ccb54f104a3 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/trunk/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -554,7 +554,6 @@ struct ipath_ibdev { u32 z_pkey_violations; /* starting count for PMA */ u32 z_local_link_integrity_errors; /* starting count for PMA */ u32 z_excessive_buffer_overrun_errors; /* starting count for PMA */ - u32 z_vl15_dropped; /* starting count for PMA */ u32 n_rc_resends; u32 n_rc_acks; u32 n_rc_qacks; @@ -599,7 +598,6 @@ struct ipath_verbs_counters { u64 port_rcv_packets; u32 local_link_integrity_errors; u32 excessive_buffer_overrun_errors; - u32 vl15_dropped; }; static inline struct ipath_mr *to_imr(struct ib_mr *ibmr) @@ -832,17 +830,7 @@ unsigned ipath_get_pkey(struct ipath_devdata *, unsigned); extern const enum ib_wc_opcode ib_ipath_wc_opcode[]; -/* - * Below converts HCA-specific LinkTrainingState to IB PhysPortState - * values. - */ extern const u8 ipath_cvt_physportstate[]; -#define IB_PHYSPORTSTATE_SLEEP 1 -#define IB_PHYSPORTSTATE_POLL 2 -#define IB_PHYSPORTSTATE_DISABLED 3 -#define IB_PHYSPORTSTATE_CFG_TRAIN 4 -#define IB_PHYSPORTSTATE_LINKUP 5 -#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6 extern const int ib_ipath_state_ops[]; diff --git a/trunk/drivers/infiniband/hw/mlx4/cq.c b/trunk/drivers/infiniband/hw/mlx4/cq.c index 7950aa6e8184..9d32c49cc651 100644 --- a/trunk/drivers/infiniband/hw/mlx4/cq.c +++ b/trunk/drivers/infiniband/hw/mlx4/cq.c @@ -313,7 +313,6 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, struct mlx4_ib_srq *srq; int is_send; int is_error; - u32 g_mlpath_rqpn; u16 wqe_ctr; cqe = next_cqe_sw(cq); @@ -427,10 +426,10 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, wc->slid = be16_to_cpu(cqe->rlid); wc->sl = cqe->sl >> 4; - g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); - wc->src_qp = g_mlpath_rqpn & 0xffffff; - wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; - wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; + wc->src_qp = be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff; + wc->dlid_path_bits = (be32_to_cpu(cqe->g_mlpath_rqpn) >> 24) & 0x7f; + wc->wc_flags |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ? + IB_WC_GRH : 0; wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; } diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_dev.h b/trunk/drivers/infiniband/hw/mthca/mthca_dev.h index 7bbdd1f4e6c7..15aa32eb78b6 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/trunk/drivers/infiniband/hw/mthca/mthca_dev.h @@ -60,12 +60,13 @@ enum { MTHCA_FLAG_DDR_HIDDEN = 1 << 1, MTHCA_FLAG_SRQ = 1 << 2, - MTHCA_FLAG_MSI_X = 1 << 3, - MTHCA_FLAG_NO_LAM = 1 << 4, - MTHCA_FLAG_FMR = 1 << 5, - MTHCA_FLAG_MEMFREE = 1 << 6, - MTHCA_FLAG_PCIE = 1 << 7, - MTHCA_FLAG_SINAI_OPT = 1 << 8 + MTHCA_FLAG_MSI = 1 << 3, + MTHCA_FLAG_MSI_X = 1 << 4, + MTHCA_FLAG_NO_LAM = 1 << 5, + MTHCA_FLAG_FMR = 1 << 6, + MTHCA_FLAG_MEMFREE = 1 << 7, + MTHCA_FLAG_PCIE = 1 << 8, + MTHCA_FLAG_SINAI_OPT = 1 << 9 }; enum { diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_eq.c b/trunk/drivers/infiniband/hw/mthca/mthca_eq.c index b60eb5df96e8..b29de51b7f35 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_eq.c @@ -827,7 +827,8 @@ int mthca_init_eq_table(struct mthca_dev *dev) if (err) goto err_out_free; - if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { + if (dev->mthca_flags & MTHCA_FLAG_MSI || + dev->mthca_flags & MTHCA_FLAG_MSI_X) { dev->eq_table.clr_mask = 0; } else { dev->eq_table.clr_mask = @@ -838,7 +839,8 @@ int mthca_init_eq_table(struct mthca_dev *dev) dev->eq_table.arm_mask = 0; - intr = dev->eq_table.inta_pin; + intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ? + 128 : dev->eq_table.inta_pin; err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE, (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr, diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_main.c b/trunk/drivers/infiniband/hw/mthca/mthca_main.c index 5cf8250d4e16..60de6f93869e 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_main.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_main.c @@ -65,9 +65,14 @@ static int msi_x = 1; module_param(msi_x, int, 0444); MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); +static int msi = 0; +module_param(msi, int, 0444); +MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)"); + #else /* CONFIG_PCI_MSI */ #define msi_x (0) +#define msi (0) #endif /* CONFIG_PCI_MSI */ @@ -811,11 +816,13 @@ static int mthca_setup_hca(struct mthca_dev *dev) err = mthca_NOP(dev, &status); if (err || status) { - if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { + if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) { mthca_warn(dev, "NOP command failed to generate interrupt " "(IRQ %d).\n", - dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector); - mthca_warn(dev, "Trying again with MSI-X disabled.\n"); + dev->mthca_flags & MTHCA_FLAG_MSI_X ? + dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : + dev->pdev->irq); + mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n"); } else { mthca_err(dev, "NOP command failed to generate interrupt " "(IRQ %d), aborting.\n", @@ -998,7 +1005,7 @@ static struct { .flags = 0 }, [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200), .flags = MTHCA_FLAG_PCIE }, - [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0), + [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0), .flags = MTHCA_FLAG_MEMFREE | MTHCA_FLAG_PCIE }, [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0), @@ -1121,12 +1128,29 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) if (msi_x && !mthca_enable_msi_x(mdev)) mdev->mthca_flags |= MTHCA_FLAG_MSI_X; + else if (msi) { + static int warned; + + if (!warned) { + printk(KERN_WARNING PFX "WARNING: MSI support will be " + "removed from the ib_mthca driver in January 2008.\n"); + printk(KERN_WARNING " If you are using MSI and cannot " + "switch to MSI-X, please tell " + ".\n"); + ++warned; + } + + if (!pci_enable_msi(pdev)) + mdev->mthca_flags |= MTHCA_FLAG_MSI; + } err = mthca_setup_hca(mdev); - if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) { + if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) { if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); - mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X; + if (mdev->mthca_flags & MTHCA_FLAG_MSI) + pci_disable_msi(pdev); + mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI); err = mthca_setup_hca(mdev); } @@ -1168,6 +1192,8 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) err_close: if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); + if (mdev->mthca_flags & MTHCA_FLAG_MSI) + pci_disable_msi(pdev); mthca_close_hca(mdev); @@ -1220,6 +1246,8 @@ static void __mthca_remove_one(struct pci_dev *pdev) if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); + if (mdev->mthca_flags & MTHCA_FLAG_MSI) + pci_disable_msi(pdev); ib_dealloc_device(&mdev->ib_dev); mthca_release_regions(pdev, mdev->mthca_flags & diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib.h b/trunk/drivers/infiniband/ulp/ipoib/ipoib.h index fe250c60607d..eb7edab0e836 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib.h @@ -56,43 +56,42 @@ /* constants */ enum { - IPOIB_PACKET_SIZE = 2048, - IPOIB_BUF_SIZE = IPOIB_PACKET_SIZE + IB_GRH_BYTES, + IPOIB_PACKET_SIZE = 2048, + IPOIB_BUF_SIZE = IPOIB_PACKET_SIZE + IB_GRH_BYTES, - IPOIB_ENCAP_LEN = 4, + IPOIB_ENCAP_LEN = 4, - IPOIB_CM_MTU = 0x10000 - 0x10, /* padding to align header to 16 */ - IPOIB_CM_BUF_SIZE = IPOIB_CM_MTU + IPOIB_ENCAP_LEN, - IPOIB_CM_HEAD_SIZE = IPOIB_CM_BUF_SIZE % PAGE_SIZE, - IPOIB_CM_RX_SG = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE, - IPOIB_RX_RING_SIZE = 128, - IPOIB_TX_RING_SIZE = 64, + IPOIB_CM_MTU = 0x10000 - 0x10, /* padding to align header to 16 */ + IPOIB_CM_BUF_SIZE = IPOIB_CM_MTU + IPOIB_ENCAP_LEN, + IPOIB_CM_HEAD_SIZE = IPOIB_CM_BUF_SIZE % PAGE_SIZE, + IPOIB_CM_RX_SG = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE, + IPOIB_RX_RING_SIZE = 128, + IPOIB_TX_RING_SIZE = 64, IPOIB_MAX_QUEUE_SIZE = 8192, IPOIB_MIN_QUEUE_SIZE = 2, - IPOIB_CM_MAX_CONN_QP = 4096, - IPOIB_NUM_WC = 4, + IPOIB_NUM_WC = 4, IPOIB_MAX_PATH_REC_QUEUE = 3, - IPOIB_MAX_MCAST_QUEUE = 3, - - IPOIB_FLAG_OPER_UP = 0, - IPOIB_FLAG_INITIALIZED = 1, - IPOIB_FLAG_ADMIN_UP = 2, - IPOIB_PKEY_ASSIGNED = 3, - IPOIB_PKEY_STOP = 4, - IPOIB_FLAG_SUBINTERFACE = 5, - IPOIB_MCAST_RUN = 6, - IPOIB_STOP_REAPER = 7, - IPOIB_MCAST_STARTED = 8, - IPOIB_FLAG_ADMIN_CM = 9, + IPOIB_MAX_MCAST_QUEUE = 3, + + IPOIB_FLAG_OPER_UP = 0, + IPOIB_FLAG_INITIALIZED = 1, + IPOIB_FLAG_ADMIN_UP = 2, + IPOIB_PKEY_ASSIGNED = 3, + IPOIB_PKEY_STOP = 4, + IPOIB_FLAG_SUBINTERFACE = 5, + IPOIB_MCAST_RUN = 6, + IPOIB_STOP_REAPER = 7, + IPOIB_MCAST_STARTED = 8, + IPOIB_FLAG_ADMIN_CM = 9, IPOIB_FLAG_UMCAST = 10, IPOIB_MAX_BACKOFF_SECONDS = 16, - IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */ + IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */ IPOIB_MCAST_FLAG_SENDONLY = 1, - IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ + IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ IPOIB_MCAST_FLAG_ATTACHED = 3, }; @@ -118,7 +117,7 @@ struct ipoib_pseudoheader { struct ipoib_mcast { struct ib_sa_mcmember_rec mcmember; struct ib_sa_multicast *mc; - struct ipoib_ah *ah; + struct ipoib_ah *ah; struct rb_node rb_node; struct list_head list; @@ -187,29 +186,27 @@ enum ipoib_cm_state { }; struct ipoib_cm_rx { - struct ib_cm_id *id; - struct ib_qp *qp; - struct ipoib_cm_rx_buf *rx_ring; - struct list_head list; - struct net_device *dev; - unsigned long jiffies; - enum ipoib_cm_state state; - int recv_count; + struct ib_cm_id *id; + struct ib_qp *qp; + struct list_head list; + struct net_device *dev; + unsigned long jiffies; + enum ipoib_cm_state state; }; struct ipoib_cm_tx { - struct ib_cm_id *id; - struct ib_qp *qp; + struct ib_cm_id *id; + struct ib_qp *qp; struct list_head list; struct net_device *dev; struct ipoib_neigh *neigh; struct ipoib_path *path; struct ipoib_tx_buf *tx_ring; - unsigned tx_head; - unsigned tx_tail; - unsigned long flags; - u32 mtu; - struct ib_wc ibwc[IPOIB_NUM_WC]; + unsigned tx_head; + unsigned tx_tail; + unsigned long flags; + u32 mtu; + struct ib_wc ibwc[IPOIB_NUM_WC]; }; struct ipoib_cm_rx_buf { @@ -218,28 +215,25 @@ struct ipoib_cm_rx_buf { }; struct ipoib_cm_dev_priv { - struct ib_srq *srq; + struct ib_srq *srq; struct ipoib_cm_rx_buf *srq_ring; - struct ib_cm_id *id; - struct list_head passive_ids; /* state: LIVE */ - struct list_head rx_error_list; /* state: ERROR */ - struct list_head rx_flush_list; /* state: FLUSH, drain not started */ - struct list_head rx_drain_list; /* state: FLUSH, drain started */ - struct list_head rx_reap_list; /* state: FLUSH, drain done */ + struct ib_cm_id *id; + struct list_head passive_ids; /* state: LIVE */ + struct list_head rx_error_list; /* state: ERROR */ + struct list_head rx_flush_list; /* state: FLUSH, drain not started */ + struct list_head rx_drain_list; /* state: FLUSH, drain started */ + struct list_head rx_reap_list; /* state: FLUSH, drain done */ struct work_struct start_task; struct work_struct reap_task; struct work_struct skb_task; struct work_struct rx_reap_task; struct delayed_work stale_task; struct sk_buff_head skb_queue; - struct list_head start_list; - struct list_head reap_list; - struct ib_wc ibwc[IPOIB_NUM_WC]; - struct ib_sge rx_sge[IPOIB_CM_RX_SG]; + struct list_head start_list; + struct list_head reap_list; + struct ib_wc ibwc[IPOIB_NUM_WC]; + struct ib_sge rx_sge[IPOIB_CM_RX_SG]; struct ib_recv_wr rx_wr; - int nonsrq_conn_qp; - int max_cm_mtu; - int num_frags; }; /* @@ -275,30 +269,30 @@ struct ipoib_dev_priv { struct work_struct pkey_event_task; struct ib_device *ca; - u8 port; - u16 pkey; - u16 pkey_index; - struct ib_pd *pd; - struct ib_mr *mr; - struct ib_cq *cq; - struct ib_qp *qp; - u32 qkey; + u8 port; + u16 pkey; + u16 pkey_index; + struct ib_pd *pd; + struct ib_mr *mr; + struct ib_cq *cq; + struct ib_qp *qp; + u32 qkey; union ib_gid local_gid; - u16 local_lid; + u16 local_lid; unsigned int admin_mtu; unsigned int mcast_mtu; struct ipoib_rx_buf *rx_ring; - spinlock_t tx_lock; + spinlock_t tx_lock; struct ipoib_tx_buf *tx_ring; - unsigned tx_head; - unsigned tx_tail; - struct ib_sge tx_sge; + unsigned tx_head; + unsigned tx_tail; + struct ib_sge tx_sge; struct ib_send_wr tx_wr; - unsigned tx_outstanding; + unsigned tx_outstanding; struct ib_wc ibwc[IPOIB_NUM_WC]; @@ -323,10 +317,10 @@ struct ipoib_dev_priv { struct ipoib_ah { struct net_device *dev; - struct ib_ah *ah; + struct ib_ah *ah; struct list_head list; - struct kref ref; - unsigned last_send; + struct kref ref; + unsigned last_send; }; struct ipoib_path { @@ -337,11 +331,11 @@ struct ipoib_path { struct list_head neigh_list; - int query_id; + int query_id; struct ib_sa_query *query; struct completion done; - struct rb_node rb_node; + struct rb_node rb_node; struct list_head list; }; @@ -350,7 +344,7 @@ struct ipoib_neigh { #ifdef CONFIG_INFINIBAND_IPOIB_CM struct ipoib_cm_tx *cm; #endif - union ib_gid dgid; + union ib_gid dgid; struct sk_buff_head queue; struct neighbour *neighbour; @@ -461,14 +455,12 @@ void ipoib_drain_cq(struct net_device *dev); #ifdef CONFIG_INFINIBAND_IPOIB_CM -#define IPOIB_FLAGS_RC 0x80 -#define IPOIB_FLAGS_UC 0x40 +#define IPOIB_FLAGS_RC 0x80 +#define IPOIB_FLAGS_UC 0x40 /* We don't support UC connections at the moment */ #define IPOIB_CM_SUPPORTED(ha) (ha[0] & (IPOIB_FLAGS_RC)) -extern int ipoib_max_conn_qp; - static inline int ipoib_cm_admin_enabled(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -499,18 +491,6 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t neigh->cm = tx; } -static inline int ipoib_cm_has_srq(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - return !!priv->cm.srq; -} - -static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - return priv->cm.max_cm_mtu; -} - void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx); int ipoib_cm_dev_open(struct net_device *dev); void ipoib_cm_dev_stop(struct net_device *dev); @@ -520,7 +500,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev); struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path, struct ipoib_neigh *neigh); void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx); -void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, +void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, unsigned int mtu); void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc); void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc); @@ -528,8 +508,6 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc); struct ipoib_cm_tx; -#define ipoib_max_conn_qp 0 - static inline int ipoib_cm_admin_enabled(struct net_device *dev) { return 0; @@ -555,16 +533,6 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t { } -static inline int ipoib_cm_has_srq(struct net_device *dev) -{ - return 0; -} - -static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev) -{ - return 0; -} - static inline void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx) { @@ -614,7 +582,7 @@ int ipoib_cm_add_mode_attr(struct net_device *dev) return 0; } -static inline void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, +static inline void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, unsigned int mtu) { dev_kfree_skb_any(skb); @@ -656,12 +624,12 @@ extern struct ib_sa_client ipoib_sa_client; extern int ipoib_debug_level; #define ipoib_dbg(priv, format, arg...) \ - do { \ + do { \ if (ipoib_debug_level > 0) \ ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ } while (0) #define ipoib_dbg_mcast(priv, format, arg...) \ - do { \ + do { \ if (mcast_debug_level > 0) \ ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ } while (0) @@ -674,7 +642,7 @@ extern int ipoib_debug_level; #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA #define ipoib_dbg_data(priv, format, arg...) \ - do { \ + do { \ if (data_debug_level > 0) \ ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ } while (0) diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 1818f958c250..059cf92b60a5 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -39,15 +39,6 @@ #include #include -#include "ipoib.h" - -int ipoib_max_conn_qp = 128; - -module_param_named(max_nonsrq_conn_qp, ipoib_max_conn_qp, int, 0444); -MODULE_PARM_DESC(max_nonsrq_conn_qp, - "Max number of connected-mode QPs per interface " - "(applied only if shared receive queue is not available)"); - #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA static int data_debug_level; @@ -56,6 +47,8 @@ MODULE_PARM_DESC(cm_data_debug_level, "Enable data path debug tracing for connected mode if > 0"); #endif +#include "ipoib.h" + #define IPOIB_CM_IETF_ID 0x1000000000000000ULL #define IPOIB_CM_RX_UPDATE_TIME (256 * HZ) @@ -88,7 +81,7 @@ static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags, ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); } -static int ipoib_cm_post_receive_srq(struct net_device *dev, int id) +static int ipoib_cm_post_receive(struct net_device *dev, int id) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_recv_wr *bad_wr; @@ -96,13 +89,13 @@ static int ipoib_cm_post_receive_srq(struct net_device *dev, int id) priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV; - for (i = 0; i < priv->cm.num_frags; ++i) + for (i = 0; i < IPOIB_CM_RX_SG; ++i) priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i]; ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr); if (unlikely(ret)) { ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret); - ipoib_cm_dma_unmap_rx(priv, priv->cm.num_frags - 1, + ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, priv->cm.srq_ring[id].mapping); dev_kfree_skb_any(priv->cm.srq_ring[id].skb); priv->cm.srq_ring[id].skb = NULL; @@ -111,33 +104,7 @@ static int ipoib_cm_post_receive_srq(struct net_device *dev, int id) return ret; } -static int ipoib_cm_post_receive_nonsrq(struct net_device *dev, - struct ipoib_cm_rx *rx, int id) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ib_recv_wr *bad_wr; - int i, ret; - - priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV; - - for (i = 0; i < IPOIB_CM_RX_SG; ++i) - priv->cm.rx_sge[i].addr = rx->rx_ring[id].mapping[i]; - - ret = ib_post_recv(rx->qp, &priv->cm.rx_wr, &bad_wr); - if (unlikely(ret)) { - ipoib_warn(priv, "post recv failed for buf %d (%d)\n", id, ret); - ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, - rx->rx_ring[id].mapping); - dev_kfree_skb_any(rx->rx_ring[id].skb); - rx->rx_ring[id].skb = NULL; - } - - return ret; -} - -static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, - struct ipoib_cm_rx_buf *rx_ring, - int id, int frags, +static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags, u64 mapping[IPOIB_CM_RX_SG]) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -174,7 +141,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, goto partial_error; } - rx_ring[id].skb = skb; + priv->cm.srq_ring[id].skb = skb; return skb; partial_error: @@ -188,23 +155,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, return NULL; } -static void ipoib_cm_free_rx_ring(struct net_device *dev, - struct ipoib_cm_rx_buf *rx_ring) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - int i; - - for (i = 0; i < ipoib_recvq_size; ++i) - if (rx_ring[i].skb) { - ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, - rx_ring[i].mapping); - dev_kfree_skb_any(rx_ring[i].skb); - } - - kfree(rx_ring); -} - -static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv) +static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv* priv) { struct ib_send_wr *bad_wr; struct ipoib_cm_rx *p; @@ -257,18 +208,12 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, .qp_type = IB_QPT_RC, .qp_context = p, }; - - if (!ipoib_cm_has_srq(dev)) { - attr.cap.max_recv_wr = ipoib_recvq_size; - attr.cap.max_recv_sge = IPOIB_CM_RX_SG; - } - return ib_create_qp(priv->pd, &attr); } static int ipoib_cm_modify_rx_qp(struct net_device *dev, - struct ib_cm_id *cm_id, struct ib_qp *qp, - unsigned psn) + struct ib_cm_id *cm_id, struct ib_qp *qp, + unsigned psn) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_attr qp_attr; @@ -321,60 +266,6 @@ static int ipoib_cm_modify_rx_qp(struct net_device *dev, return 0; } -static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_id, - struct ipoib_cm_rx *rx) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - int ret; - int i; - - rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL); - if (!rx->rx_ring) - return -ENOMEM; - - spin_lock_irq(&priv->lock); - - if (priv->cm.nonsrq_conn_qp >= ipoib_max_conn_qp) { - spin_unlock_irq(&priv->lock); - ib_send_cm_rej(cm_id, IB_CM_REJ_NO_QP, NULL, 0, NULL, 0); - ret = -EINVAL; - goto err_free; - } else - ++priv->cm.nonsrq_conn_qp; - - spin_unlock_irq(&priv->lock); - - for (i = 0; i < ipoib_recvq_size; ++i) { - if (!ipoib_cm_alloc_rx_skb(dev, rx->rx_ring, i, IPOIB_CM_RX_SG - 1, - rx->rx_ring[i].mapping)) { - ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); - ret = -ENOMEM; - goto err_count; - } - ret = ipoib_cm_post_receive_nonsrq(dev, rx, i); - if (ret) { - ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq " - "failed for buf %d\n", i); - ret = -EIO; - goto err_count; - } - } - - rx->recv_count = ipoib_recvq_size; - - return 0; - -err_count: - spin_lock_irq(&priv->lock); - --priv->cm.nonsrq_conn_qp; - spin_unlock_irq(&priv->lock); - -err_free: - ipoib_cm_free_rx_ring(dev, rx->rx_ring); - - return ret; -} - static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id, struct ib_qp *qp, struct ib_cm_req_event_param *req, unsigned psn) @@ -390,7 +281,7 @@ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id, rep.private_data_len = sizeof data; rep.flow_control = 0; rep.rnr_retry_count = req->rnr_retry_count; - rep.srq = ipoib_cm_has_srq(dev); + rep.srq = 1; rep.qp_num = qp->qp_num; rep.starting_psn = psn; return ib_send_cm_rep(cm_id, &rep); @@ -426,12 +317,6 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even if (ret) goto err_modify; - if (!ipoib_cm_has_srq(dev)) { - ret = ipoib_cm_nonsrq_init_rx(dev, cm_id, p); - if (ret) - goto err_modify; - } - spin_lock_irq(&priv->lock); queue_delayed_work(ipoib_workqueue, &priv->cm.stale_task, IPOIB_CM_RX_DELAY); @@ -516,14 +401,12 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space, void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_cm_rx_buf *rx_ring; unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV); struct sk_buff *skb, *newskb; struct ipoib_cm_rx *p; unsigned long flags; u64 mapping[IPOIB_CM_RX_SG]; int frags; - int has_srq; ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n", wr_id, wc->status); @@ -541,32 +424,18 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) return; } - p = wc->qp->qp_context; - - has_srq = ipoib_cm_has_srq(dev); - rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring; - - skb = rx_ring[wr_id].skb; + skb = priv->cm.srq_ring[wr_id].skb; if (unlikely(wc->status != IB_WC_SUCCESS)) { ipoib_dbg(priv, "cm recv error " "(status=%d, wrid=%d vend_err %x)\n", wc->status, wr_id, wc->vendor_err); ++dev->stats.rx_dropped; - if (has_srq) - goto repost; - else { - if (!--p->recv_count) { - spin_lock_irqsave(&priv->lock, flags); - list_move(&p->list, &priv->cm.rx_reap_list); - spin_unlock_irqrestore(&priv->lock, flags); - queue_work(ipoib_workqueue, &priv->cm.rx_reap_task); - } - return; - } + goto repost; } if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) { + p = wc->qp->qp_context; if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) { spin_lock_irqsave(&priv->lock, flags); p->jiffies = jiffies; @@ -581,7 +450,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len, (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE; - newskb = ipoib_cm_alloc_rx_skb(dev, rx_ring, wr_id, frags, mapping); + newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping); if (unlikely(!newskb)) { /* * If we can't allocate a new RX buffer, dump @@ -592,8 +461,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) goto repost; } - ipoib_cm_dma_unmap_rx(priv, frags, rx_ring[wr_id].mapping); - memcpy(rx_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping); + ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping); + memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping); ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", wc->byte_len, wc->slid); @@ -614,17 +483,9 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) netif_receive_skb(skb); repost: - if (has_srq) { - if (unlikely(ipoib_cm_post_receive_srq(dev, wr_id))) - ipoib_warn(priv, "ipoib_cm_post_receive_srq failed " - "for buf %d\n", wr_id); - } else { - if (unlikely(ipoib_cm_post_receive_nonsrq(dev, p, wr_id))) { - --p->recv_count; - ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq failed " - "for buf %d\n", wr_id); - } - } + if (unlikely(ipoib_cm_post_receive(dev, wr_id))) + ipoib_warn(priv, "ipoib_cm_post_receive failed " + "for buf %d\n", wr_id); } static inline int post_send(struct ipoib_dev_priv *priv, @@ -634,10 +495,10 @@ static inline int post_send(struct ipoib_dev_priv *priv, { struct ib_send_wr *bad_wr; - priv->tx_sge.addr = addr; - priv->tx_sge.length = len; + priv->tx_sge.addr = addr; + priv->tx_sge.length = len; - priv->tx_wr.wr_id = wr_id | IPOIB_OP_CM; + priv->tx_wr.wr_id = wr_id | IPOIB_OP_CM; return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr); } @@ -679,7 +540,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ tx_req->mapping = addr; if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), - addr, skb->len))) { + addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); ++dev->stats.tx_errors; ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); @@ -796,33 +657,10 @@ int ipoib_cm_dev_open(struct net_device *dev) return ret; } -static void ipoib_cm_free_rx_reap_list(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_cm_rx *rx, *n; - LIST_HEAD(list); - - spin_lock_irq(&priv->lock); - list_splice_init(&priv->cm.rx_reap_list, &list); - spin_unlock_irq(&priv->lock); - - list_for_each_entry_safe(rx, n, &list, list) { - ib_destroy_cm_id(rx->id); - ib_destroy_qp(rx->qp); - if (!ipoib_cm_has_srq(dev)) { - ipoib_cm_free_rx_ring(priv->dev, rx->rx_ring); - spin_lock_irq(&priv->lock); - --priv->cm.nonsrq_conn_qp; - spin_unlock_irq(&priv->lock); - } - kfree(rx); - } -} - void ipoib_cm_dev_stop(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_cm_rx *p; + struct ipoib_cm_rx *p, *n; unsigned long begin; LIST_HEAD(list); int ret; @@ -868,9 +706,15 @@ void ipoib_cm_dev_stop(struct net_device *dev) spin_lock_irq(&priv->lock); } + list_splice_init(&priv->cm.rx_reap_list, &list); + spin_unlock_irq(&priv->lock); - ipoib_cm_free_rx_reap_list(dev); + list_for_each_entry_safe(p, n, &list, list) { + ib_destroy_cm_id(p->id); + ib_destroy_qp(p->qp); + kfree(p); + } cancel_delayed_work(&priv->cm.stale_task); } @@ -955,7 +799,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ .sq_sig_type = IB_SIGNAL_ALL_WR, .qp_type = IB_QPT_RC, .qp_context = tx - }; + }; return ib_create_qp(priv->pd, &attr); } @@ -972,28 +816,28 @@ static int ipoib_cm_send_req(struct net_device *dev, data.qpn = cpu_to_be32(priv->qp->qp_num); data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE); - req.primary_path = pathrec; - req.alternate_path = NULL; - req.service_id = cpu_to_be64(IPOIB_CM_IETF_ID | qpn); - req.qp_num = qp->qp_num; - req.qp_type = qp->qp_type; - req.private_data = &data; - req.private_data_len = sizeof data; - req.flow_control = 0; + req.primary_path = pathrec; + req.alternate_path = NULL; + req.service_id = cpu_to_be64(IPOIB_CM_IETF_ID | qpn); + req.qp_num = qp->qp_num; + req.qp_type = qp->qp_type; + req.private_data = &data; + req.private_data_len = sizeof data; + req.flow_control = 0; - req.starting_psn = 0; /* FIXME */ + req.starting_psn = 0; /* FIXME */ /* * Pick some arbitrary defaults here; we could make these * module parameters if anyone cared about setting them. */ - req.responder_resources = 4; - req.remote_cm_response_timeout = 20; - req.local_cm_response_timeout = 20; - req.retry_count = 0; /* RFC draft warns against retries */ - req.rnr_retry_count = 0; /* RFC draft warns against retries */ - req.max_cm_retries = 15; - req.srq = ipoib_cm_has_srq(dev); + req.responder_resources = 4; + req.remote_cm_response_timeout = 20; + req.local_cm_response_timeout = 20; + req.retry_count = 0; /* RFC draft warns against retries */ + req.rnr_retry_count = 0; /* RFC draft warns against retries */ + req.max_cm_retries = 15; + req.srq = 1; return ib_send_cm_req(id, &req); } @@ -1306,7 +1150,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work) spin_unlock_irq(&priv->tx_lock); } -void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, +void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, unsigned int mtu) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -1322,8 +1166,20 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, static void ipoib_cm_rx_reap(struct work_struct *work) { - ipoib_cm_free_rx_reap_list(container_of(work, struct ipoib_dev_priv, - cm.rx_reap_task)->dev); + struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, + cm.rx_reap_task); + struct ipoib_cm_rx *p, *n; + LIST_HEAD(list); + + spin_lock_irq(&priv->lock); + list_splice_init(&priv->cm.rx_reap_list, &list); + spin_unlock_irq(&priv->lock); + + list_for_each_entry_safe(p, n, &list, list) { + ib_destroy_cm_id(p->id); + ib_destroy_qp(p->qp); + kfree(p); + } } static void ipoib_cm_stale_task(struct work_struct *work) @@ -1356,7 +1212,7 @@ static void ipoib_cm_stale_task(struct work_struct *work) } -static ssize_t show_mode(struct device *d, struct device_attribute *attr, +static ssize_t show_mode(struct device *d, struct device_attribute *attr, char *buf) { struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d)); @@ -1399,40 +1255,16 @@ int ipoib_cm_add_mode_attr(struct net_device *dev) return device_create_file(&dev->dev, &dev_attr_mode); } -static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) +int ipoib_cm_dev_init(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_srq_init_attr srq_init_attr = { .attr = { .max_wr = ipoib_recvq_size, - .max_sge = max_sge + .max_sge = IPOIB_CM_RX_SG } }; - - priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr); - if (IS_ERR(priv->cm.srq)) { - if (PTR_ERR(priv->cm.srq) != -ENOSYS) - printk(KERN_WARNING "%s: failed to allocate SRQ, error %ld\n", - priv->ca->name, PTR_ERR(priv->cm.srq)); - priv->cm.srq = NULL; - return; - } - - priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, - GFP_KERNEL); - if (!priv->cm.srq_ring) { - printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", - priv->ca->name, ipoib_recvq_size); - ib_destroy_srq(priv->cm.srq); - priv->cm.srq = NULL; - } -} - -int ipoib_cm_dev_init(struct net_device *dev) -{ - struct ipoib_dev_priv *priv = netdev_priv(dev); - int i, ret; - struct ib_device_attr attr; + int ret, i; INIT_LIST_HEAD(&priv->cm.passive_ids); INIT_LIST_HEAD(&priv->cm.reap_list); @@ -1449,53 +1281,43 @@ int ipoib_cm_dev_init(struct net_device *dev) skb_queue_head_init(&priv->cm.skb_queue); - ret = ib_query_device(priv->ca, &attr); - if (ret) { - printk(KERN_WARNING "ib_query_device() failed with %d\n", ret); + priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr); + if (IS_ERR(priv->cm.srq)) { + ret = PTR_ERR(priv->cm.srq); + priv->cm.srq = NULL; return ret; } - ipoib_dbg(priv, "max_srq_sge=%d\n", attr.max_srq_sge); - - attr.max_srq_sge = min_t(int, IPOIB_CM_RX_SG, attr.max_srq_sge); - ipoib_cm_create_srq(dev, attr.max_srq_sge); - if (ipoib_cm_has_srq(dev)) { - priv->cm.max_cm_mtu = attr.max_srq_sge * PAGE_SIZE - 0x10; - priv->cm.num_frags = attr.max_srq_sge; - ipoib_dbg(priv, "max_cm_mtu = 0x%x, num_frags=%d\n", - priv->cm.max_cm_mtu, priv->cm.num_frags); - } else { - priv->cm.max_cm_mtu = IPOIB_CM_MTU; - priv->cm.num_frags = IPOIB_CM_RX_SG; + priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, + GFP_KERNEL); + if (!priv->cm.srq_ring) { + printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n", + priv->ca->name, ipoib_recvq_size); + ipoib_cm_dev_cleanup(dev); + return -ENOMEM; } - for (i = 0; i < priv->cm.num_frags; ++i) + for (i = 0; i < IPOIB_CM_RX_SG; ++i) priv->cm.rx_sge[i].lkey = priv->mr->lkey; priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE; - for (i = 1; i < priv->cm.num_frags; ++i) + for (i = 1; i < IPOIB_CM_RX_SG; ++i) priv->cm.rx_sge[i].length = PAGE_SIZE; priv->cm.rx_wr.next = NULL; priv->cm.rx_wr.sg_list = priv->cm.rx_sge; - priv->cm.rx_wr.num_sge = priv->cm.num_frags; - - if (ipoib_cm_has_srq(dev)) { - for (i = 0; i < ipoib_recvq_size; ++i) { - if (!ipoib_cm_alloc_rx_skb(dev, priv->cm.srq_ring, i, - priv->cm.num_frags - 1, - priv->cm.srq_ring[i].mapping)) { - ipoib_warn(priv, "failed to allocate " - "receive buffer %d\n", i); - ipoib_cm_dev_cleanup(dev); - return -ENOMEM; - } + priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG; - if (ipoib_cm_post_receive_srq(dev, i)) { - ipoib_warn(priv, "ipoib_cm_post_receive_srq " - "failed for buf %d\n", i); - ipoib_cm_dev_cleanup(dev); - return -EIO; - } + for (i = 0; i < ipoib_recvq_size; ++i) { + if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1, + priv->cm.srq_ring[i].mapping)) { + ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); + ipoib_cm_dev_cleanup(dev); + return -ENOMEM; + } + if (ipoib_cm_post_receive(dev, i)) { + ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i); + ipoib_cm_dev_cleanup(dev); + return -EIO; } } @@ -1506,7 +1328,7 @@ int ipoib_cm_dev_init(struct net_device *dev) void ipoib_cm_dev_cleanup(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - int ret; + int i, ret; if (!priv->cm.srq) return; @@ -1520,7 +1342,13 @@ void ipoib_cm_dev_cleanup(struct net_device *dev) priv->cm.srq = NULL; if (!priv->cm.srq_ring) return; - - ipoib_cm_free_rx_ring(dev, priv->cm.srq_ring); + for (i = 0; i < ipoib_recvq_size; ++i) + if (priv->cm.srq_ring[i].skb) { + ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, + priv->cm.srq_ring[i].mapping); + dev_kfree_skb_any(priv->cm.srq_ring[i].skb); + priv->cm.srq_ring[i].skb = NULL; + } + kfree(priv->cm.srq_ring); priv->cm.srq_ring = NULL; } diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 8b882bbd1d05..44c174182a82 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -124,7 +124,7 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static const struct seq_operations ipoib_mcg_seq_ops = { +static struct seq_operations ipoib_mcg_seq_ops = { .start = ipoib_mcg_seq_start, .next = ipoib_mcg_seq_next, .stop = ipoib_mcg_seq_stop, @@ -230,7 +230,7 @@ static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static const struct seq_operations ipoib_path_seq_ops = { +static struct seq_operations ipoib_path_seq_ops = { .start = ipoib_path_seq_start, .next = ipoib_path_seq_next, .stop = ipoib_path_seq_stop, diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 52bc2bd5799a..5063dd509ad2 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -345,12 +345,12 @@ static inline int post_send(struct ipoib_dev_priv *priv, { struct ib_send_wr *bad_wr; - priv->tx_sge.addr = addr; - priv->tx_sge.length = len; + priv->tx_sge.addr = addr; + priv->tx_sge.length = len; - priv->tx_wr.wr_id = wr_id; + priv->tx_wr.wr_id = wr_id; priv->tx_wr.wr.ud.remote_qpn = qpn; - priv->tx_wr.wr.ud.ah = address; + priv->tx_wr.wr.ud.ah = address; return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr); } diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c index a082466f4a83..c9f6077b615e 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -182,20 +182,17 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu) struct ipoib_dev_priv *priv = netdev_priv(dev); /* dev->mtu > 2K ==> connected mode */ - if (ipoib_cm_admin_enabled(dev)) { - if (new_mtu > ipoib_cm_max_mtu(dev)) - return -EINVAL; - + if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) { if (new_mtu > priv->mcast_mtu) ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", priv->mcast_mtu); - dev->mtu = new_mtu; return 0; } - if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) + if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) { return -EINVAL; + } priv->admin_mtu = new_mtu; @@ -477,8 +474,8 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) INIT_LIST_HEAD(&path->neigh_list); memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); - path->pathrec.sgid = priv->local_gid; - path->pathrec.pkey = cpu_to_be16(priv->pkey); + path->pathrec.sgid = priv->local_gid; + path->pathrec.pkey = cpu_to_be16(priv->pkey); path->pathrec.numb_path = 1; path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; @@ -672,6 +669,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags))) return NETDEV_TX_LOCKED; + /* + * Check if our queue is stopped. Since we have the LLTX bit + * set, we can't rely on netif_stop_queue() preventing our + * xmit function from being called with a full queue. + */ + if (unlikely(netif_queue_stopped(dev))) { + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_BUSY; + } + if (likely(skb->dst && skb->dst->neighbour)) { if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { ipoib_path_lookup(skb, dev); @@ -943,34 +950,34 @@ static void ipoib_setup(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - dev->open = ipoib_open; - dev->stop = ipoib_stop; - dev->change_mtu = ipoib_change_mtu; - dev->hard_start_xmit = ipoib_start_xmit; - dev->tx_timeout = ipoib_timeout; - dev->header_ops = &ipoib_header_ops; - dev->set_multicast_list = ipoib_set_mcast_list; - dev->neigh_setup = ipoib_neigh_setup_dev; + dev->open = ipoib_open; + dev->stop = ipoib_stop; + dev->change_mtu = ipoib_change_mtu; + dev->hard_start_xmit = ipoib_start_xmit; + dev->tx_timeout = ipoib_timeout; + dev->header_ops = &ipoib_header_ops; + dev->set_multicast_list = ipoib_set_mcast_list; + dev->neigh_setup = ipoib_neigh_setup_dev; netif_napi_add(dev, &priv->napi, ipoib_poll, 100); - dev->watchdog_timeo = HZ; + dev->watchdog_timeo = HZ; - dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; /* * We add in INFINIBAND_ALEN to allow for the destination * address "pseudoheader" for skbs without neighbour struct. */ - dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN; - dev->addr_len = INFINIBAND_ALEN; - dev->type = ARPHRD_INFINIBAND; - dev->tx_queue_len = ipoib_sendq_size * 2; - dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX; + dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN; + dev->addr_len = INFINIBAND_ALEN; + dev->type = ARPHRD_INFINIBAND; + dev->tx_queue_len = ipoib_sendq_size * 2; + dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX; /* MTU will be reset when mcast join happens */ - dev->mtu = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN; - priv->mcast_mtu = priv->admin_mtu = dev->mtu; + dev->mtu = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN; + priv->mcast_mtu = priv->admin_mtu = dev->mtu; memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); @@ -1261,9 +1268,6 @@ static int __init ipoib_init_module(void) ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE); -#ifdef CONFIG_INFINIBAND_IPOIB_CM - ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); -#endif ret = ipoib_register_debugfs(); if (ret) diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 2628339e3a99..9bcfc7ad6aa6 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -702,7 +702,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) out: if (mcast && mcast->ah) { - if (skb->dst && + if (skb->dst && skb->dst->neighbour && !*to_ipoib_neigh(skb->dst->neighbour)) { struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour, @@ -710,7 +710,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) if (neigh) { kref_get(&mcast->ah->ref); - neigh->ah = mcast->ah; + neigh->ah = mcast->ah; list_add_tail(&neigh->list, &mcast->neigh_list); } } @@ -788,6 +788,10 @@ void ipoib_mcast_restart_task(struct work_struct *work) memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid); + /* Add in the P_Key */ + mgid.raw[4] = (priv->pkey >> 8) & 0xff; + mgid.raw[5] = priv->pkey & 0xff; + mcast = __ipoib_mcast_find(dev, &mgid); if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { struct ipoib_mcast *nmcast; diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 433e99ac227b..3c6e45db0ab5 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -172,12 +172,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) size = ipoib_sendq_size + ipoib_recvq_size + 1; ret = ipoib_cm_dev_init(dev); - if (!ret) { - if (ipoib_cm_has_srq(dev)) - size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */ - else - size += ipoib_recvq_size * ipoib_max_conn_qp; - } + if (!ret) + size += ipoib_recvq_size + 1 /* 1 extra for rx_drain_qp */; priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); if (IS_ERR(priv->cq)) { @@ -201,12 +197,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) priv->dev->dev_addr[2] = (priv->qp->qp_num >> 8) & 0xff; priv->dev->dev_addr[3] = (priv->qp->qp_num ) & 0xff; - priv->tx_sge.lkey = priv->mr->lkey; + priv->tx_sge.lkey = priv->mr->lkey; - priv->tx_wr.opcode = IB_WR_SEND; - priv->tx_wr.sg_list = &priv->tx_sge; - priv->tx_wr.num_sge = 1; - priv->tx_wr.send_flags = IB_SEND_SIGNALED; + priv->tx_wr.opcode = IB_WR_SEND; + priv->tx_wr.sg_list = &priv->tx_sge; + priv->tx_wr.num_sge = 1; + priv->tx_wr.send_flags = IB_SEND_SIGNALED; return 0; diff --git a/trunk/drivers/infiniband/ulp/iser/Kconfig b/trunk/drivers/infiniband/ulp/iser/Kconfig index 77dedba829e6..fe604c8d2996 100644 --- a/trunk/drivers/infiniband/ulp/iser/Kconfig +++ b/trunk/drivers/infiniband/ulp/iser/Kconfig @@ -8,5 +8,5 @@ config INFINIBAND_ISER that speak iSCSI over iSER over InfiniBand. The iSER protocol is defined by IETF. - See - and + See + and diff --git a/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c b/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c index dfa5a4544187..bad8dacafd10 100644 --- a/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/trunk/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -551,7 +551,6 @@ static struct scsi_host_template iscsi_iser_sht = { .module = THIS_MODULE, .name = "iSCSI Initiator over iSER, v." DRV_VER, .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, .max_sectors = 1024, diff --git a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c index ba1b455949c0..a6f2303ed14a 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c @@ -561,7 +561,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc, if (opcode == ISCSI_OP_SCSI_CMD_RSP) { itt = get_itt(hdr->itt); /* mask out cid and age bits */ if (!(itt < session->cmds_max)) - iser_err("itt can't be matched to task!!! " + iser_err("itt can't be matched to task!!!" "conn %p opcode %d cmds_max %d itt %d\n", conn->iscsi_conn,opcode,session->cmds_max,itt); /* use the mapping given with the cmds array indexed by itt */ diff --git a/trunk/drivers/infiniband/ulp/iser/iser_verbs.c b/trunk/drivers/infiniband/ulp/iser/iser_verbs.c index 714b8db02b29..654a4dce0236 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_verbs.c @@ -105,7 +105,7 @@ static int iser_create_device_ib_res(struct iser_device *device) } /** - * iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR, + * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR, * CQ and PD created with the device associated with the adapator. */ static void iser_free_device_ib_res(struct iser_device *device) @@ -475,11 +475,13 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve iser_disconnected_handler(cma_id); break; case RDMA_CM_EVENT_DEVICE_REMOVAL: - iser_err("Device removal is currently unsupported\n"); BUG(); break; + case RDMA_CM_EVENT_CONNECT_RESPONSE: + BUG(); + break; + case RDMA_CM_EVENT_CONNECT_REQUEST: default: - iser_err("Unexpected RDMA CM event (%d)\n", event->event); break; } return ret; diff --git a/trunk/drivers/infiniband/ulp/srp/ib_srp.c b/trunk/drivers/infiniband/ulp/srp/ib_srp.c index f2d2c7e2c76b..bdb6f8517401 100644 --- a/trunk/drivers/infiniband/ulp/srp/ib_srp.c +++ b/trunk/drivers/infiniband/ulp/srp/ib_srp.c @@ -272,8 +272,7 @@ static void srp_path_rec_completion(int status, target->status = status; if (status) - shost_printk(KERN_ERR, target->scsi_host, - PFX "Got failed path rec status %d\n", status); + printk(KERN_ERR PFX "Got failed path rec status %d\n", status); else target->path = *pathrec; complete(&target->done); @@ -304,8 +303,7 @@ static int srp_lookup_path(struct srp_target_port *target) wait_for_completion(&target->done); if (target->status < 0) - shost_printk(KERN_WARNING, target->scsi_host, - PFX "Path record query failed\n"); + printk(KERN_WARNING PFX "Path record query failed\n"); return target->status; } @@ -381,10 +379,9 @@ static int srp_send_req(struct srp_target_port *target) * the second 8 bytes to the local node GUID. */ if (srp_target_is_topspin(target)) { - shost_printk(KERN_DEBUG, target->scsi_host, - PFX "Topspin/Cisco initiator port ID workaround " - "activated for target GUID %016llx\n", - (unsigned long long) be64_to_cpu(target->ioc_guid)); + printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround " + "activated for target GUID %016llx\n", + (unsigned long long) be64_to_cpu(target->ioc_guid)); memset(req->priv.initiator_port_id, 0, 8); memcpy(req->priv.initiator_port_id + 8, &target->srp_host->dev->dev->node_guid, 8); @@ -403,8 +400,7 @@ static void srp_disconnect_target(struct srp_target_port *target) init_completion(&target->done); if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { - shost_printk(KERN_DEBUG, target->scsi_host, - PFX "Sending CM DREQ failed\n"); + printk(KERN_DEBUG PFX "Sending CM DREQ failed\n"); return; } wait_for_completion(&target->done); @@ -572,8 +568,7 @@ static int srp_reconnect_target(struct srp_target_port *target) return ret; err: - shost_printk(KERN_ERR, target->scsi_host, - PFX "reconnect failed (%d), removing target port.\n", ret); + printk(KERN_ERR PFX "reconnect failed (%d), removing target port.\n", ret); /* * We couldn't reconnect, so kill our target port off. @@ -688,9 +683,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, if (scmnd->sc_data_direction != DMA_FROM_DEVICE && scmnd->sc_data_direction != DMA_TO_DEVICE) { - shost_printk(KERN_WARNING, target->scsi_host, - PFX "Unhandled data direction %d\n", - scmnd->sc_data_direction); + printk(KERN_WARNING PFX "Unhandled data direction %d\n", + scmnd->sc_data_direction); return -EINVAL; } @@ -792,9 +786,8 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) } else { scmnd = req->scmnd; if (!scmnd) - shost_printk(KERN_ERR, target->scsi_host, - "Null scmnd for RSP w/tag %016llx\n", - (unsigned long long) rsp->tag); + printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n", + (unsigned long long) rsp->tag); scmnd->result = rsp->status; if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { @@ -838,8 +831,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) if (0) { int i; - shost_printk(KERN_ERR, target->scsi_host, - PFX "recv completion, opcode 0x%02x\n", opcode); + printk(KERN_ERR PFX "recv completion, opcode 0x%02x\n", opcode); for (i = 0; i < wc->byte_len; ++i) { if (i % 8 == 0) @@ -860,13 +852,11 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) case SRP_T_LOGOUT: /* XXX Handle target logout */ - shost_printk(KERN_WARNING, target->scsi_host, - PFX "Got target logout request\n"); + printk(KERN_WARNING PFX "Got target logout request\n"); break; default: - shost_printk(KERN_WARNING, target->scsi_host, - PFX "Unhandled SRP opcode 0x%02x\n", opcode); + printk(KERN_WARNING PFX "Unhandled SRP opcode 0x%02x\n", opcode); break; } @@ -882,10 +872,9 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr) ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { - shost_printk(KERN_ERR, target->scsi_host, - PFX "failed %s status %d\n", - wc.wr_id & SRP_OP_RECV ? "receive" : "send", - wc.status); + printk(KERN_ERR PFX "failed %s status %d\n", + wc.wr_id & SRP_OP_RECV ? "receive" : "send", + wc.status); target->qp_in_error = 1; break; } @@ -941,18 +930,13 @@ static int srp_post_recv(struct srp_target_port *target) * req_lim and tx_head. Lock cannot be dropped between call here and * call to __srp_post_send(). */ -static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, - enum srp_request_type req_type) +static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target) { - s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2; - if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) return NULL; - if (target->req_lim < min) { + if (unlikely(target->req_lim < 1)) ++target->zero_req_lim; - return NULL; - } return target->tx_ring[target->tx_head & SRP_SQ_SIZE]; } @@ -1009,7 +993,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, return 0; } - iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL); + iu = __srp_get_tx_iu(target); if (!iu) goto err; @@ -1038,13 +1022,12 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, len = srp_map_data(scmnd, target, req); if (len < 0) { - shost_printk(KERN_ERR, target->scsi_host, - PFX "Failed to map data\n"); + printk(KERN_ERR PFX "Failed to map data\n"); goto err; } if (__srp_post_recv(target)) { - shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n"); + printk(KERN_ERR PFX "Recv failed\n"); goto err_unmap; } @@ -1052,7 +1035,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, DMA_TO_DEVICE); if (__srp_post_send(target, iu, len)) { - shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); + printk(KERN_ERR PFX "Send failed\n"); goto err_unmap; } @@ -1107,7 +1090,6 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event, struct srp_target_port *target) { - struct Scsi_Host *shost = target->scsi_host; struct ib_class_port_info *cpi; int opcode; @@ -1133,22 +1115,19 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id, memcpy(target->path.dgid.raw, event->param.rej_rcvd.ari, 16); - shost_printk(KERN_DEBUG, shost, - PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", - (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), - (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); + printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", + (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), + (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); target->status = SRP_PORT_REDIRECT; } else { - shost_printk(KERN_WARNING, shost, - " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); + printk(KERN_WARNING " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); target->status = -ECONNRESET; } break; case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: - shost_printk(KERN_WARNING, shost, - " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); + printk(KERN_WARNING " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); target->status = -ECONNRESET; break; @@ -1159,21 +1138,20 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id, u32 reason = be32_to_cpu(rej->reason); if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) - shost_printk(KERN_WARNING, shost, - PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); + printk(KERN_WARNING PFX + "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); else - shost_printk(KERN_WARNING, shost, - PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); + printk(KERN_WARNING PFX + "SRP LOGIN REJECTED, reason 0x%08x\n", reason); } else - shost_printk(KERN_WARNING, shost, - " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," - " opcode 0x%02x\n", opcode); + printk(KERN_WARNING " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," + " opcode 0x%02x\n", opcode); target->status = -ECONNRESET; break; default: - shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", - event->param.rej_rcvd.reason); + printk(KERN_WARNING " REJ reason 0x%x\n", + event->param.rej_rcvd.reason); target->status = -ECONNRESET; } } @@ -1188,8 +1166,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) switch (event->event) { case IB_CM_REQ_ERROR: - shost_printk(KERN_DEBUG, target->scsi_host, - PFX "Sending CM REQ failed\n"); + printk(KERN_DEBUG PFX "Sending CM REQ failed\n"); comp = 1; target->status = -ECONNRESET; break; @@ -1207,8 +1184,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) target->scsi_host->can_queue = min(target->req_lim, target->scsi_host->can_queue); } else { - shost_printk(KERN_WARNING, target->scsi_host, - PFX "Unhandled RSP opcode %#x\n", opcode); + printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode); target->status = -ECONNRESET; break; } @@ -1254,23 +1230,20 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) break; case IB_CM_REJ_RECEIVED: - shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); + printk(KERN_DEBUG PFX "REJ received\n"); comp = 1; srp_cm_rej_handler(cm_id, event, target); break; case IB_CM_DREQ_RECEIVED: - shost_printk(KERN_WARNING, target->scsi_host, - PFX "DREQ received - connection closed\n"); + printk(KERN_WARNING PFX "DREQ received - connection closed\n"); if (ib_send_cm_drep(cm_id, NULL, 0)) - shost_printk(KERN_ERR, target->scsi_host, - PFX "Sending CM DREP failed\n"); + printk(KERN_ERR PFX "Sending CM DREP failed\n"); break; case IB_CM_TIMEWAIT_EXIT: - shost_printk(KERN_ERR, target->scsi_host, - PFX "connection closed\n"); + printk(KERN_ERR PFX "connection closed\n"); comp = 1; target->status = 0; @@ -1282,8 +1255,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) break; default: - shost_printk(KERN_WARNING, target->scsi_host, - PFX "Unhandled CM event %d\n", event->event); + printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event); break; } @@ -1311,7 +1283,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, init_completion(&req->done); - iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT); + iu = __srp_get_tx_iu(target); if (!iu) goto out; @@ -1360,7 +1332,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) struct srp_request *req; int ret = SUCCESS; - shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); + printk(KERN_ERR "SRP abort called\n"); if (target->qp_in_error) return FAILED; @@ -1390,7 +1362,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_request *req, *tmp; - shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); + printk(KERN_ERR "SRP reset_device called\n"); if (target->qp_in_error) return FAILED; @@ -1417,7 +1389,7 @@ static int srp_reset_host(struct scsi_cmnd *scmnd) struct srp_target_port *target = host_to_target(scmnd->device->host); int ret = FAILED; - shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); + printk(KERN_ERR PFX "SRP reset_host called\n"); if (!srp_reconnect_target(target)) ret = SUCCESS; @@ -1571,7 +1543,6 @@ static struct scsi_host_template srp_template = { .this_id = -1, .cmd_per_lun = SRP_SQ_SIZE, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = srp_host_attrs }; @@ -1843,9 +1814,8 @@ static ssize_t srp_create_target(struct class_device *class_dev, ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid); - shost_printk(KERN_DEBUG, target->scsi_host, PFX - "new target: id_ext %016llx ioc_guid %016llx pkey %04x " - "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " + "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", (unsigned long long) be64_to_cpu(target->id_ext), (unsigned long long) be64_to_cpu(target->ioc_guid), be16_to_cpu(target->path.pkey), @@ -1872,8 +1842,7 @@ static ssize_t srp_create_target(struct class_device *class_dev, target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) { - shost_printk(KERN_ERR, target->scsi_host, - PFX "Connection failed\n"); + printk(KERN_ERR PFX "Connection failed\n"); goto err_cm_id; } diff --git a/trunk/drivers/infiniband/ulp/srp/ib_srp.h b/trunk/drivers/infiniband/ulp/srp/ib_srp.h index 4a3c1f37e4c2..e3573e7038c4 100644 --- a/trunk/drivers/infiniband/ulp/srp/ib_srp.h +++ b/trunk/drivers/infiniband/ulp/srp/ib_srp.h @@ -79,11 +79,6 @@ enum srp_target_state { SRP_TARGET_REMOVED }; -enum srp_request_type { - SRP_REQ_NORMAL, - SRP_REQ_TASK_MGMT, -}; - struct srp_device { struct list_head dev_list; struct ib_device *dev; diff --git a/trunk/drivers/lguest/x86/core.c b/trunk/drivers/lguest/x86/core.c index 96d0fd07c57d..482aec2a9631 100644 --- a/trunk/drivers/lguest/x86/core.c +++ b/trunk/drivers/lguest/x86/core.c @@ -459,7 +459,7 @@ void __init lguest_arch_host_init(void) /* We don't need the complexity of CPUs coming and going while we're * doing this. */ - get_online_cpus(); + lock_cpu_hotplug(); if (cpu_has_pge) { /* We have a broader idea of "global". */ /* Remember that this was originally set (for cleanup). */ cpu_had_pge = 1; @@ -469,20 +469,20 @@ void __init lguest_arch_host_init(void) /* Turn off the feature in the global feature set. */ clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); } - put_online_cpus(); + unlock_cpu_hotplug(); }; /*:*/ void __exit lguest_arch_host_fini(void) { /* If we had PGE before we started, turn it back on now. */ - get_online_cpus(); + lock_cpu_hotplug(); if (cpu_had_pge) { set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); /* adjust_pge's argument "1" means set PGE. */ on_each_cpu(adjust_pge, (void *)1, 0, 1); } - put_online_cpus(); + unlock_cpu_hotplug(); } diff --git a/trunk/drivers/media/Kconfig b/trunk/drivers/media/Kconfig index 8f4a45346de7..1604f0490404 100644 --- a/trunk/drivers/media/Kconfig +++ b/trunk/drivers/media/Kconfig @@ -69,13 +69,11 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate depends on I2C - select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE menuconfig VIDEO_TUNER_CUSTOMIZE bool "Customize analog tuner modules to build" @@ -91,13 +89,6 @@ menuconfig VIDEO_TUNER_CUSTOMIZE if VIDEO_TUNER_CUSTOMIZE -config TUNER_XC2028 - tristate "XCeive xc2028/xc3028 tuners" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the xc2028/xc3028 tuners. - config TUNER_MT20XX tristate "Microtune 2032 / 2050 tuners" depends on I2C @@ -106,10 +97,8 @@ config TUNER_MT20XX Say Y here to include support for the MT2032 / MT2050 tuner. config TUNER_TDA8290 - tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" + tristate "TDA 8290+8275(a) tuner combo" depends on I2C - select DVB_TDA827X - select DVB_TDA18271 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for Philips TDA8290+8275(a) tuner. @@ -131,19 +120,10 @@ config TUNER_TEA5767 config TUNER_SIMPLE tristate "Simple tuner support" depends on I2C - select TUNER_TDA9887 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for various simple tuners. -config TUNER_TDA9887 - tristate "TDA 9885/6/7 analog IF demodulator" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for Philips TDA9885/6/7 - analog IF demodulator. - endif # VIDEO_TUNER_CUSTOMIZE config VIDEOBUF_GEN diff --git a/trunk/drivers/media/common/Kconfig b/trunk/drivers/media/common/Kconfig index 06ca75911b7f..c5092ef1082f 100644 --- a/trunk/drivers/media/common/Kconfig +++ b/trunk/drivers/media/common/Kconfig @@ -1,6 +1,6 @@ config VIDEO_SAA7146 tristate - depends on I2C && PCI + depends on I2C config VIDEO_SAA7146_VV tristate diff --git a/trunk/drivers/media/common/ir-functions.c b/trunk/drivers/media/common/ir-functions.c index bb2a027b9483..e7c3ab951a44 100644 --- a/trunk/drivers/media/common/ir-functions.c +++ b/trunk/drivers/media/common/ir-functions.c @@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high) * saa7134 */ /* decode raw bit pattern to RC5 code */ -static u32 ir_rc5_decode(unsigned int code) +u32 ir_rc5_decode(unsigned int code) { unsigned int org_code = code; unsigned int pair; @@ -371,6 +371,7 @@ EXPORT_SYMBOL_GPL(ir_dump_samples); EXPORT_SYMBOL_GPL(ir_decode_biphase); EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); +EXPORT_SYMBOL_GPL(ir_rc5_decode); EXPORT_SYMBOL_GPL(ir_rc5_timer_end); EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup); diff --git a/trunk/drivers/media/common/ir-keymaps.c b/trunk/drivers/media/common/ir-keymaps.c index a4a937c90534..185e8a860c1a 100644 --- a/trunk/drivers/media/common/ir-keymaps.c +++ b/trunk/drivers/media/common/ir-keymaps.c @@ -1331,12 +1331,7 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 0x35 ] = KEY_FASTFORWARD, [ 0x36 ] = KEY_TV, [ 0x37 ] = KEY_RADIO, /* FM */ - [ 0x38 ] = KEY_DVD, - - [ 0x3e ] = KEY_F21, /* MCE +VOL, on Y04G0033 */ - [ 0x3a ] = KEY_F22, /* MCE -VOL, on Y04G0033 */ - [ 0x3b ] = KEY_F23, /* MCE +CH, on Y04G0033 */ - [ 0x3f ] = KEY_F24 /* MCE -CH, on Y04G0033 */ + [ 0x38 ] = KEY_DVD }; EXPORT_SYMBOL_GPL(ir_codes_winfast); @@ -1848,142 +1843,3 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); - -/* Pinnacle PCTV HD 800i mini remote */ -IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = { - - [0x0f] = KEY_1, - [0x15] = KEY_2, - [0x10] = KEY_3, - [0x18] = KEY_4, - [0x1b] = KEY_5, - [0x1e] = KEY_6, - [0x11] = KEY_7, - [0x21] = KEY_8, - [0x12] = KEY_9, - [0x27] = KEY_0, - - [0x24] = KEY_ZOOM, - [0x2a] = KEY_SUBTITLE, - - [0x00] = KEY_MUTE, - [0x01] = KEY_ENTER, /* Pinnacle Logo */ - [0x39] = KEY_POWER, - - [0x03] = KEY_VOLUMEUP, - [0x09] = KEY_VOLUMEDOWN, - [0x06] = KEY_CHANNELUP, - [0x0c] = KEY_CHANNELDOWN, - - [0x2d] = KEY_REWIND, - [0x30] = KEY_PLAYPAUSE, - [0x33] = KEY_FASTFORWARD, - [0x3c] = KEY_STOP, - [0x36] = KEY_RECORD, - [0x3f] = KEY_EPG, /* Labeled "?" */ -}; -EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd); - -/* - * Igor Kuznetsov - * Andrey J. Melnikov - * - * Keytable is used by BeholdTV 60x series, M6 series at - * least, and probably other cards too. - * The "ascii-art picture" below (in comments, first row - * is the keycode in hex, and subsequent row(s) shows - * the button labels (several variants when appropriate) - * helps to descide which keycodes to assign to the buttons. - */ -IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = { - - /* 0x1c 0x12 * - * TV/FM POWER * - * */ - [ 0x1c ] = KEY_TUNER, /*XXX KEY_TV KEY_RADIO */ - [ 0x12 ] = KEY_POWER, - - /* 0x01 0x02 0x03 * - * 1 2 3 * - * * - * 0x04 0x05 0x06 * - * 4 5 6 * - * * - * 0x07 0x08 0x09 * - * 7 8 9 * - * */ - [ 0x01 ] = KEY_1, - [ 0x02 ] = KEY_2, - [ 0x03 ] = KEY_3, - [ 0x04 ] = KEY_4, - [ 0x05 ] = KEY_5, - [ 0x06 ] = KEY_6, - [ 0x07 ] = KEY_7, - [ 0x08 ] = KEY_8, - [ 0x09 ] = KEY_9, - - /* 0x0a 0x00 0x17 * - * RECALL 0 MODE * - * */ - [ 0x0a ] = KEY_AGAIN, - [ 0x00 ] = KEY_0, - [ 0x17 ] = KEY_MODE, - - /* 0x14 0x10 * - * ASPECT FULLSCREEN * - * */ - [ 0x14 ] = KEY_SCREEN, - [ 0x10 ] = KEY_ZOOM, - - /* 0x0b * - * Up * - * * - * 0x18 0x16 0x0c * - * Left Ok Right * - * * - * 0x015 * - * Down * - * */ - [ 0x0b ] = KEY_CHANNELUP, /*XXX KEY_UP */ - [ 0x18 ] = KEY_VOLUMEDOWN, /*XXX KEY_LEFT */ - [ 0x16 ] = KEY_OK, /*XXX KEY_ENTER */ - [ 0x0c ] = KEY_VOLUMEUP, /*XXX KEY_RIGHT */ - [ 0x15 ] = KEY_CHANNELDOWN, /*XXX KEY_DOWN */ - - /* 0x11 0x0d * - * MUTE INFO * - * */ - [ 0x11 ] = KEY_MUTE, - [ 0x0d ] = KEY_INFO, - - /* 0x0f 0x1b 0x1a * - * RECORD PLAY/PAUSE STOP * - * * - * 0x0e 0x1f 0x1e * - *TELETEXT AUDIO SOURCE * - * RED YELLOW * - * */ - [ 0x0f ] = KEY_RECORD, - [ 0x1b ] = KEY_PLAYPAUSE, - [ 0x1a ] = KEY_STOP, - [ 0x0e ] = KEY_TEXT, - [ 0x1f ] = KEY_RED, /*XXX KEY_AUDIO */ - [ 0x1e ] = KEY_YELLOW, /*XXX KEY_SOURCE */ - - /* 0x1d 0x13 0x19 * - * SLEEP PREVIEW DVB * - * GREEN BLUE * - * */ - [ 0x1d ] = KEY_SLEEP, - [ 0x13 ] = KEY_GREEN, - [ 0x19 ] = KEY_BLUE, /*XXX KEY_SAT */ - - /* 0x58 0x5c * - * FREEZE SNAPSHOT * - * */ - [ 0x58 ] = KEY_SLOW, - [ 0x5c ] = KEY_SAVE, - -}; - -EXPORT_SYMBOL_GPL(ir_codes_behold); diff --git a/trunk/drivers/media/common/saa7146_fops.c b/trunk/drivers/media/common/saa7146_fops.c index f0703d8bc3e8..67d1b1b1b254 100644 --- a/trunk/drivers/media/common/saa7146_fops.c +++ b/trunk/drivers/media/common/saa7146_fops.c @@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + buf->vb.state = STATE_NEEDS_INIT; } @@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev, buf->activate(dev,buf,NULL); } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = VIDEOBUF_QUEUED; + buf->vb.state = STATE_QUEUED; DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); } return 0; @@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data) spin_lock_irqsave(&dev->slock,flags); if (q->curr) { DEB_D(("timeout on %p\n", q->curr)); - saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); + saa7146_buffer_finish(dev,q,STATE_ERROR); } /* we don't restart the transfer here like other drivers do. when @@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) } poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { + if (buf->state == STATE_DONE || buf->state == STATE_ERROR) { DEB_D(("poll succeeded!\n")); return POLLIN|POLLRDNORM; } @@ -538,7 +538,6 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); if (video_register_device(vfd, type, -1) < 0) { ERR(("cannot register v4l2 device. skipping.\n")); - video_device_release(vfd); return -1; } diff --git a/trunk/drivers/media/common/saa7146_vbi.c b/trunk/drivers/media/common/saa7146_vbi.c index c32dda973e92..6103484e4442 100644 --- a/trunk/drivers/media/common/saa7146_vbi.c +++ b/trunk/drivers/media/common/saa7146_vbi.c @@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev, struct saa7146_buf *next) { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); saa7146_set_vbi_capture(dev,buf,next); @@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (buf->vb.size != size) saa7146_dma_free(dev,q,buf); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (0 != err) return err; } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; return 0; @@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) saa7146_write(dev, MC1, MASK_20); if (vv->vbi_q.curr) { - saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); } videobuf_queue_cancel(&fh->vbi_q); @@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) /* this must be += 2, one count for each field */ vv->vbi_fieldcount+=2; vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; - saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); } else { DEB_VBI(("dev:%p\n",dev)); } diff --git a/trunk/drivers/media/common/saa7146_video.c b/trunk/drivers/media/common/saa7146_video.c index c31ab480d8e1..ae36d101006b 100644 --- a/trunk/drivers/media/common/saa7146_video.c +++ b/trunk/drivers/media/common/saa7146_video.c @@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev, { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; saa7146_set_capture(dev,buf,next); mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); @@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7146_dma_free(dev,q,buf); } - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { struct saa7146_format *sfmt; buf->vb.bytesperline = fh->video_fmt.bytesperline; @@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; return 0; @@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st) /* only finish the buffer if we have one... */ if( NULL != q->curr ) { - saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); + saa7146_buffer_finish(dev,q,STATE_DONE); } saa7146_buffer_next(dev,q,0); diff --git a/trunk/drivers/media/dvb/b2c2/flexcop.c b/trunk/drivers/media/dvb/b2c2/flexcop.c index 2ddafd071c97..29ec4183118e 100644 --- a/trunk/drivers/media/dvb/b2c2/flexcop.c +++ b/trunk/drivers/media/dvb/b2c2/flexcop.c @@ -212,6 +212,7 @@ void flexcop_reset_block_300(struct flexcop_device *fc) fc->write_ibi_reg(fc,ctrl_208,v208_save); } +EXPORT_SYMBOL(flexcop_reset_block_300); struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) { diff --git a/trunk/drivers/media/dvb/bt8xx/bt878.c b/trunk/drivers/media/dvb/bt8xx/bt878.c index c7bbb40223f5..85e36a1d6d78 100644 --- a/trunk/drivers/media/dvb/bt8xx/bt878.c +++ b/trunk/drivers/media/dvb/bt8xx/bt878.c @@ -378,37 +378,23 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet * EXPORT_SYMBOL(bt878_device_control); -#define BROOKTREE_878_DEVICE(vend, dev, name) \ - { \ - .vendor = PCI_VENDOR_ID_BROOKTREE, \ - .device = PCI_DEVICE_ID_BROOKTREE_878, \ - .subvendor = (vend), .subdevice = (dev), \ - .driver_data = (unsigned long) name \ - } -static struct pci_device_id bt878_pci_tbl[] __devinitdata = { - BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), - BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), - BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), - BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), - BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), - BROOKTREE_878_DEVICE(0x270f, 0xfc00, - "ChainTech digitop DST-1000 DVB-S"), - BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), - BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), - BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), - BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), - BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), - BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), - { } +static struct cards card_list[] __devinitdata = { + + { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, + { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, + { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, + { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, + { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, + { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, + { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, + { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, + { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, + { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, + { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" }, + { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" } }; -MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); - -static const char * __devinit card_name(const struct pci_device_id *id) -{ - return id->driver_data ? (const char *)id->driver_data : "Unknown"; -} /***********************/ /* PCI device handling */ @@ -417,13 +403,15 @@ static const char * __devinit card_name(const struct pci_device_id *id) static int __devinit bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { - int result = 0; + int result = 0, has_dvb = 0, i; unsigned char lat; struct bt878 *bt; #if defined(__powerpc__) unsigned int cmd; #endif unsigned int cardid; + unsigned short id; + struct cards *dvb_cards; printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", bt878_num); @@ -435,11 +423,25 @@ static int __devinit bt878_probe(struct pci_dev *dev, if (pci_enable_device(dev)) return -EIO; - cardid = dev->subsystem_device << 16; - cardid |= dev->subsystem_vendor; + pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id); + cardid = id << 16; + pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id); + cardid |= id; + + for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) { + if (cardid == dvb_cards->pci_id) { + printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n", + __func__, cardid, dvb_cards->name); + has_dvb = 1; + } + } - printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", - __func__, cardid, card_name(pci_id)); + if (!has_dvb) { + printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid); + result = -EINVAL; + + goto fail0; + } bt = &bt878[bt878_num]; bt->dev = dev; @@ -570,6 +572,14 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) return; } +static struct pci_device_id bt878_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); + static struct pci_driver bt878_pci_driver = { .name = "bt878", .id_table = bt878_pci_tbl, diff --git a/trunk/drivers/media/dvb/bt8xx/bt878.h b/trunk/drivers/media/dvb/bt8xx/bt878.h index 375fd2892a11..d593bc145628 100644 --- a/trunk/drivers/media/dvb/bt8xx/bt878.h +++ b/trunk/drivers/media/dvb/bt8xx/bt878.h @@ -101,6 +101,12 @@ #define BTTV_BOARD_DVICO_DVBT_LITE 0x80 #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 +struct cards { + __u32 pci_id; + __u16 card_id; + char *name; +}; + extern int bt878_num; struct bt878 { diff --git a/trunk/drivers/media/dvb/bt8xx/dst.c b/trunk/drivers/media/dvb/bt8xx/dst.c index 307ff35bdf13..b7a17e69ca4d 100644 --- a/trunk/drivers/media/dvb/bt8xx/dst.c +++ b/trunk/drivers/media/dvb/bt8xx/dst.c @@ -71,7 +71,6 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); } \ } while(0) -static int dst_command(struct dst_state *state, u8 *data, u8 len); static void dst_packsize(struct dst_state *state, int psize) { @@ -81,8 +80,7 @@ static void dst_packsize(struct dst_state *state, int psize) bt878_device_control(state->bt, DST_IG_TS, &bits); } -static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, - u32 outhigh, int delay) +int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay) { union dst_gpio_packet enb; union dst_gpio_packet bits; @@ -111,8 +109,9 @@ static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, return 0; } +EXPORT_SYMBOL(dst_gpio_outb); -static int dst_gpio_inb(struct dst_state *state, u8 *result) +int dst_gpio_inb(struct dst_state *state, u8 *result) { union dst_gpio_packet rd_packet; int err; @@ -126,6 +125,7 @@ static int dst_gpio_inb(struct dst_state *state, u8 *result) return 0; } +EXPORT_SYMBOL(dst_gpio_inb); int rdc_reset_state(struct dst_state *state) { @@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state) } EXPORT_SYMBOL(rdc_reset_state); -static int rdc_8820_reset(struct dst_state *state) +int rdc_8820_reset(struct dst_state *state) { dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { @@ -160,8 +160,9 @@ static int rdc_8820_reset(struct dst_state *state) return 0; } +EXPORT_SYMBOL(rdc_8820_reset); -static int dst_pio_enable(struct dst_state *state) +int dst_pio_enable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); @@ -171,6 +172,7 @@ static int dst_pio_enable(struct dst_state *state) return 0; } +EXPORT_SYMBOL(dst_pio_enable); int dst_pio_disable(struct dst_state *state) { @@ -609,7 +611,7 @@ static int dst_type_print(struct dst_state *state, u8 type) return 0; } -static struct tuner_types tuner_list[] = { +struct tuner_types tuner_list[] = { { .tuner_type = TUNER_TYPE_L64724, .tuner_name = "L 64724", @@ -1222,7 +1224,7 @@ static int dst_probe(struct dst_state *state) return 0; } -static int dst_command(struct dst_state *state, u8 *data, u8 len) +int dst_command(struct dst_state *state, u8 *data, u8 len) { u8 reply; @@ -1285,6 +1287,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len) return -EIO; } +EXPORT_SYMBOL(dst_command); static int dst_get_signal(struct dst_state *state) { diff --git a/trunk/drivers/media/dvb/bt8xx/dst_common.h b/trunk/drivers/media/dvb/bt8xx/dst_common.h index d88cf2add82b..87623d203a89 100644 --- a/trunk/drivers/media/dvb/bt8xx/dst_common.h +++ b/trunk/drivers/media/dvb/bt8xx/dst_common.h @@ -165,8 +165,10 @@ struct dst_config }; int rdc_reset_state(struct dst_state *state); +int rdc_8820_reset(struct dst_state *state); int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); +int dst_pio_enable(struct dst_state *state); int dst_pio_disable(struct dst_state *state); int dst_error_recovery(struct dst_state* state); int dst_error_bailout(struct dst_state *state); @@ -177,6 +179,9 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len); u8 dst_check_sum(u8 * buf, u32 len); struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); +int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay); + +int dst_command(struct dst_state* state, u8 * data, u8 len); #endif // DST_COMMON_H diff --git a/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c b/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c index 925cfa6221ad..445f02665577 100644 --- a/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/trunk/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1202,10 +1202,6 @@ void dvb_frontend_detach(struct dvb_frontend* fe) fe->ops.tuner_ops.release(fe); symbol_put_addr(fe->ops.tuner_ops.release); } - if (fe->ops.analog_ops.release) { - fe->ops.analog_ops.release(fe); - symbol_put_addr(fe->ops.analog_ops.release); - } ptr = (void*)fe->ops.release; if (ptr) { fe->ops.release(fe); @@ -1219,8 +1215,6 @@ void dvb_frontend_detach(struct dvb_frontend* fe) fe->ops.release_sec(fe); if (fe->ops.tuner_ops.release) fe->ops.tuner_ops.release(fe); - if (fe->ops.analog_ops.release) - fe->ops.analog_ops.release(fe); if (fe->ops.release) fe->ops.release(fe); } diff --git a/trunk/drivers/media/dvb/dvb-core/dvb_frontend.h b/trunk/drivers/media/dvb/dvb-core/dvb_frontend.h index aa4133f0bd19..a5262e852c82 100644 --- a/trunk/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/trunk/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -84,9 +84,6 @@ struct dvb_tuner_ops { /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); - /** This is to allow setting tuner-specific configs */ - int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); - int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); @@ -101,28 +98,6 @@ struct dvb_tuner_ops { int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); }; -struct analog_demod_info { - char *name; -}; - -struct analog_demod_ops { - - struct analog_demod_info info; - - void (*set_params)(struct dvb_frontend *fe, - struct analog_parameters *params); - int (*has_signal)(struct dvb_frontend *fe); - int (*is_stereo)(struct dvb_frontend *fe); - int (*get_afc)(struct dvb_frontend *fe); - void (*tuner_status)(struct dvb_frontend *fe); - void (*standby)(struct dvb_frontend *fe); - void (*release)(struct dvb_frontend *fe); - int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); - - /** This is to allow setting tuner-specific configuration */ - int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); -}; - struct dvb_frontend_ops { struct dvb_frontend_info info; @@ -168,7 +143,6 @@ struct dvb_frontend_ops { int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); struct dvb_tuner_ops tuner_ops; - struct analog_demod_ops analog_ops; }; #define MAX_EVENT 8 @@ -185,19 +159,18 @@ struct dvb_fe_events { struct dvb_frontend { struct dvb_frontend_ops ops; struct dvb_adapter *dvb; - void *demodulator_priv; - void *tuner_priv; - void *frontend_priv; - void *sec_priv; - void *analog_demod_priv; + void* demodulator_priv; + void* tuner_priv; + void* frontend_priv; + void* sec_priv; }; -extern int dvb_register_frontend(struct dvb_adapter *dvb, - struct dvb_frontend *fe); +extern int dvb_register_frontend(struct dvb_adapter* dvb, + struct dvb_frontend* fe); -extern int dvb_unregister_frontend(struct dvb_frontend *fe); +extern int dvb_unregister_frontend(struct dvb_frontend* fe); -extern void dvb_frontend_detach(struct dvb_frontend *fe); +extern void dvb_frontend_detach(struct dvb_frontend* fe); extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); diff --git a/trunk/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/trunk/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index ac9d93cf83c6..9878183ba3f0 100644 --- a/trunk/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/trunk/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -261,6 +261,11 @@ EXPORT_SYMBOL(dvb_ringbuffer_init); EXPORT_SYMBOL(dvb_ringbuffer_empty); EXPORT_SYMBOL(dvb_ringbuffer_free); EXPORT_SYMBOL(dvb_ringbuffer_avail); +EXPORT_SYMBOL(dvb_ringbuffer_flush); EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); +EXPORT_SYMBOL(dvb_ringbuffer_pkt_write); +EXPORT_SYMBOL(dvb_ringbuffer_pkt_read); +EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose); +EXPORT_SYMBOL(dvb_ringbuffer_pkt_next); diff --git a/trunk/drivers/media/dvb/dvb-usb/af9005.c b/trunk/drivers/media/dvb/dvb-usb/af9005.c index e7f76f515b4f..7db6eee50e39 100644 --- a/trunk/drivers/media/dvb/dvb-usb/af9005.c +++ b/trunk/drivers/media/dvb/dvb-usb/af9005.c @@ -1026,7 +1026,6 @@ static int af9005_usb_probe(struct usb_interface *intf, static struct usb_device_id af9005_usb_table[] = { {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, - {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)}, {0}, }; @@ -1076,7 +1075,7 @@ static struct dvb_usb_device_properties af9005_properties = { .rc_key_map_size = 0, .rc_query = af9005_rc_query, - .num_device_descs = 3, + .num_device_descs = 2, .devices = { {.name = "Afatech DVB-T USB1.1 stick", .cold_ids = {&af9005_usb_table[0], NULL}, @@ -1086,10 +1085,6 @@ static struct dvb_usb_device_properties af9005_properties = { .cold_ids = {&af9005_usb_table[1], NULL}, .warm_ids = {NULL}, }, - {.name = "Ansonic DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[2], NULL}, - .warm_ids = {NULL}, - }, {NULL}, } }; diff --git a/trunk/drivers/media/dvb/dvb-usb/au6610.c b/trunk/drivers/media/dvb/dvb-usb/au6610.c index f3ff81314696..18e0b16fb2a9 100644 --- a/trunk/drivers/media/dvb/dvb-usb/au6610.c +++ b/trunk/drivers/media/dvb/dvb-usb/au6610.c @@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (num > 2) - return -EINVAL; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; + if (num > 2) + return -EINVAL; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { diff --git a/trunk/drivers/media/dvb/dvb-usb/cxusb.c b/trunk/drivers/media/dvb/dvb-usb/cxusb.c index c58365005ac1..04e31cf7d530 100644 --- a/trunk/drivers/media/dvb/dvb-usb/cxusb.c +++ b/trunk/drivers/media/dvb/dvb-usb/cxusb.c @@ -15,7 +15,7 @@ * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) - * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) + * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au) * * 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 @@ -30,16 +30,11 @@ #include "mt352.h" #include "mt352_priv.h" #include "zl10353.h" -#include "tuner-xc2028.h" -#include "tuner-xc2028-types.h" /* debug */ -static int dvb_usb_cxusb_debug; +int dvb_usb_cxusb_debug; module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) -#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \ - dprintk(dvb_usb_cxusb_debug,0x01,args) static int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) @@ -51,9 +46,11 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d, sndbuf[0] = cmd; memcpy(&sndbuf[1], wbuf, wlen); if (wo) - return dvb_usb_generic_write(d, sndbuf, 1+wlen); + dvb_usb_generic_write(d, sndbuf, 1+wlen); else - return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); + dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); + + return 0; } /* GPIO */ @@ -75,34 +72,6 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) st->gpio_write_state[GPIO_TUNER] = onoff; } -static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, - u8 newval) -{ - u8 o[2], gpio_state; - int rc; - - o[0] = 0xff & ~changemask; /* mask of bits to keep */ - o[1] = newval & changemask; /* new values for bits */ - - rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); - if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) - deb_info("bluebird_gpio_write failed.\n"); - - return rc < 0 ? rc : gpio_state; -} - -static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) -{ - cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); - msleep(5); - cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); -} - -static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) -{ - cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); -} - /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -113,6 +82,9 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; + if (num > 2) + warn("more than two i2c messages at a time is not handled yet. TODO."); + for (i = 0; i < num; i++) { if (d->udev->descriptor.idVendor == USB_VID_MEDION) @@ -125,22 +97,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], break; } - if (msg[i].flags & I2C_M_RD) { - /* read only */ - u8 obuf[3], ibuf[1+msg[i].len]; - obuf[0] = 0; - obuf[1] = msg[i].len; - obuf[2] = msg[i].addr; - if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3, - ibuf, 1+msg[i].len) < 0) { - warn("i2c read failed"); - break; - } - memcpy(msg[i].buf, &ibuf[1], msg[i].len); - } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && - msg[i].addr == msg[i+1].addr) { - /* write to then read from same address */ + /* read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; obuf[0] = msg[i].len; obuf[1] = msg[i+1].len; @@ -158,8 +116,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); i++; - } else { - /* write only */ + } else { /* write */ u8 obuf[2+msg[i].len], ibuf; obuf[0] = msg[i].addr; obuf[1] = msg[i].len; @@ -174,7 +131,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } mutex_unlock(&d->i2c_mutex); - return i == num ? num : -EREMOTEIO; + return i; } static u32 cxusb_i2c_func(struct i2c_adapter *adapter) @@ -205,17 +162,6 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - int rc = 0; - - rc = cxusb_power_ctrl(d, onoff); - if (!onoff) - cxusb_nano2_led(d, 0); - - return rc; -} - static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[2] = { 0x03, 0x00 }; @@ -251,34 +197,6 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } -static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, - int *state) -{ - struct dvb_usb_rc_key *keymap = d->props.rc_key_map; - u8 ircode[4]; - int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; - - *event = 0; - *state = REMOTE_NO_KEY_PRESSED; - - if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) - return 0; - - for (i = 0; i < d->props.rc_key_map_size; i++) { - if (keymap[i].custom == ircode[1] && - keymap[i].data == ircode[2]) { - *event = keymap[i].event; - *state = REMOTE_KEY_PRESSED; - - return 0; - } - } - - return 0; -} - static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x02, KEY_TV }, { 0xfe, 0x0e, KEY_MP3 }, @@ -433,20 +351,6 @@ static struct mt352_config cxusb_mt352_config = { .demod_init = cxusb_mt352_demod_init, }; -static struct zl10353_config cxusb_zl10353_xc3028_config = { - .demod_address = 0x0f, - .if2 = 45600, - .no_tuner = 1, - .parallel_ts = 1, -}; - -static struct mt352_config cxusb_mt352_xc3028_config = { - .demod_address = 0x0f, - .if2 = 4560, - .no_tuner = 1, - .demod_init = cxusb_mt352_demod_init, -}; - /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -482,51 +386,6 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) -{ - struct dvb_usb_device *d = ptr; - - switch (command) { - case XC2028_TUNER_RESET: - deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg); - cxusb_bluebird_gpio_pulse(d, 0x01, 1); - break; - case XC2028_RESET_CLK: - deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg); - break; - default: - deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__, - command, arg); - return -EINVAL; - } - - return 0; -} - -static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &adap->dev->i2c_adap, - .i2c_addr = 0x61, - .video_dev = adap->dev, - .callback = dvico_bluebird_xc2028_callback, - }; - static struct xc2028_ctrl ctl = { - .fname = "xc3028-dvico-au-01.fw", - .max_len = 64, - .scode_table = ZARLINK456, - }; - - fe = dvb_attach(xc2028_attach, adap->fe, &cfg); - if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) - return -EIO; - - fe->ops.tuner_ops.set_config(fe, &ctl); - - return 0; -} - static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; @@ -588,120 +447,27 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) return -EIO; } -static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) -{ - u8 ircode[4]; - int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; - - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - /* reset the tuner and demodulator */ - cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); - cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - if ((adap->fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config, - &adap->dev->i2c_adap)) == NULL) - return -EIO; - - /* try to determine if there is no IR decoder on the I2C bus */ - for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) { - msleep(20); - if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) - goto no_IR; - if (ircode[0] == 0 && ircode[1] == 0) - continue; - if (ircode[2] + ircode[3] != 0xff) { -no_IR: - adap->dev->props.rc_key_map = NULL; - info("No IR receiver detected on this device."); - break; - } - } - - return 0; -} - -static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (usb_set_interface(adap->dev->udev, 0, 1) < 0) - err("set interface failed"); - - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - - /* reset the tuner and demodulator */ - cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); - cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); - cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - - if ((adap->fe = dvb_attach(zl10353_attach, - &cxusb_zl10353_xc3028_config, - &adap->dev->i2c_adap)) != NULL) - return 0; - - if ((adap->fe = dvb_attach(mt352_attach, - &cxusb_mt352_xc3028_config, - &adap->dev->i2c_adap)) != NULL) - return 0; - - return -EIO; -} - -/* - * DViCO has shipped two devices with the same USB ID, but only one of them - * needs a firmware download. Check the device class details to see if they - * have non-default values to decide whether the device is actually cold or - * not, and forget a match if it turns out we selected the wrong device. - */ -static int bluebird_fx2_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) -{ - int wascold = *cold; - - *cold = udev->descriptor.bDeviceClass == 0xff && - udev->descriptor.bDeviceSubClass == 0xff && - udev->descriptor.bDeviceProtocol == 0xff; - - if (*cold && !wascold) - *desc = NULL; - - return 0; -} - /* * DViCO bluebird firmware needs the "warm" product ID to be patched into the * firmware file before download. */ -static const int dvico_firmware_id_offsets[] = { 6638, 3204 }; +#define BLUEBIRD_01_ID_OFFSET 6638 static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw) { - int pos; - - for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) { - int idoff = dvico_firmware_id_offsets[pos]; + if (fw->size < BLUEBIRD_01_ID_OFFSET + 4) + return -EINVAL; - if (fw->size < idoff + 4) - continue; + if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) && + fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) { - if (fw->data[idoff] == (USB_VID_DVICO & 0xff) && - fw->data[idoff + 1] == USB_VID_DVICO >> 8) { - fw->data[idoff + 2] = - le16_to_cpu(udev->descriptor.idProduct) + 1; - fw->data[idoff + 3] = - le16_to_cpu(udev->descriptor.idProduct) >> 8; + fw->data[BLUEBIRD_01_ID_OFFSET + 2] = + le16_to_cpu(udev->descriptor.idProduct) + 1; + fw->data[BLUEBIRD_01_ID_OFFSET + 3] = + le16_to_cpu(udev->descriptor.idProduct) >> 8; - return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); - } + return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); } return -EINVAL; @@ -713,9 +479,6 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -724,10 +487,7 @@ static int cxusb_probe(struct usb_interface *intf, dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) { + dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) { return 0; } @@ -748,9 +508,6 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1009,151 +766,6 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { } }; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dualdig4_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc_interval = 100, - .rc_key_map = dvico_mce_rc_keys, - .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), - .rc_query = cxusb_bluebird2_rc_query, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T Dual Digital 4", - { NULL }, - { &cxusb_table[13], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = CYPRESS_FX2, - .identify_state = bluebird_fx2_identify_state, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_nano2_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_nano2_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc_interval = 100, - .rc_key_map = dvico_portable_rc_keys, - .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), - .rc_query = cxusb_bluebird2_rc_query, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2", - { NULL }, - { &cxusb_table[14], NULL }, - }, - } -}; - -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { - .caps = DVB_USB_IS_AN_I2C_ADAPTER, - - .usb_ctrl = DEVICE_SPECIFIC, - .firmware = "dvb-usb-bluebird-02.fw", - .download_firmware = bluebird_patch_dvico_firmware_download, - .identify_state = bluebird_fx2_identify_state, - - .size_of_priv = sizeof(struct cxusb_state), - - .num_adapters = 1, - .adapter = { - { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_nano2_frontend_attach, - .tuner_attach = cxusb_dvico_xc3028_tuner_attach, - /* parameter for the MPEG2-data transfer */ - .stream = { - .type = USB_BULK, - .count = 5, - .endpoint = 0x02, - .u = { - .bulk = { - .buffersize = 8192, - } - } - }, - }, - }, - - .power_ctrl = cxusb_nano2_power_ctrl, - - .i2c_algo = &cxusb_i2c_algo, - - .generic_bulk_ctrl_endpoint = 0x01, - - .rc_interval = 100, - .rc_key_map = dvico_portable_rc_keys, - .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), - .rc_query = cxusb_rc_query, - - .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", - { &cxusb_table[14], NULL }, - { &cxusb_table[15], NULL }, - }, - } -}; - static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/trunk/drivers/media/dvb/dvb-usb/cxusb.h b/trunk/drivers/media/dvb/dvb-usb/cxusb.h index 4768a2c35517..c8ef77554b00 100644 --- a/trunk/drivers/media/dvb/dvb-usb/cxusb.h +++ b/trunk/drivers/media/dvb/dvb-usb/cxusb.h @@ -4,9 +4,12 @@ #define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" -/* usb commands - some of it are guesses, don't have a reference yet */ -#define CMD_BLUEBIRD_GPIO_RW 0x05 +extern int dvb_usb_cxusb_debug; +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) +#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \ + dprintk(dvb_usb_cxusb_debug,0x01,args) +/* usb commands - some of it are guesses, don't have a reference yet */ #define CMD_I2C_WRITE 0x08 #define CMD_I2C_READ 0x09 diff --git a/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c b/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c index c9857d5c6982..3ea294eb96bd 100644 --- a/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/trunk/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) u8 b[4]; b[0] = REQUEST_ENABLE_VIDEO; - b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ + b[1] = 0x00; b[2] = (0x01 << 4); /* Master mode */ b[3] = 0x00; @@ -256,6 +256,9 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) b[2] |= st->channel_state; + if (st->channel_state) /* if at least one channel is active */ + b[1] = (0x01 << 4) | 0x00; + deb_info("data for streaming: %x %x\n",b[1],b[2]); return dib0700_ctrl_wr(adap->dev, b, 4); diff --git a/trunk/drivers/media/dvb/dvb-usb/dib0700_devices.c b/trunk/drivers/media/dvb/dvb-usb/dib0700_devices.c index e7093826e975..58452b52002c 100644 --- a/trunk/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/trunk/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -94,28 +94,12 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap) (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; } -static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) -{ - struct i2c_msg msg[2] = { - { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, - { .addr = 0x50, .flags = I2C_M_RD, .buf = pval, .len = 1 }, - }; - if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO; - return 0; -} - static int bristol_tuner_attach(struct dvb_usb_adapter *adap) { - struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; + struct dib0700_state *st = adap->dev->priv; struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - s8 a; - int if1=1220; - if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE && - adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) { - if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; - } - return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id], - if1) == NULL ? -ENODEV : 0; + return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id], + st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; } /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ @@ -246,27 +230,6 @@ static struct mt2266_config stk7700d_mt2266_config[2] = { } }; -static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) -{ - if (adap->id == 0) { - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); - dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config); - } - - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), - &stk7700d_dib7000p_mt2266_config[adap->id]); - - return adap->fe == NULL ? -ENODEV : 0; -} - static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) { if (adap->id == 0) { @@ -452,35 +415,6 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0x1e, 0x38, KEY_YELLOW }, { 0x1e, 0x3b, KEY_GOTO }, { 0x1e, 0x3d, KEY_POWER }, - - /* Key codes for the Leadtek Winfast DTV Dongle */ - { 0x00, 0x42, KEY_POWER }, - { 0x07, 0x7c, KEY_TUNER }, - { 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */ - { 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/ - { 0x0f, 0x71, KEY_DOT }, /* frequency */ - { 0x07, 0x43, KEY_0 }, - { 0x0c, 0x41, KEY_1 }, - { 0x04, 0x43, KEY_2 }, - { 0x0b, 0x7f, KEY_3 }, - { 0x0e, 0x41, KEY_4 }, - { 0x06, 0x43, KEY_5 }, - { 0x09, 0x7f, KEY_6 }, - { 0x0d, 0x7e, KEY_7 }, - { 0x05, 0x7c, KEY_8 }, - { 0x0a, 0x40, KEY_9 }, - { 0x0e, 0x4e, KEY_CLEAR }, - { 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */ - { 0x0f, 0x41, KEY_LAST }, /* recall */ - { 0x03, 0x42, KEY_MUTE }, - { 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/ - { 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */ - { 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */ - { 0x0b, 0x70, KEY_RECORD }, - { 0x03, 0x7d, KEY_VOLUMEUP }, - { 0x01, 0x7d, KEY_VOLUMEDOWN }, - { 0x02, 0x42, KEY_CHANNELUP }, - { 0x00, 0x7d, KEY_CHANNELDOWN }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ @@ -644,22 +578,16 @@ static struct mt2060_config stk7700p_mt2060_config = { static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) { - struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; struct dib0700_state *st = adap->dev->priv; struct i2c_adapter *tun_i2c; - s8 a; - int if1=1220; - if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE && - adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) { - if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; - } + if (st->is_dib7000pc) tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); else tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, - if1) == NULL ? -ENODEV : 0; + st->mt2060_if1[0]) == NULL ? -ENODEV : 0; } /* DIB7070 generic */ @@ -781,8 +709,6 @@ static struct dib7000p_config dib7070p_dib7000p_config = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -822,8 +748,6 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -836,8 +760,6 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, - .tuner_is_baseband = 1, - .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -899,12 +821,6 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, - { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, - { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, -/* 25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -946,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 8, + .num_device_descs = 7, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -975,10 +891,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "AVerMedia AVerTV DVB-T Express", { &dib0700_usb_id_table[20] }, { NULL }, - }, - { "Gigabyte U7000", - { &dib0700_usb_id_table[21], NULL }, - { NULL }, } }, @@ -1049,7 +961,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, - } + }, }, .rc_interval = DEFAULT_RC_INTERVAL, @@ -1057,25 +969,6 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - - .num_adapters = 1, - .adapter = { - { - .frontend_attach = stk7700P2_frontend_attach, - .tuner_attach = stk7700d_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - }, - }, - - .num_device_descs = 1, - .devices = { - { "ASUS My Cinema U3000 Mini DVBT Tuner", - { &dib0700_usb_id_table[23], NULL }, - { NULL }, - }, - } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 1, @@ -1090,7 +983,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 6, + .num_device_descs = 2, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -1100,29 +993,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[16], NULL }, { NULL }, }, - { "Artec T14BR DVB-T", - { &dib0700_usb_id_table[22], NULL }, - { NULL }, - }, - { "ASUS My Cinema U3100 Mini DVBT Tuner", - { &dib0700_usb_id_table[24], NULL }, - { NULL }, - }, - { "Hauppauge Nova-T Stick", - { &dib0700_usb_id_table[25], NULL }, - { NULL }, - }, - { "Hauppauge Nova-T MyTV.t", - { &dib0700_usb_id_table[26], NULL }, - { NULL }, - }, - }, - - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_key_map = dib0700_rc_keys, - .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), - .rc_query = dib0700_rc_query - + } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, @@ -1153,7 +1024,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Pinnacle PCTV Dual DVB-T Diversity Stick", { &dib0700_usb_id_table[18], NULL }, { NULL }, - } + }, } }, }; diff --git a/trunk/drivers/media/dvb/dvb-usb/digitv.c b/trunk/drivers/media/dvb/dvb-usb/digitv.c index 3acbda4aa27e..bca1e0905739 100644 --- a/trunk/drivers/media/dvb/dvb-usb/digitv.c +++ b/trunk/drivers/media/dvb/dvb-usb/digitv.c @@ -17,10 +17,9 @@ #include "nxt6000.h" /* debug */ -static int dvb_usb_digitv_debug; +int dvb_usb_digitv_debug; module_param_named(debug,dvb_usb_digitv_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); -#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) static int digitv_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) diff --git a/trunk/drivers/media/dvb/dvb-usb/digitv.h b/trunk/drivers/media/dvb/dvb-usb/digitv.h index 908c09f4966b..8b43e3db8691 100644 --- a/trunk/drivers/media/dvb/dvb-usb/digitv.h +++ b/trunk/drivers/media/dvb/dvb-usb/digitv.h @@ -8,6 +8,9 @@ struct digitv_state { int is_nxt6000; }; +extern int dvb_usb_digitv_debug; +#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) + /* protocol (from usblogging and the SDK: * * Always 7 bytes bulk message(s) for controlling diff --git a/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index aa4844ef875e..4fa3e895028a 100644 --- a/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/trunk/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -15,9 +15,7 @@ #define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 -#define USB_VID_ANSONIC 0x10b9 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd -#define USB_VID_ASUS 0x0b05 #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f @@ -46,16 +44,12 @@ #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 #define USB_VID_UNIWILL 0x1584 #define USB_VID_WIDEVIEW 0x14aa -/* dom : pour gigabyte u7000 */ -#define USB_VID_GIGABYTE 0x1044 - /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 #define USB_PID_ADSTECH_USB2_WARM 0xa334 #define USB_PID_AFATECH_AF9005 0x9020 #define USB_VID_ALINK_DTU 0xf170 -#define USB_PID_ANSONIC_DVBT_USB 0x6000 #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 @@ -75,7 +69,6 @@ #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 #define USB_PID_DIBCOM_STK7700D 0x1ef0 -#define USB_PID_DIBCOM_STK7700_U7000 0x7001 #define USB_PID_DIBCOM_STK7070P 0x1ebc #define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 @@ -106,7 +99,6 @@ #define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a #define USB_PID_ARTEC_T14_COLD 0x810b #define USB_PID_ARTEC_T14_WARM 0x810c -#define USB_PID_ARTEC_T14BR 0x810f #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 #define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e @@ -128,8 +120,6 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 -#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 -#define USB_PID_HAUPPAUGE_MYTV_T 0x7080 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 @@ -153,9 +143,6 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 -#define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 -#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 -#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 #define USB_PID_MEDION_MD95700 0x0932 @@ -183,9 +170,6 @@ #define USB_PID_OPERA1_WARM 0x3829 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 -/* dom pour gigabyte u7000 */ -#define USB_PID_GIGABYTE_U7000 0x7001 -#define USB_PID_ASUS_U3000 0x171f -#define USB_PID_ASUS_U3100 0x173f + #endif diff --git a/trunk/drivers/media/dvb/dvb-usb/gl861.c b/trunk/drivers/media/dvb/dvb-usb/gl861.c index 6b99d9f4d5b3..f01d99c1c43c 100644 --- a/trunk/drivers/media/dvb/dvb-usb/gl861.c +++ b/trunk/drivers/media/dvb/dvb-usb/gl861.c @@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (num > 2) - return -EINVAL; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; + if (num > 2) + return -EINVAL; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { diff --git a/trunk/drivers/media/dvb/dvb-usb/gp8psk.c b/trunk/drivers/media/dvb/dvb-usb/gp8psk.c index 83e8535014c6..92147ee3e14f 100644 --- a/trunk/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/trunk/drivers/media/dvb/dvb-usb/gp8psk.c @@ -171,6 +171,22 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } +int gp8psk_bcm4500_reload(struct dvb_usb_device *d) +{ + u8 buf; + int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + /* Turn On 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + /* load BCM4500 firmware */ + if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) + if (gp8psk_load_bcm4500fw(d)) + return EINVAL; + return 0; +} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { diff --git a/trunk/drivers/media/dvb/dvb-usb/gp8psk.h b/trunk/drivers/media/dvb/dvb-usb/gp8psk.h index e5cd8149c23d..e83a57506cfa 100644 --- a/trunk/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/trunk/drivers/media/dvb/dvb-usb/gp8psk.h @@ -92,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif diff --git a/trunk/drivers/media/dvb/dvb-usb/opera1.c b/trunk/drivers/media/dvb/dvb-usb/opera1.c index 21935bf7059e..d7c04951ceab 100644 --- a/trunk/drivers/media/dvb/dvb-usb/opera1.c +++ b/trunk/drivers/media/dvb/dvb-usb/opera1.c @@ -10,9 +10,7 @@ * see Documentation/dvb/README.dvb-usb for more information */ -#define DVB_USB_LOG_PREFIX "opera" - -#include "dvb-usb.h" +#include "opera1.h" #include "stv0299.h" #define OPERA_READ_MSG 0 @@ -40,7 +38,7 @@ struct opera_rc_keys { u32 event; }; -static int dvb_usb_opera1_debug; +int dvb_usb_opera1_debug; module_param_named(debug, dvb_usb_opera1_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." diff --git a/trunk/drivers/media/dvb/dvb-usb/opera1.h b/trunk/drivers/media/dvb/dvb-usb/opera1.h new file mode 100644 index 000000000000..53174427902d --- /dev/null +++ b/trunk/drivers/media/dvb/dvb-usb/opera1.h @@ -0,0 +1,9 @@ +#ifndef _OPERA1_H_ +#define _OPERA1_H_ + +#define DVB_USB_LOG_PREFIX "opera" +#include "dvb-usb.h" + +extern int dvb_usb_opera1_debug; +#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args) +#endif diff --git a/trunk/drivers/media/dvb/dvb-usb/vp702x.c b/trunk/drivers/media/dvb/dvb-usb/vp702x.c index e553c139ac44..16533b31a82d 100644 --- a/trunk/drivers/media/dvb/dvb-usb/vp702x.c +++ b/trunk/drivers/media/dvb/dvb-usb/vp702x.c @@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 return ret; } -static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, +int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { int ret; @@ -204,6 +204,19 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + struct vp702x_device_state *st = d->priv; + + if (st->power_state == 0 && onoff) + vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); + else if (st->power_state == 1 && onoff == 0) + vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); + + st->power_state = onoff; + + return 0; +} static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { diff --git a/trunk/drivers/media/dvb/dvb-usb/vp702x.h b/trunk/drivers/media/dvb/dvb-usb/vp702x.h index c2f97f96c21f..25a9dee4c824 100644 --- a/trunk/drivers/media/dvb/dvb-usb/vp702x.h +++ b/trunk/drivers/media/dvb/dvb-usb/vp702x.h @@ -102,5 +102,7 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff); #endif diff --git a/trunk/drivers/media/dvb/dvb-usb/vp7045.c b/trunk/drivers/media/dvb/dvb-usb/vp7045.c index c172babf59bb..5bbd2d5192f0 100644 --- a/trunk/drivers/media/dvb/dvb-usb/vp7045.c +++ b/trunk/drivers/media/dvb/dvb-usb/vp7045.c @@ -15,12 +15,9 @@ #include "vp7045.h" /* debug */ -static int dvb_usb_vp7045_debug; +int dvb_usb_vp7045_debug; module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); -#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) { diff --git a/trunk/drivers/media/dvb/dvb-usb/vp7045.h b/trunk/drivers/media/dvb/dvb-usb/vp7045.h index 969688f85267..9ce21a20fa86 100644 --- a/trunk/drivers/media/dvb/dvb-usb/vp7045.h +++ b/trunk/drivers/media/dvb/dvb-usb/vp7045.h @@ -17,6 +17,11 @@ #define DVB_USB_LOG_PREFIX "vp7045" #include "dvb-usb.h" +extern int dvb_usb_vp7045_debug; +#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) + /* vp7045 commands */ /* Twinhan Vendor requests */ diff --git a/trunk/drivers/media/dvb/frontends/Kconfig b/trunk/drivers/media/dvb/frontends/Kconfig index 9ad86ce4a4e5..59b9ed1f1aec 100644 --- a/trunk/drivers/media/dvb/frontends/Kconfig +++ b/trunk/drivers/media/dvb/frontends/Kconfig @@ -316,13 +316,6 @@ config DVB_TDA827X help A DVB-T silicon tuner module. Say Y when you want to support this tuner. -config DVB_TDA18271 - tristate "NXP TDA18271 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A silicon tuner module. Say Y when you want to support this tuner. - config DVB_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" depends on DVB_CORE && I2C @@ -360,15 +353,6 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called togther with a demodulator for now. -config DVB_TUNER_XC5000 - tristate "Xceive XC5000 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon tuner XC5000 from Xceive. - This device is only used inside a SiP called togther with a - demodulator for now. - comment "Miscellaneous devices" depends on DVB_CORE diff --git a/trunk/drivers/media/dvb/frontends/Makefile b/trunk/drivers/media/dvb/frontends/Makefile index 16bd107ebd32..4b8ad1f132aa 100644 --- a/trunk/drivers/media/dvb/frontends/Makefile +++ b/trunk/drivers/media/dvb/frontends/Makefile @@ -3,9 +3,6 @@ # EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/video/ - -tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o @@ -42,7 +39,6 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o -obj-$(CONFIG_DVB_TDA18271) += tda18271.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o @@ -50,4 +46,3 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o -obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o diff --git a/trunk/drivers/media/dvb/frontends/dib0070.c b/trunk/drivers/media/dvb/frontends/dib0070.c index fe895bf7b18f..481eaa684157 100644 --- a/trunk/drivers/media/dvb/frontends/dib0070.c +++ b/trunk/drivers/media/dvb/frontends/dib0070.c @@ -434,14 +434,9 @@ static u16 dib0070_p1f_defaults[] = 0, }; -static void dib0070_wbd_calibration(struct dvb_frontend *fe) +static void dib0070_wbd_calibration(struct dib0070_state *state) { u16 wbd_offs; - struct dib0070_state *state = fe->tuner_priv; - - if (state->cfg->sleep) - state->cfg->sleep(fe, 0); - dib0070_write_reg(state, 0x0f, 0x6d81); dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); msleep(9); @@ -449,10 +444,6 @@ static void dib0070_wbd_calibration(struct dvb_frontend *fe) dib0070_write_reg(state, 0x20, 0); state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); - - if (state->cfg->sleep) - state->cfg->sleep(fe, 1); - } u16 dib0070_wbd_offset(struct dvb_frontend *fe) @@ -569,7 +560,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter if (dib0070_reset(state) != 0) goto free_mem; - dib0070_wbd_calibration(fe); + dib0070_wbd_calibration(state); printk(KERN_INFO "DiB0070: successfully identified\n"); memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); diff --git a/trunk/drivers/media/dvb/frontends/dib3000mc.c b/trunk/drivers/media/dvb/frontends/dib3000mc.c index fa851601e7d4..edae0be063f5 100644 --- a/trunk/drivers/media/dvb/frontends/dib3000mc.c +++ b/trunk/drivers/media/dvb/frontends/dib3000mc.c @@ -684,9 +684,6 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; - int ret; - - dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); @@ -703,7 +700,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { - int i = 1000, found; + int i = 100, found; dib3000mc_autosearch_start(fe, fep); do { @@ -718,11 +715,10 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, dib3000mc_get_frontend(fe, fep); } - ret = dib3000mc_tune(fe, fep); - /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; + + return dib3000mc_tune(fe, fep); } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/trunk/drivers/media/dvb/frontends/dib7000m.c b/trunk/drivers/media/dvb/frontends/dib7000m.c index 5f1375e30dfc..fb18441a8c57 100644 --- a/trunk/drivers/media/dvb/frontends/dib7000m.c +++ b/trunk/drivers/media/dvb/frontends/dib7000m.c @@ -1171,9 +1171,7 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - int time, ret; - - dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); + int time; state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); @@ -1208,11 +1206,10 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, dib7000m_get_frontend(fe, fep); } - ret = dib7000m_tune(fe, fep); - /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; + + return dib7000m_tune(fe, fep); } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/trunk/drivers/media/dvb/frontends/dib7000p.c b/trunk/drivers/media/dvb/frontends/dib7000p.c index 47c23e29753e..f45bcfc51cf8 100644 --- a/trunk/drivers/media/dvb/frontends/dib7000p.c +++ b/trunk/drivers/media/dvb/frontends/dib7000p.c @@ -35,8 +35,8 @@ struct dib7000p_state { u16 wbd_ref; - u8 current_band; - u32 current_bandwidth; + u8 current_band; + fe_bandwidth_t current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; @@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe, fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); + fep->u.ofdm.bandwidth = state->current_bandwidth; switch ((tps >> 8) & 0x3) { case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; @@ -1128,11 +1128,12 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - int time, ret; + int time; - dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); + state->current_bandwidth = fep->u.ofdm.bandwidth; + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); - /* maybe the parameter has been changed */ + /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) @@ -1165,11 +1166,10 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, dib7000p_get_frontend(fe, fep); } - ret = dib7000p_tune(fe, fep); - /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - return ret; + + return dib7000p_tune(fe, fep); } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/trunk/drivers/media/dvb/frontends/dibx000_common.h b/trunk/drivers/media/dvb/frontends/dibx000_common.h index 84e4d5362922..5e17275afd25 100644 --- a/trunk/drivers/media/dvb/frontends/dibx000_common.h +++ b/trunk/drivers/media/dvb/frontends/dibx000_common.h @@ -128,11 +128,6 @@ enum dibx000_adc_states { (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) -#define BANDWIDTH_TO_INDEX(v) ( \ - (v) == 8000 ? BANDWIDTH_8_MHZ : \ - (v) == 7000 ? BANDWIDTH_7_MHZ : \ - (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ ) - /* Chip output mode. */ #define OUTMODE_HIGH_Z 0 #define OUTMODE_MPEG2_PAR_GATED_CLK 1 diff --git a/trunk/drivers/media/dvb/frontends/mt2266.c b/trunk/drivers/media/dvb/frontends/mt2266.c index 54b18f94b14b..03fe8265745f 100644 --- a/trunk/drivers/media/dvb/frontends/mt2266.c +++ b/trunk/drivers/media/dvb/frontends/mt2266.c @@ -38,12 +38,8 @@ struct mt2266_priv { u32 frequency; u32 bandwidth; - u8 band; }; -#define MT2266_VHF 1 -#define MT2266_UHF 0 - /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ static int debug; @@ -94,30 +90,26 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) } // Initialisation sequences -static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, - 0x00, 0x52, 0x99, 0x3f }; +static u8 mt2266_init1[] = { + REG_TUNE, + 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; static u8 mt2266_init2[] = { - 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, - 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, - 0xff, 0x00, 0x77, 0x0f, 0x2d -}; - -static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22 }; + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, + 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; -static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32 }; +static u8 mt2266_init_8mhz[] = { + REG_BANDWIDTH, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; -static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7 }; +static u8 mt2266_init_7mhz[] = { + REG_BANDWIDTH, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; -static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, - 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; - -static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, - 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; +static u8 mt2266_init_6mhz[] = { + REG_BANDWIDTH, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; #define FREF 30000 // Quartz oscillator 30 MHz @@ -130,78 +122,35 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame u8 lnaband; u8 b[10]; int i; - u8 band; priv = fe->tuner_priv; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); + freq = params->frequency / 1000; // Hz -> kHz - if (freq < 470000 && freq > 230000) - return -EINVAL; /* Gap between VHF and UHF bands */ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; priv->frequency = freq * 1000; - - tune = 2 * freq * (8192/16) / (FREF/16); - band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; - if (band == MT2266_VHF) - tune *= 2; - - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - mt2266_writeregs(priv, mt2266_init_6mhz, - sizeof(mt2266_init_6mhz)); - break; - case BANDWIDTH_7_MHZ: - mt2266_writeregs(priv, mt2266_init_7mhz, - sizeof(mt2266_init_7mhz)); - break; - case BANDWIDTH_8_MHZ: - default: - mt2266_writeregs(priv, mt2266_init_8mhz, - sizeof(mt2266_init_8mhz)); - break; - } - - if (band == MT2266_VHF && priv->band == MT2266_UHF) { - dprintk("Switch from UHF to VHF"); - mt2266_writereg(priv, 0x05, 0x04); - mt2266_writereg(priv, 0x19, 0x61); - mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); - } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { - dprintk("Switch from VHF to UHF"); - mt2266_writereg(priv, 0x05, 0x52); - mt2266_writereg(priv, 0x19, 0x61); - mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); - } - msleep(10); - - if (freq <= 495000) - lnaband = 0xEE; - else if (freq <= 525000) - lnaband = 0xDD; - else if (freq <= 550000) - lnaband = 0xCC; - else if (freq <= 580000) - lnaband = 0xBB; - else if (freq <= 605000) - lnaband = 0xAA; - else if (freq <= 630000) - lnaband = 0x99; - else if (freq <= 655000) - lnaband = 0x88; - else if (freq <= 685000) - lnaband = 0x77; - else if (freq <= 710000) - lnaband = 0x66; - else if (freq <= 735000) - lnaband = 0x55; - else if (freq <= 765000) - lnaband = 0x44; - else if (freq <= 802000) - lnaband = 0x33; - else if (freq <= 840000) - lnaband = 0x22; - else - lnaband = 0x11; + tune=2 * freq * (8192/16) / (FREF/16); + + if (freq <= 495000) lnaband = 0xEE; else + if (freq <= 525000) lnaband = 0xDD; else + if (freq <= 550000) lnaband = 0xCC; else + if (freq <= 580000) lnaband = 0xBB; else + if (freq <= 605000) lnaband = 0xAA; else + if (freq <= 630000) lnaband = 0x99; else + if (freq <= 655000) lnaband = 0x88; else + if (freq <= 685000) lnaband = 0x77; else + if (freq <= 710000) lnaband = 0x66; else + if (freq <= 735000) lnaband = 0x55; else + if (freq <= 765000) lnaband = 0x44; else + if (freq <= 802000) lnaband = 0x33; else + if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; + + msleep(100); + mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: + (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: + mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); b[0] = REG_TUNE; b[1] = (tune >> 8) & 0x1F; @@ -209,54 +158,47 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d %s", - (int) tune, (int) lnaband, - (band == MT2266_UHF) ? "UHF" : "VHF"); - dprintk("set_parms: [1..3]: %2x %2x %2x", - (int) b[1], (int) b[2], (int)b[3]); - - if (band == MT2266_UHF) { - b[0] = 0x05; - b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; - b[2] = lnaband; - mt2266_writeregs(priv, b, 3); - } + dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); + dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); + + b[0] = 0x05; + b[1] = 0x62; + b[2] = lnaband; + mt2266_writeregs(priv,b,3); - /* Wait for pll lock or timeout */ + //Waits for pll lock or timeout i = 0; do { mt2266_readreg(priv,REG_LOCK,b); - if (b[0] & 0x40) + if ((b[0] & 0x40)==0x40) break; msleep(10); i++; } while (i<10); dprintk("Lock when i=%i",(int)i); - - if (band == MT2266_UHF && priv->band == MT2266_VHF) - mt2266_writereg(priv, 0x05, 0x62); - - priv->band = band; - return ret; } static void mt2266_calibrate(struct mt2266_priv *priv) { - mt2266_writereg(priv, 0x11, 0x03); - mt2266_writereg(priv, 0x11, 0x01); - mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); - mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); - mt2266_writereg(priv, 0x33, 0x5e); - mt2266_writereg(priv, 0x10, 0x10); - mt2266_writereg(priv, 0x10, 0x00); - mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); + mt2266_writereg(priv,0x11,0x03); + mt2266_writereg(priv,0x11,0x01); + + mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); + mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); + + mt2266_writereg(priv,0x33,0x5e); + mt2266_writereg(priv,0x10,0x10); + mt2266_writereg(priv,0x10,0x00); + + mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + msleep(25); - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0x00); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); msleep(75); - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0xff); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); } static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) @@ -275,22 +217,17 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) static int mt2266_init(struct dvb_frontend *fe) { - int ret; struct mt2266_priv *priv = fe->tuner_priv; - ret = mt2266_writereg(priv, 0x17, 0x6d); - if (ret < 0) - return ret; - ret = mt2266_writereg(priv, 0x1c, 0xff); - if (ret < 0) - return ret; + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0xff); return 0; } static int mt2266_sleep(struct dvb_frontend *fe) { struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv, 0x17, 0x6d); - mt2266_writereg(priv, 0x1c, 0x00); + mt2266_writereg(priv,0x17,0x6d); + mt2266_writereg(priv,0x1c,0x00); return 0; } @@ -304,8 +241,8 @@ static int mt2266_release(struct dvb_frontend *fe) static const struct dvb_tuner_ops mt2266_tuner_ops = { .info = { .name = "Microtune MT2266", - .frequency_min = 174000000, - .frequency_max = 862000000, + .frequency_min = 470000000, + .frequency_max = 860000000, .frequency_step = 50000, }, .release = mt2266_release, @@ -327,9 +264,8 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter priv->cfg = cfg; priv->i2c = i2c; - priv->band = MT2266_UHF; - if (mt2266_readreg(priv, 0, &id)) { + if (mt2266_readreg(priv,0,&id) != 0) { kfree(priv); return NULL; } diff --git a/trunk/drivers/media/dvb/frontends/mt312.c b/trunk/drivers/media/dvb/frontends/mt312.c index 1638301fbd6e..0606b9a5b616 100644 --- a/trunk/drivers/media/dvb/frontends/mt312.c +++ b/trunk/drivers/media/dvb/frontends/mt312.c @@ -37,9 +37,9 @@ struct mt312_state { - struct i2c_adapter *i2c; + struct i2c_adapter* i2c; /* configuration settings */ - const struct mt312_config *config; + const struct mt312_config* config; struct dvb_frontend frontend; u8 id; @@ -49,15 +49,14 @@ struct mt312_state { static int debug; #define dprintk(args...) \ do { \ - if (debug) \ - printk(KERN_DEBUG "mt312: " args); \ + if (debug) printk(KERN_DEBUG "mt312: " args); \ } while (0) #define MT312_SYS_CLK 90000000UL /* 90 MHz */ #define MT312_LPOWER_SYS_CLK 60000000UL /* 60 MHz */ #define MT312_PLL_CLK 10000000UL /* 10 MHz */ -static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, +static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, void *buf, const size_t count) { int ret; @@ -80,7 +79,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, return -EREMOTEIO; } - if (debug) { + if(debug) { int i; dprintk("R(%d):", reg & 0x7f); for (i = 0; i < count; i++) @@ -91,14 +90,14 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, return 0; } -static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, +static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg, const void *src, const size_t count) { int ret; u8 buf[count + 1]; struct i2c_msg msg; - if (debug) { + if(debug) { int i; dprintk("W(%d):", reg & 0x7f); for (i = 0; i < count; i++) @@ -124,13 +123,13 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, return 0; } -static inline int mt312_readreg(struct mt312_state *state, +static inline int mt312_readreg(struct mt312_state* state, const enum mt312_reg_addr reg, u8 *val) { return mt312_read(state, reg, val, 1); } -static inline int mt312_writereg(struct mt312_state *state, +static inline int mt312_writereg(struct mt312_state* state, const enum mt312_reg_addr reg, const u8 val) { return mt312_write(state, reg, &val, 1); @@ -141,19 +140,18 @@ static inline u32 mt312_div(u32 a, u32 b) return (a + (b / 2)) / b; } -static int mt312_reset(struct mt312_state *state, const u8 full) +static int mt312_reset(struct mt312_state* state, const u8 full) { return mt312_writereg(state, RESET, full ? 0x80 : 0x40); } -static int mt312_get_inversion(struct mt312_state *state, +static int mt312_get_inversion(struct mt312_state* state, fe_spectral_inversion_t *i) { int ret; u8 vit_mode; - ret = mt312_readreg(state, VIT_MODE, &vit_mode); - if (ret < 0) + if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0) return ret; if (vit_mode & 0x80) /* auto inversion was used */ @@ -162,7 +160,7 @@ static int mt312_get_inversion(struct mt312_state *state, return 0; } -static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) +static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) { int ret; u8 sym_rate_h; @@ -171,44 +169,37 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) u16 monitor; u8 buf[2]; - ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h); - if (ret < 0) + if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0) return ret; - if (sym_rate_h & 0x80) { - /* symbol rate search was used */ - ret = mt312_writereg(state, MON_CTRL, 0x03); - if (ret < 0) + if (sym_rate_h & 0x80) { /* symbol rate search was used */ + if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0) return ret; - ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) return ret; monitor = (buf[0] << 8) | buf[1]; - dprintk("sr(auto) = %u\n", + dprintk(KERN_DEBUG "sr(auto) = %u\n", mt312_div(monitor * 15625, 4)); } else { - ret = mt312_writereg(state, MON_CTRL, 0x05); - if (ret < 0) + if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0) return ret; - ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) return ret; dec_ratio = ((buf[0] >> 5) & 0x07) * 32; - ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0) return ret; sym_rat_op = (buf[0] << 8) | buf[1]; - dprintk("sym_rat_op=%d dec_ratio=%d\n", + dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n", sym_rat_op, dec_ratio); - dprintk("*sr(manual) = %lu\n", + dprintk(KERN_DEBUG "*sr(manual) = %lu\n", (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * 2) - dec_ratio); } @@ -216,7 +207,7 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) return 0; } -static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) +static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) { const fe_code_rate_t fec_tab[8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, @@ -225,8 +216,7 @@ static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) int ret; u8 fec_status; - ret = mt312_readreg(state, FEC_STATUS, &fec_status); - if (ret < 0) + if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0) return ret; *cr = fec_tab[(fec_status >> 4) & 0x07]; @@ -234,72 +224,61 @@ static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) return 0; } -static int mt312_initfe(struct dvb_frontend *fe) +static int mt312_initfe(struct dvb_frontend* fe) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; /* wake up */ - ret = mt312_writereg(state, CONFIG, - (state->frequency == 60 ? 0x88 : 0x8c)); - if (ret < 0) + if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0) return ret; /* wait at least 150 usec */ udelay(150); /* full reset */ - ret = mt312_reset(state, 1); - if (ret < 0) + if ((ret = mt312_reset(state, 1)) < 0) return ret; -/* Per datasheet, write correct values. 09/28/03 ACCJr. - * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */ +// Per datasheet, write correct values. 09/28/03 ACCJr. +// If we don't do this, we won't get FE_HAS_VITERBI in the VP310. { - u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02, - 0x01, 0x00, 0x00, 0x00 }; + u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00}; - ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def)); - if (ret < 0) + if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0) return ret; } /* SYS_CLK */ - buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : - MT312_SYS_CLK) * 2, 1000000); + buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000); /* DISEQC_RATIO */ buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4); - ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0) return ret; - ret = mt312_writereg(state, SNR_THS_HIGH, 0x32); - if (ret < 0) + if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0) return ret; - ret = mt312_writereg(state, OP_CTRL, 0x53); - if (ret < 0) + if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0) return ret; /* TS_SW_LIM */ buf[0] = 0x8c; buf[1] = 0x98; - ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0) return ret; - ret = mt312_writereg(state, CS_SW_LIM, 0x69); - if (ret < 0) + if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0) return ret; return 0; } -static int mt312_send_master_cmd(struct dvb_frontend *fe, +static int mt312_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *c) { struct mt312_state *state = fe->demodulator_priv; @@ -309,31 +288,29 @@ static int mt312_send_master_cmd(struct dvb_frontend *fe, if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) return -EINVAL; - ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); - if (ret < 0) + if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) return ret; - ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len); - if (ret < 0) + if ((ret = + mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0) return ret; - ret = mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) - | 0x04); - if (ret < 0) + if ((ret = + mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) + | 0x04)) < 0) return ret; /* set DISEQC_MODE[2:0] to zero if a return message is expected */ - if (c->msg[0] & 0x02) { - ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40)); - if (ret < 0) + if (c->msg[0] & 0x02) + if ((ret = + mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0) return ret; - } return 0; } -static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) +static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) { struct mt312_state *state = fe->demodulator_priv; const u8 mini_tab[2] = { 0x02, 0x03 }; @@ -344,19 +321,18 @@ static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) if (c > SEC_MINI_B) return -EINVAL; - ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); - if (ret < 0) + if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) return ret; - ret = mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | mini_tab[c]); - if (ret < 0) + if ((ret = + mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | mini_tab[c])) < 0) return ret; return 0; } -static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) +static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) { struct mt312_state *state = fe->demodulator_priv; const u8 tone_tab[2] = { 0x01, 0x00 }; @@ -367,19 +343,18 @@ static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) if (t > SEC_TONE_OFF) return -EINVAL; - ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); - if (ret < 0) + if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) return ret; - ret = mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | tone_tab[t]); - if (ret < 0) + if ((ret = + mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | tone_tab[t])) < 0) return ret; return 0; } -static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) +static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) { struct mt312_state *state = fe->demodulator_priv; const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; @@ -390,7 +365,7 @@ static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) return mt312_writereg(state, DISEQC_MODE, volt_tab[v]); } -static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) +static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -398,12 +373,10 @@ static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) *s = 0; - ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status)); - if (ret < 0) + if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0) return ret; - dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," - " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); + dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); if (status[0] & 0xc0) *s |= FE_HAS_SIGNAL; /* signal noise ratio */ @@ -419,14 +392,13 @@ static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) return 0; } -static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber) +static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[3]; - ret = mt312_read(state, RS_BERCNT_H, buf, 3); - if (ret < 0) + if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0) return ret; *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; @@ -434,8 +406,7 @@ static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber) return 0; } -static int mt312_read_signal_strength(struct dvb_frontend *fe, - u16 *signal_strength) +static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -443,8 +414,7 @@ static int mt312_read_signal_strength(struct dvb_frontend *fe, u16 agc; s16 err_db; - ret = mt312_read(state, AGC_H, buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0) return ret; agc = (buf[0] << 6) | (buf[1] >> 2); @@ -452,19 +422,18 @@ static int mt312_read_signal_strength(struct dvb_frontend *fe, *signal_strength = agc; - dprintk("agc=%08x err_db=%hd\n", agc, err_db); + dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db); return 0; } -static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr) +static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; - ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0) return ret; *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); @@ -472,14 +441,13 @@ static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; } -static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) +static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; - ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0) return ret; *ubc = (buf[0] << 8) | buf[1]; @@ -487,7 +455,7 @@ static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) return 0; } -static int mt312_set_frontend(struct dvb_frontend *fe, +static int mt312_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct mt312_state *state = fe->demodulator_priv; @@ -523,28 +491,24 @@ static int mt312_set_frontend(struct dvb_frontend *fe, switch (state->id) { case ID_VP310: - /* For now we will do this only for the VP310. - * It should be better for the mt312 as well, - * but tuning will be slower. ACCJr 09/29/03 - */ + // For now we will do this only for the VP310. + // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03 ret = mt312_readreg(state, CONFIG, &config_val); if (ret < 0) return ret; - if (p->u.qpsk.symbol_rate >= 30000000) { - /* Note that 30MS/s should use 90MHz */ - if ((config_val & 0x0c) == 0x08) { - /* We are running 60MHz */ + if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz + { + if ((config_val & 0x0c) == 0x08) { //We are running 60MHz state->frequency = 90; - ret = mt312_initfe(fe); - if (ret < 0) + if ((ret = mt312_initfe(fe)) < 0) return ret; } - } else { - if ((config_val & 0x0c) == 0x0C) { - /* We are running 90MHz */ + } + else + { + if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz state->frequency = 60; - ret = mt312_initfe(fe); - if (ret < 0) + if ((ret = mt312_initfe(fe)) < 0) return ret; } } @@ -559,8 +523,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe, if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } /* sr = (u16)(sr * 256.0 / 1000000.0) */ @@ -582,8 +545,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe, /* GO */ buf[4] = 0x01; - ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf)); - if (ret < 0) + if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0) return ret; mt312_reset(state, 0); @@ -591,30 +553,27 @@ static int mt312_set_frontend(struct dvb_frontend *fe, return 0; } -static int mt312_get_frontend(struct dvb_frontend *fe, +static int mt312_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct mt312_state *state = fe->demodulator_priv; int ret; - ret = mt312_get_inversion(state, &p->inversion); - if (ret < 0) + if ((ret = mt312_get_inversion(state, &p->inversion)) < 0) return ret; - ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate); - if (ret < 0) + if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0) return ret; - ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner); - if (ret < 0) + if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0) return ret; return 0; } -static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) { - struct mt312_state *state = fe->demodulator_priv; + struct mt312_state* state = fe->demodulator_priv; if (enable) { return mt312_writereg(state, GPP_CTRL, 0x40); @@ -623,31 +582,27 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) } } -static int mt312_sleep(struct dvb_frontend *fe) +static int mt312_sleep(struct dvb_frontend* fe) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 config; /* reset all registers to defaults */ - ret = mt312_reset(state, 1); - if (ret < 0) + if ((ret = mt312_reset(state, 1)) < 0) return ret; - ret = mt312_readreg(state, CONFIG, &config); - if (ret < 0) + if ((ret = mt312_readreg(state, CONFIG, &config)) < 0) return ret; /* enter standby */ - ret = mt312_writereg(state, CONFIG, config & 0x7f); - if (ret < 0) + if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0) return ret; return 0; } -static int mt312_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *fesettings) +static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { fesettings->min_delay_ms = 50; fesettings->step_size = 0; @@ -655,9 +610,9 @@ static int mt312_get_tune_settings(struct dvb_frontend *fe, return 0; } -static void mt312_release(struct dvb_frontend *fe) +static void mt312_release(struct dvb_frontend* fe) { - struct mt312_state *state = fe->demodulator_priv; + struct mt312_state* state = fe->demodulator_priv; kfree(state); } @@ -700,10 +655,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = { .set_voltage = mt312_set_voltage, }; -struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, - struct i2c_adapter *i2c) +struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, + struct i2c_adapter* i2c) { - struct mt312_state *state = NULL; + struct mt312_state* state = NULL; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL); @@ -719,8 +674,7 @@ struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &vp310_mt312_ops, - sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; switch (state->id) { @@ -733,8 +687,7 @@ struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, state->frequency = 60; break; default: - printk(KERN_WARNING "Only Zarlink VP310/MT312" - " are supported chips.\n"); + printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n"); goto error; } @@ -744,7 +697,6 @@ struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, kfree(state); return NULL; } -EXPORT_SYMBOL(vp310_mt312_attach); module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); @@ -753,3 +705,4 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver"); MODULE_AUTHOR("Andreas Oberritter "); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(vp310_mt312_attach); diff --git a/trunk/drivers/media/dvb/frontends/mt312.h b/trunk/drivers/media/dvb/frontends/mt312.h index f17cb93ba9ba..cf9a1505ad4b 100644 --- a/trunk/drivers/media/dvb/frontends/mt312.h +++ b/trunk/drivers/media/dvb/frontends/mt312.h @@ -28,21 +28,22 @@ #include -struct mt312_config { +struct mt312_config +{ /* the demodulator's i2c address */ u8 demod_address; }; #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE)) -struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, - struct i2c_adapter *i2c); +struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, + struct i2c_adapter* i2c); #else -static inline struct dvb_frontend *vp310_mt312_attach( - const struct mt312_config *config, struct i2c_adapter *i2c) +static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, + struct i2c_adapter* i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif /* CONFIG_DVB_MT312 */ +#endif // CONFIG_DVB_MT312 -#endif /* MT312_H */ +#endif // MT312_H diff --git a/trunk/drivers/media/dvb/frontends/mt352.c b/trunk/drivers/media/dvb/frontends/mt352.c index 7cd190b6f015..5dd9b731f6f2 100644 --- a/trunk/drivers/media/dvb/frontends/mt352.c +++ b/trunk/drivers/media/dvb/frontends/mt352.c @@ -152,13 +152,7 @@ static void mt352_calc_input_freq(struct mt352_state* state, if (state->config.if2) if2 = state->config.if2; - if (adc_clock >= if2 * 2) - ife = if2; - else { - ife = adc_clock - (if2 % adc_clock); - if (ife > adc_clock / 2) - ife = adc_clock - ife; - } + ife = (2*adc_clock - if2); value = -16374 * ife / adc_clock; dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", __FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff); diff --git a/trunk/drivers/media/dvb/frontends/or51132.c b/trunk/drivers/media/dvb/frontends/or51132.c index 1d2d28ce823d..b314a1f2deed 100644 --- a/trunk/drivers/media/dvb/frontends/or51132.c +++ b/trunk/drivers/media/dvb/frontends/or51132.c @@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, /* Allocate memory for the internal state */ state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL); if (state == NULL) - return NULL; + goto error; /* Setup the state */ state->config = config; @@ -576,6 +576,10 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; + +error: + kfree(state); + return NULL; } static struct dvb_frontend_ops or51132_ops = { diff --git a/trunk/drivers/media/dvb/frontends/or51211.c b/trunk/drivers/media/dvb/frontends/or51211.c index 6a6b0d727c6f..f02bd9445955 100644 --- a/trunk/drivers/media/dvb/frontends/or51211.c +++ b/trunk/drivers/media/dvb/frontends/or51211.c @@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, /* Allocate memory for the internal state */ state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL); if (state == NULL) - return NULL; + goto error; /* Setup the state */ state->config = config; @@ -541,6 +541,10 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; + +error: + kfree(state); + return NULL; } static struct dvb_frontend_ops or51211_ops = { diff --git a/trunk/drivers/media/dvb/frontends/s5h1409.c b/trunk/drivers/media/dvb/frontends/s5h1409.c index 819433485d3b..562d9208857a 100644 --- a/trunk/drivers/media/dvb/frontends/s5h1409.c +++ b/trunk/drivers/media/dvb/frontends/s5h1409.c @@ -42,7 +42,6 @@ struct s5h1409_state { fe_modulation_t current_modulation; u32 current_frequency; - int if_freq; u32 is_qam_locked; u32 qam_state; @@ -98,7 +97,7 @@ static struct init_tab { { 0xac, 0x1003, }, { 0xad, 0x103f, }, { 0xe2, 0x0100, }, - { 0xe3, 0x1000, }, + { 0xe3, 0x0000, }, { 0x28, 0x1010, }, { 0xb1, 0x000e, }, }; @@ -349,32 +348,28 @@ static int s5h1409_softreset(struct dvb_frontend* fe) return 0; } -#define S5H1409_VSB_IF_FREQ 5380 -#define S5H1409_QAM_IF_FREQ state->config->qam_if - static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) { struct s5h1409_state* state = fe->demodulator_priv; + int ret = 0; dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); - switch (KHz) { - case 4000: - s5h1409_writereg(state, 0x87, 0x014b); - s5h1409_writereg(state, 0x88, 0x0cb5); - s5h1409_writereg(state, 0x89, 0x03e2); - break; - case 5380: - case 44000: - default: + if( (KHz == 44000) || (KHz == 5380) ) { s5h1409_writereg(state, 0x87, 0x01be); s5h1409_writereg(state, 0x88, 0x0436); s5h1409_writereg(state, 0x89, 0x054d); - break; + } else + if (KHz == 4000) { + s5h1409_writereg(state, 0x87, 0x014b); + s5h1409_writereg(state, 0x88, 0x0cb5); + s5h1409_writereg(state, 0x89, 0x03e2); + } else { + printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); + ret = -1; } - state->if_freq = KHz; - return 0; + return ret; } static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) @@ -399,15 +394,11 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, switch(m) { case VSB_8: dprintk("%s() VSB_8\n", __FUNCTION__); - if (state->if_freq != S5H1409_VSB_IF_FREQ) - s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ); s5h1409_writereg(state, 0xf4, 0); break; case QAM_64: case QAM_256: dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__); - if (state->if_freq != S5H1409_QAM_IF_FREQ) - s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); s5h1409_writereg(state, 0xf4, 1); s5h1409_writereg(state, 0x85, 0x110); break; @@ -441,11 +432,9 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) dprintk("%s(%d)\n", __FUNCTION__, enable); if (enable) - return s5h1409_writereg(state, 0xe3, - s5h1409_readreg(state, 0xe3) | 0x1100); + return s5h1409_writereg(state, 0xe3, 0x1100); else - return s5h1409_writereg(state, 0xe3, - s5h1409_readreg(state, 0xe3) & 0xeeff); + return s5h1409_writereg(state, 0xe3, 0x1000); } static int s5h1409_sleep(struct dvb_frontend* fe, int enable) @@ -515,15 +504,13 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) s5h1409_writereg(state, 0x96, 0x20); s5h1409_writereg(state, 0xad, ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) ); - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) & 0xeffe); + s5h1409_writereg(state, 0xab, 0x1100); } } else { if (state->qam_state != 1) { state->qam_state = 1; s5h1409_writereg(state, 0x96, 0x08); - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) | 0x1001); + s5h1409_writereg(state, 0xab, 0x1101); } } } @@ -560,36 +547,6 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, return 0; } -static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) -{ - struct s5h1409_state *state = fe->demodulator_priv; - u16 val; - - dprintk("%s(%d)\n", __FUNCTION__, mode); - - val = s5h1409_readreg(state, 0xac) & 0xcfff; - switch (mode) { - case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: - val |= 0x0000; - break; - case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: - dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode); - val |= 0x1000; - break; - case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: - val |= 0x2000; - break; - case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: - val |= 0x3000; - break; - default: - return -EINVAL; - } - - /* Configure MPEG Signal Timing charactistics */ - return s5h1409_writereg(state, 0xac, val); -} - /* Reset the demod hardware and reset all of the configuration registers to a default state. */ static int s5h1409_init (struct dvb_frontend* fe) @@ -609,16 +566,13 @@ static int s5h1409_init (struct dvb_frontend* fe) state->current_modulation = VSB_8; if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ + s5h1409_writereg(state, 0xab, 0x100); /* Serial */ else - s5h1409_writereg(state, 0xab, - s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ + s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ s5h1409_set_spectralinversion(fe, state->config->inversion); - s5h1409_set_if_freq(fe, state->if_freq); + s5h1409_set_if_freq(fe, state->config->if_freq); s5h1409_set_gpio(fe, state->config->gpio); - s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); s5h1409_softreset(fe); /* Note: Leaving the I2C gate closed. */ @@ -787,7 +741,6 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c) { struct s5h1409_state* state = NULL; - u16 reg; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); @@ -798,11 +751,9 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, state->config = config; state->i2c = i2c; state->current_modulation = 0; - state->if_freq = S5H1409_VSB_IF_FREQ; /* check if the demod exists */ - reg = s5h1409_readreg(state, 0x04); - if ((reg != 0x0066) && (reg != 0x007f)) + if (s5h1409_readreg(state, 0x04) != 0x0066) goto error; /* create dvb_frontend */ @@ -810,14 +761,8 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; - if (s5h1409_init(&state->frontend) != 0) { - printk(KERN_ERR "%s: Failed to initialize correctly\n", - __FUNCTION__); - goto error; - } - /* Note: Leaving the I2C gate open here. */ - s5h1409_i2c_gate_ctrl(&state->frontend, 1); + s5h1409_writereg(state, 0xf3, 1); return &state->frontend; diff --git a/trunk/drivers/media/dvb/frontends/s5h1409.h b/trunk/drivers/media/dvb/frontends/s5h1409.h index f0bb13fe808b..20f9af1af445 100644 --- a/trunk/drivers/media/dvb/frontends/s5h1409.h +++ b/trunk/drivers/media/dvb/frontends/s5h1409.h @@ -39,8 +39,8 @@ struct s5h1409_config #define S5H1409_GPIO_ON 1 u8 gpio; - /* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */ - u16 qam_if; + /* IF Freq in KHz */ + u16 if_freq; /* Spectral Inversion */ #define S5H1409_INVERSION_OFF 0 @@ -51,13 +51,6 @@ struct s5h1409_config #define S5H1409_TUNERLOCKING 0 #define S5H1409_DEMODLOCKING 1 u8 status_mode; - - /* MPEG signal timing */ -#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 -#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 -#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 -#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 - u16 mpeg_timing; }; #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) diff --git a/trunk/drivers/media/dvb/frontends/tda18271-common.c b/trunk/drivers/media/dvb/frontends/tda18271-common.c deleted file mode 100644 index cebb6b90b7e0..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda18271-common.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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 "tda18271-priv.h" - -static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - struct tda18271_priv *priv = fe->tuner_priv; - enum tda18271_i2c_gate gate; - int ret = 0; - - switch (priv->gate) { - case TDA18271_GATE_DIGITAL: - case TDA18271_GATE_ANALOG: - gate = priv->gate; - break; - case TDA18271_GATE_AUTO: - default: - switch (priv->mode) { - case TDA18271_DIGITAL: - gate = TDA18271_GATE_DIGITAL; - break; - case TDA18271_ANALOG: - default: - gate = TDA18271_GATE_ANALOG; - break; - } - } - - switch (gate) { - case TDA18271_GATE_ANALOG: - if (fe->ops.analog_ops.i2c_gate_ctrl) - ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); - break; - case TDA18271_GATE_DIGITAL: - if (fe->ops.i2c_gate_ctrl) - ret = fe->ops.i2c_gate_ctrl(fe, enable); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -}; - -/*---------------------------------------------------------------------*/ - -static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_reg("=== TDA18271 REG DUMP ===\n"); - tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); - tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); - tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); - tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); - tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); - tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); - tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); - tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); - tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); - tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); - tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); - tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); - tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); - tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); - tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); - tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); - - /* only dump extended regs if DBG_ADV is set */ - if (!(tda18271_debug & DBG_ADV)) - return; - - /* W indicates write-only registers. - * Register dump for write-only registers shows last value written. */ - - tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); - tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); - tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); - tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); - tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); - tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); - tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); - tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); - tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); - tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); - tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); - tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); - tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); - tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); - tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); - tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); - tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); - tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); - tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); - tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); - tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); - tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); - tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); -} - -int tda18271_read_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf = 0x00; - int ret; - struct i2c_msg msg[] = { - { .addr = priv->i2c_addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = regs, .len = 16 } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 0); - - return (ret == 2 ? 0 : ret); -} - -int tda18271_read_extended(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char regdump[TDA18271_NUM_REGS]; - unsigned char buf = 0x00; - int ret, i; - struct i2c_msg msg[] = { - { .addr = priv->i2c_addr, .flags = 0, - .buf = &buf, .len = 1 }, - { .addr = priv->i2c_addr, .flags = I2C_M_RD, - .buf = regdump, .len = TDA18271_NUM_REGS } - }; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* read all registers */ - ret = i2c_transfer(priv->i2c_adap, msg, 2); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 2) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - for (i = 0; i <= TDA18271_NUM_REGS; i++) { - /* don't update write-only registers */ - if ((i != R_EB9) && - (i != R_EB16) && - (i != R_EB17) && - (i != R_EB19) && - (i != R_EB20)) - regs[i] = regdump[i]; - } - - if (tda18271_debug & DBG_REG) - tda18271_dump_regs(fe, 1); - - return (ret == 2 ? 0 : ret); -} - -int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - unsigned char buf[TDA18271_NUM_REGS + 1]; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = len + 1 }; - int i, ret; - - BUG_ON((len == 0) || (idx + len > sizeof(buf))); - - buf[0] = idx; - for (i = 1; i <= len; i++) - buf[i] = regs[idx - 1 + i]; - - tda18271_i2c_gate_ctrl(fe, 1); - - /* write registers */ - ret = i2c_transfer(priv->i2c_adap, &msg, 1); - - tda18271_i2c_gate_ctrl(fe, 0); - - if (ret != 1) - tda_err("ERROR: i2c_transfer returned: %d\n", ret); - - return (ret == 1 ? 0 : ret); -} - -/*---------------------------------------------------------------------*/ - -int tda18271_init_regs(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_dbg("initializing registers for device @ %d-%04x\n", - i2c_adapter_id(priv->i2c_adap), priv->i2c_addr); - - /* initialize registers */ - switch (priv->id) { - case TDA18271HDC1: - regs[R_ID] = 0x83; - break; - case TDA18271HDC2: - regs[R_ID] = 0x84; - break; - }; - - regs[R_TM] = 0x08; - regs[R_PL] = 0x80; - regs[R_EP1] = 0xc6; - regs[R_EP2] = 0xdf; - regs[R_EP3] = 0x16; - regs[R_EP4] = 0x60; - regs[R_EP5] = 0x80; - regs[R_CPD] = 0x80; - regs[R_CD1] = 0x00; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0x00; - regs[R_MD1] = 0x00; - regs[R_MD2] = 0x00; - regs[R_MD3] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB1] = 0xff; - break; - case TDA18271HDC2: - regs[R_EB1] = 0xfc; - break; - }; - - regs[R_EB2] = 0x01; - regs[R_EB3] = 0x84; - regs[R_EB4] = 0x41; - regs[R_EB5] = 0x01; - regs[R_EB6] = 0x84; - regs[R_EB7] = 0x40; - regs[R_EB8] = 0x07; - regs[R_EB9] = 0x00; - regs[R_EB10] = 0x00; - regs[R_EB11] = 0x96; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB12] = 0x0f; - break; - case TDA18271HDC2: - regs[R_EB12] = 0x33; - break; - }; - - regs[R_EB13] = 0xc1; - regs[R_EB14] = 0x00; - regs[R_EB15] = 0x8f; - regs[R_EB16] = 0x00; - regs[R_EB17] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB18] = 0x00; - break; - case TDA18271HDC2: - regs[R_EB18] = 0x8c; - break; - }; - - regs[R_EB19] = 0x00; - regs[R_EB20] = 0x20; - - switch (priv->id) { - case TDA18271HDC1: - regs[R_EB21] = 0x33; - break; - case TDA18271HDC2: - regs[R_EB21] = 0xb3; - break; - }; - - regs[R_EB22] = 0x48; - regs[R_EB23] = 0xb0; - - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); - - /* setup agc1 gain */ - regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); - regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); - - /* setup agc2 gain */ - if ((priv->id) == TDA18271HDC1) { - regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - } - - /* image rejection calibration */ - - /* low-band */ - regs[R_EP3] = 0x1f; - regs[R_EP4] = 0x66; - regs[R_EP5] = 0x81; - regs[R_CPD] = 0xcc; - regs[R_CD1] = 0x6c; - regs[R_CD2] = 0x00; - regs[R_CD3] = 0x00; - regs[R_MPD] = 0xcd; - regs[R_MD1] = 0x77; - regs[R_MD2] = 0x08; - regs[R_MD3] = 0x00; - - switch (priv->id) { - case TDA18271HDC1: - tda18271_write_regs(fe, R_EP3, 11); - break; - case TDA18271HDC2: - tda18271_write_regs(fe, R_EP3, 12); - break; - }; - - if ((priv->id) == TDA18271HDC2) { - /* main pll cp source on */ - regs[R_EB4] = 0x61; - tda18271_write_regs(fe, R_EB4, 1); - msleep(1); - - /* main pll cp source off */ - regs[R_EB4] = 0x41; - tda18271_write_regs(fe, R_EB4, 1); - } - - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted low measurement */ - - regs[R_EP5] = 0x85; - regs[R_CPD] = 0xcb; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0x70; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image low optimization completion */ - - /* mid-band */ - regs[R_EP5] = 0x82; - regs[R_CPD] = 0xa8; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0xa9; - regs[R_MD1] = 0x73; - regs[R_MD2] = 0x1a; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted mid measurement */ - - regs[R_EP5] = 0x86; - regs[R_CPD] = 0xa8; - regs[R_CD1] = 0x66; - regs[R_CD2] = 0xa0; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image mid optimization completion */ - - /* high-band */ - regs[R_EP5] = 0x83; - regs[R_CPD] = 0x98; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x00; - regs[R_MPD] = 0x99; - regs[R_MD1] = 0x71; - regs[R_MD2] = 0xcd; - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* pll locking */ - - /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); - msleep(5); /* wanted high measurement */ - - regs[R_EP5] = 0x87; - regs[R_CD1] = 0x65; - regs[R_CD2] = 0x50; - - tda18271_write_regs(fe, R_EP3, 7); - msleep(5); /* pll locking */ - - /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); - msleep(30); /* image high optimization completion */ - - /* return to normal mode */ - regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); - - /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); - - return 0; -} - -/*---------------------------------------------------------------------*/ - -/* - * Standby modes, EP3 [7:5] - * - * | SM || SM_LT || SM_XT || mode description - * |=====\\=======\\=======\\=================================== - * | 0 || 0 || 0 || normal mode - * |-----||-------||-------||----------------------------------- - * | || || || standby mode w/ slave tuner output - * | 1 || 0 || 0 || & loop thru & xtal oscillator on - * |-----||-------||-------||----------------------------------- - * | 1 || 1 || 0 || standby mode w/ xtal oscillator on - * |-----||-------||-------||----------------------------------- - * | 1 || 1 || 1 || power off - * - */ - -int tda18271_set_standby_mode(struct dvb_frontend *fe, - int sm, int sm_lt, int sm_xt) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); - - regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ - regs[R_EP3] |= sm ? (1 << 7) : 0 | - sm_lt ? (1 << 6) : 0 | - sm_xt ? (1 << 5) : 0; - - tda18271_write_regs(fe, R_EP3, 1); - - return 0; -} - -/*---------------------------------------------------------------------*/ - -int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) -{ - /* sets main post divider & divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); - if (ret < 0) - goto fail; - - regs[R_MPD] = (0x77 & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_MD1] = 0x7f & (div >> 16); - regs[R_MD2] = 0xff & (div >> 8); - regs[R_MD3] = 0xff & div; -fail: - return ret; -} - -int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) -{ - /* sets cal post divider & divider bytes, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 d, pd; - u32 div; - - int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); - if (ret < 0) - goto fail; - - regs[R_CPD] = pd; - - div = ((d * (freq / 1000)) << 7) / 125; - - regs[R_CD1] = 0x7f & (div >> 16); - regs[R_CD2] = 0xff & (div >> 8); - regs[R_CD3] = 0xff & div; -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) -{ - /* sets bp filter bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP1] &= ~0x07; /* clear bp filter bits */ - regs[R_EP1] |= (0x07 & val); -fail: - return ret; -} - -int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) -{ - /* sets K & M bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EB13] &= ~0x7c; /* clear k & m bits */ - regs[R_EB13] |= (0x7c & val); -fail: - return ret; -} - -int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) -{ - /* sets rf band bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP2] &= ~0xe0; /* clear rf band bits */ - regs[R_EP2] |= (0xe0 & (val << 5)); -fail: - return ret; -} - -int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) -{ - /* sets gain taper bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ - regs[R_EP2] |= (0x1f & val); -fail: - return ret; -} - -int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) -{ - /* sets IR Meas bits, but does not write them */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); - if (ret < 0) - goto fail; - - regs[R_EP5] &= ~0x07; - regs[R_EP5] |= (0x07 & val); -fail: - return ret; -} - -int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) -{ - /* sets rf cal byte (RFC_Cprog), but does not write it */ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u8 val; - - tda18271_lookup_map(fe, RF_CAL, freq, &val); - - regs[R_EB14] = val; - - return 0; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/trunk/drivers/media/dvb/frontends/tda18271-fe.c b/trunk/drivers/media/dvb/frontends/tda18271-fe.c deleted file mode 100644 index dfe72aaec380..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda18271-fe.c +++ /dev/null @@ -1,1225 +0,0 @@ -/* - tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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 -#include -#include "tda18271-priv.h" - -int tda18271_debug; -module_param_named(debug, tda18271_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level " - "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); - -static int tda18271_cal_on_startup; -module_param_named(cal, tda18271_cal_on_startup, int, 0644); -MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); - -static LIST_HEAD(tda18271_list); -static DEFINE_MUTEX(tda18271_list_mutex); - -/*---------------------------------------------------------------------*/ - -static int tda18271_ir_cal_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - tda18271_read_regs(fe); - - /* test IR_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x08) == 0) - tda18271_init_regs(fe); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_channel_configuration(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std, - int radio) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u32 N; - - /* update TV broadcast parameters */ - - /* set standard */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - regs[R_EP3] |= std; - - /* set cal mode to normal */ - regs[R_EP4] &= ~0x03; - - /* update IF output level & IF notch frequency */ - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x80; /* IF notch = 0 */ - break; - case TDA18271_DIGITAL: - regs[R_EP4] |= 0x04; /* IF level = 1 */ - regs[R_MPD] |= 0x80; /* IF notch = 1 */ - break; - } - - if (radio) - regs[R_EP4] |= 0x80; - else - regs[R_EP4] &= ~0x80; - - /* update RF_TOP / IF_TOP */ - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_EB22] = 0x2c; - break; - case TDA18271_DIGITAL: - regs[R_EB22] = 0x37; - break; - } - tda18271_write_regs(fe, R_EB22, 1); - - /* --------------------------------------------------------------- */ - - /* disable Power Level Indicator */ - regs[R_EP1] |= 0x40; - - /* frequency dependent parameters */ - - tda18271_calc_ir_measure(fe, &freq); - - tda18271_calc_bp_filter(fe, &freq); - - tda18271_calc_rf_band(fe, &freq); - - tda18271_calc_gain_taper(fe, &freq); - - /* --------------------------------------------------------------- */ - - /* dual tuner and agc1 extra configuration */ - - /* main vco when Master, cal vco when slave */ - regs[R_EB1] |= 0x04; /* FIXME: assumes master */ - - /* agc1 always active */ - regs[R_EB1] &= ~0x02; - - /* agc1 has priority on agc2 */ - regs[R_EB1] &= ~0x01; - - tda18271_write_regs(fe, R_EB1, 1); - - /* --------------------------------------------------------------- */ - - N = freq + ifc; - - /* FIXME: assumes master */ - tda18271_calc_main_pll(fe, N); - tda18271_write_regs(fe, R_MPD, 4); - - tda18271_write_regs(fe, R_TM, 7); - - /* main pll charge pump source */ - regs[R_EB4] |= 0x20; - tda18271_write_regs(fe, R_EB4, 1); - - msleep(1); - - /* normal operation for the main pll */ - regs[R_EB4] &= ~0x20; - tda18271_write_regs(fe, R_EB4, 1); - - msleep(5); - - return 0; -} - -static int tda18271_read_thermometer(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int tm; - - /* switch thermometer on */ - regs[R_TM] |= 0x10; - tda18271_write_regs(fe, R_TM, 1); - - /* read thermometer info */ - tda18271_read_regs(fe); - - if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || - (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { - - if ((regs[R_TM] & 0x20) == 0x20) - regs[R_TM] &= ~0x20; - else - regs[R_TM] |= 0x20; - - tda18271_write_regs(fe, R_TM, 1); - - msleep(10); /* temperature sensing */ - - /* read thermometer info */ - tda18271_read_regs(fe); - } - - tm = tda18271_lookup_thermometer(fe); - - /* switch thermometer off */ - regs[R_TM] &= ~0x10; - tda18271_write_regs(fe, R_TM, 1); - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - tda18271_write_regs(fe, R_EP4, 1); - - return tm; -} - -static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe, - u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - unsigned char *regs = priv->tda18271_regs; - int tm_current, rfcal_comp, approx, i; - u8 dc_over_dt, rf_tab; - - /* power up */ - tda18271_set_standby_mode(fe, 0, 0, 0); - - /* read die current temperature */ - tm_current = tda18271_read_thermometer(fe); - - /* frequency dependent parameters */ - - tda18271_calc_rf_cal(fe, &freq); - rf_tab = regs[R_EB14]; - - i = tda18271_lookup_rf_band(fe, &freq, NULL); - if (i < 0) - return -EINVAL; - - if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { - approx = map[i].rf_a1 * - (freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab; - } else { - approx = map[i].rf_a2 * - (freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab; - } - - if (approx < 0) - approx = 0; - if (approx > 255) - approx = 255; - - tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); - - /* calculate temperature compensation */ - rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal); - - regs[R_EB14] = approx + rfcal_comp; - tda18271_write_regs(fe, R_EB14, 1); - - return 0; -} - -static int tda18271_por(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - /* power up detector 1 */ - regs[R_EB12] &= ~0x20; - tda18271_write_regs(fe, R_EB12, 1); - - regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ - - /* POR mode */ - tda18271_set_standby_mode(fe, 1, 0, 0); - - /* disable 1.5 MHz low pass filter */ - regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ - regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ - tda18271_write_regs(fe, R_EB21, 3); - - return 0; -} - -static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u32 N; - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - tda18271_write_regs(fe, R_EP4, 1); - - /* switch off agc1 */ - regs[R_EP3] |= 0x40; /* sm_lt = 1 */ - - regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - /* frequency dependent parameters */ - - tda18271_calc_bp_filter(fe, &freq); - tda18271_calc_gain_taper(fe, &freq); - tda18271_calc_rf_band(fe, &freq); - tda18271_calc_km(fe, &freq); - - tda18271_write_regs(fe, R_EP1, 3); - tda18271_write_regs(fe, R_EB13, 1); - - /* main pll charge pump source */ - regs[R_EB4] |= 0x20; - tda18271_write_regs(fe, R_EB4, 1); - - /* cal pll charge pump source */ - regs[R_EB7] |= 0x20; - tda18271_write_regs(fe, R_EB7, 1); - - /* force dcdc converter to 0 V */ - regs[R_EB14] = 0x00; - tda18271_write_regs(fe, R_EB14, 1); - - /* disable plls lock */ - regs[R_EB20] &= ~0x20; - tda18271_write_regs(fe, R_EB20, 1); - - /* set CAL mode to RF tracking filter calibration */ - regs[R_EP4] |= 0x03; - tda18271_write_regs(fe, R_EP4, 2); - - /* --------------------------------------------------------------- */ - - /* set the internal calibration signal */ - N = freq; - - tda18271_calc_main_pll(fe, N); - tda18271_write_regs(fe, R_MPD, 4); - - /* downconvert internal calibration */ - N += 1000000; - - tda18271_calc_main_pll(fe, N); - tda18271_write_regs(fe, R_MPD, 4); - - msleep(5); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - - /* --------------------------------------------------------------- */ - - /* normal operation for the main pll */ - regs[R_EB4] &= ~0x20; - tda18271_write_regs(fe, R_EB4, 1); - - /* normal operation for the cal pll */ - regs[R_EB7] &= ~0x20; - tda18271_write_regs(fe, R_EB7, 1); - - msleep(5); /* plls locking */ - - /* launch the rf tracking filters calibration */ - regs[R_EB20] |= 0x20; - tda18271_write_regs(fe, R_EB20, 1); - - msleep(60); /* calibration */ - - /* --------------------------------------------------------------- */ - - /* set CAL mode to normal */ - regs[R_EP4] &= ~0x03; - - /* switch on agc1 */ - regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ - - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - tda18271_write_regs(fe, R_EP3, 2); - - /* synchronization */ - tda18271_write_regs(fe, R_EP1, 1); - - /* get calibration result */ - tda18271_read_extended(fe); - - return regs[R_EB14]; -} - -static int tda18271_powerscan(struct dvb_frontend *fe, - u32 *freq_in, u32 *freq_out) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int sgn, bcal, count, wait; - u8 cid_target; - u16 count_limit; - u32 freq; - - freq = *freq_in; - - tda18271_calc_rf_band(fe, &freq); - tda18271_calc_rf_cal(fe, &freq); - tda18271_calc_gain_taper(fe, &freq); - tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EB14, 1); - - /* downconvert frequency */ - freq += 1000000; - - tda18271_calc_main_pll(fe, freq); - tda18271_write_regs(fe, R_MPD, 4); - - msleep(5); /* pll locking */ - - /* detection mode */ - regs[R_EP4] &= ~0x03; - regs[R_EP4] |= 0x01; - tda18271_write_regs(fe, R_EP4, 1); - - /* launch power detection measurement */ - tda18271_write_regs(fe, R_EP2, 1); - - /* read power detection info, stored in EB10 */ - tda18271_read_extended(fe); - - /* algorithm initialization */ - sgn = 1; - *freq_out = *freq_in; - bcal = 0; - count = 0; - wait = false; - - while ((regs[R_EB10] & 0x3f) < cid_target) { - /* downconvert updated freq to 1 MHz */ - freq = *freq_in + (sgn * count) + 1000000; - - tda18271_calc_main_pll(fe, freq); - tda18271_write_regs(fe, R_MPD, 4); - - if (wait) { - msleep(5); /* pll locking */ - wait = false; - } else - udelay(100); /* pll locking */ - - /* launch power detection measurement */ - tda18271_write_regs(fe, R_EP2, 1); - - /* read power detection info, stored in EB10 */ - tda18271_read_extended(fe); - - count += 200; - - if (count < count_limit) - continue; - - if (sgn <= 0) - break; - - sgn = -1 * sgn; - count = 200; - wait = true; - } - - if ((regs[R_EB10] & 0x3f) >= cid_target) { - bcal = 1; - *freq_out = freq - 1000000; - } else - bcal = 0; - - tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", - bcal, *freq_in, *freq_out, freq); - - return bcal; -} - -static int tda18271_powerscan_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - /* set standard to digital */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - regs[R_EP3] |= 0x12; - - /* set cal mode to normal */ - regs[R_EP4] &= ~0x03; - - /* update IF output level & IF notch frequency */ - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - - tda18271_write_regs(fe, R_EP3, 2); - - regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ - tda18271_write_regs(fe, R_EB18, 1); - - regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ - - /* 1.5 MHz low pass filter */ - regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ - regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ - - tda18271_write_regs(fe, R_EB21, 3); - - return 0; -} - -static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - unsigned char *regs = priv->tda18271_regs; - int bcal, rf, i; -#define RF1 0 -#define RF2 1 -#define RF3 2 - u32 rf_default[3]; - u32 rf_freq[3]; - u8 prog_cal[3]; - u8 prog_tab[3]; - - i = tda18271_lookup_rf_band(fe, &freq, NULL); - - if (i < 0) - return i; - - rf_default[RF1] = 1000 * map[i].rf1_def; - rf_default[RF2] = 1000 * map[i].rf2_def; - rf_default[RF3] = 1000 * map[i].rf3_def; - - for (rf = RF1; rf <= RF3; rf++) { - if (0 == rf_default[rf]) - return 0; - tda_cal("freq = %d, rf = %d\n", freq, rf); - - /* look for optimized calibration frequency */ - bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); - - tda18271_calc_rf_cal(fe, &rf_freq[rf]); - prog_tab[rf] = regs[R_EB14]; - - if (1 == bcal) - prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); - else - prog_cal[rf] = prog_tab[rf]; - - switch (rf) { - case RF1: - map[i].rf_a1 = 0; - map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1]; - map[i].rf1 = rf_freq[RF1] / 1000; - break; - case RF2: - map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] - - prog_cal[RF1] + prog_tab[RF1]) / - ((rf_freq[RF2] - rf_freq[RF1]) / 1000); - map[i].rf2 = rf_freq[RF2] / 1000; - break; - case RF3: - map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] - - prog_cal[RF2] + prog_tab[RF2]) / - ((rf_freq[RF3] - rf_freq[RF2]) / 1000); - map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2]; - map[i].rf3 = rf_freq[RF3] / 1000; - break; - default: - BUG(); - } - } - - return 0; -} - -static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned int i; - - tda_info("tda18271: performing RF tracking filter calibration\n"); - - /* wait for die temperature stabilization */ - msleep(200); - - tda18271_powerscan_init(fe); - - /* rf band calibration */ - for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) - tda18271_rf_tracking_filters_init(fe, 1000 * - priv->rf_cal_state[i].rfmax); - - priv->tm_rfcal = tda18271_read_thermometer(fe); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_rf_cal_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - - /* test RF_CAL_OK to see if we need init */ - if ((regs[R_EP1] & 0x10) == 0) - priv->cal_initialized = false; - - if (priv->cal_initialized) - return 0; - - tda18271_calc_rf_filter_curve(fe); - - tda18271_por(fe); - - tda_info("tda18271: RF tracking filter calibration complete\n"); - - priv->cal_initialized = true; - - return 0; -} - -static int tda18271_init(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - mutex_lock(&priv->lock); - - /* power up */ - tda18271_set_standby_mode(fe, 0, 0, 0); - - /* initialization */ - tda18271_ir_cal_init(fe); - - if (priv->id == TDA18271HDC2) - tda18271_rf_cal_init(fe); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int tda18271c2_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std, int radio) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - tda_dbg("freq = %d, ifc = %d\n", freq, ifc); - - tda18271_init(fe); - - mutex_lock(&priv->lock); - - tda18271_rf_tracking_filters_correction(fe, freq); - - tda18271_channel_configuration(fe, ifc, freq, bw, std, radio); - - mutex_unlock(&priv->lock); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271c1_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std, int radio) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - u32 N = 0; - - tda18271_init(fe); - - mutex_lock(&priv->lock); - - tda_dbg("freq = %d, ifc = %d\n", freq, ifc); - - /* RF tracking filter calibration */ - - /* calculate bp filter */ - tda18271_calc_bp_filter(fe, &freq); - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x60; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x60; - tda18271_write_regs(fe, R_EB7, 1); - - regs[R_EB14] = 0x00; - tda18271_write_regs(fe, R_EB14, 1); - - regs[R_EB20] = 0xcc; - tda18271_write_regs(fe, R_EB20, 1); - - /* set cal mode to RF tracking filter calibration */ - regs[R_EP4] |= 0x03; - - /* calculate cal pll */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 1250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2; - break; - } - - tda18271_calc_cal_pll(fe, N); - - /* calculate main pll */ - - switch (priv->mode) { - case TDA18271_ANALOG: - N = freq - 250000; - break; - case TDA18271_DIGITAL: - N = freq + bw / 2 + 1000000; - break; - } - - tda18271_calc_main_pll(fe, N); - - tda18271_write_regs(fe, R_EP3, 11); - msleep(5); /* RF tracking filter calibration initialization */ - - /* search for K,M,CO for RF calibration */ - tda18271_calc_km(fe, &freq); - tda18271_write_regs(fe, R_EB13, 1); - - /* search for rf band */ - tda18271_calc_rf_band(fe, &freq); - - /* search for gain taper */ - tda18271_calc_gain_taper(fe, &freq); - - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - tda18271_write_regs(fe, R_EP2, 1); - tda18271_write_regs(fe, R_EP1, 1); - - regs[R_EB4] &= 0x07; - regs[R_EB4] |= 0x40; - tda18271_write_regs(fe, R_EB4, 1); - - regs[R_EB7] = 0x40; - tda18271_write_regs(fe, R_EB7, 1); - msleep(10); - - regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); - msleep(60); /* RF tracking filter calibration completion */ - - regs[R_EP4] &= ~0x03; /* set cal mode to normal */ - tda18271_write_regs(fe, R_EP4, 1); - - tda18271_write_regs(fe, R_EP1, 1); - - /* RF tracking filter correction for VHF_Low band */ - if (0 == tda18271_calc_rf_cal(fe, &freq)) - tda18271_write_regs(fe, R_EB14, 1); - - /* Channel Configuration */ - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_EB22] = 0x2c; - break; - case TDA18271_DIGITAL: - regs[R_EB22] = 0x37; - break; - } - tda18271_write_regs(fe, R_EB22, 1); - - regs[R_EP1] |= 0x40; /* set dis power level on */ - - /* set standard */ - regs[R_EP3] &= ~0x1f; /* clear std bits */ - - /* see table 22 */ - regs[R_EP3] |= std; - - regs[R_EP4] &= ~0x03; /* set cal mode to normal */ - - regs[R_EP4] &= ~0x1c; /* clear if level bits */ - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x80; /* IF notch = 0 */ - break; - case TDA18271_DIGITAL: - regs[R_EP4] |= 0x04; - regs[R_MPD] |= 0x80; - break; - } - - if (radio) - regs[R_EP4] |= 0x80; - else - regs[R_EP4] &= ~0x80; - - /* image rejection validity */ - tda18271_calc_ir_measure(fe, &freq); - - /* calculate MAIN PLL */ - N = freq + ifc; - - tda18271_calc_main_pll(fe, N); - - tda18271_write_regs(fe, R_TM, 15); - msleep(5); - mutex_unlock(&priv->lock); - - return 0; -} - -static inline int tda18271_tune(struct dvb_frontend *fe, - u32 ifc, u32 freq, u32 bw, u8 std, int radio) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret = -EINVAL; - - switch (priv->id) { - case TDA18271HDC1: - ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio); - break; - case TDA18271HDC2: - ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio); - break; - } - return ret; -} - -/* ------------------------------------------------------------------ */ - -static int tda18271_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = &priv->std; - int ret; - u8 std; - u16 sgIF; - u32 bw, freq = params->frequency; - - priv->mode = TDA18271_DIGITAL; - - if (fe->ops.info.type == FE_ATSC) { - switch (params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - std = std_map->atsc_6.std_bits; - sgIF = std_map->atsc_6.if_freq; - break; - case QAM_64: - case QAM_256: - std = std_map->qam_6.std_bits; - sgIF = std_map->qam_6.if_freq; - break; - default: - tda_warn("modulation not set!\n"); - return -EINVAL; - } -#if 0 - /* userspace request is already center adjusted */ - freq += 1750000; /* Adjust to center (+1.75MHZ) */ -#endif - bw = 6000000; - } else if (fe->ops.info.type == FE_OFDM) { - switch (params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - bw = 6000000; - std = std_map->dvbt_6.std_bits; - sgIF = std_map->dvbt_6.if_freq; - break; - case BANDWIDTH_7_MHZ: - bw = 7000000; - std = std_map->dvbt_7.std_bits; - sgIF = std_map->dvbt_7.if_freq; - break; - case BANDWIDTH_8_MHZ: - bw = 8000000; - std = std_map->dvbt_8.std_bits; - sgIF = std_map->dvbt_8.if_freq; - break; - default: - tda_warn("bandwidth not set!\n"); - return -EINVAL; - } - } else { - tda_warn("modulation type not supported!\n"); - return -EINVAL; - } - - /* When tuning digital, the analog demod must be tri-stated */ - if (fe->ops.analog_ops.standby) - fe->ops.analog_ops.standby(fe); - - ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0); - - if (ret < 0) - goto fail; - - priv->frequency = freq; - priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? - params->u.ofdm.bandwidth : 0; -fail: - return ret; -} - -static int tda18271_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std_map = &priv->std; - char *mode; - int ret, radio = 0; - u8 std; - u16 sgIF; - u32 freq = params->frequency * 62500; - - priv->mode = TDA18271_ANALOG; - - if (params->mode == V4L2_TUNER_RADIO) { - radio = 1; - freq = freq / 1000; - std = std_map->fm_radio.std_bits; - sgIF = std_map->fm_radio.if_freq; - mode = "fm"; - } else if (params->std & V4L2_STD_MN) { - std = std_map->atv_mn.std_bits; - sgIF = std_map->atv_mn.if_freq; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - std = std_map->atv_b.std_bits; - sgIF = std_map->atv_b.if_freq; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - std = std_map->atv_gh.std_bits; - sgIF = std_map->atv_gh.if_freq; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - std = std_map->atv_i.std_bits; - sgIF = std_map->atv_i.if_freq; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - std = std_map->atv_dk.std_bits; - sgIF = std_map->atv_dk.if_freq; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - std = std_map->atv_l.std_bits; - sgIF = std_map->atv_l.if_freq; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - std = std_map->atv_lc.std_bits; - sgIF = std_map->atv_lc.if_freq; - mode = "L'"; - } else { - std = std_map->atv_i.std_bits; - sgIF = std_map->atv_i.if_freq; - mode = "xx"; - } - - tda_dbg("setting tda18271 to system %s\n", mode); - - ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio); - - if (ret < 0) - goto fail; - - priv->frequency = freq; - priv->bandwidth = 0; -fail: - return ret; -} - -static int tda18271_sleep(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - mutex_lock(&priv->lock); - - /* standby mode w/ slave tuner output - * & loop thru & xtal oscillator on */ - tda18271_set_standby_mode(fe, 1, 0, 0); - - mutex_unlock(&priv->lock); - - return 0; -} - -static int tda18271_release(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - - mutex_lock(&tda18271_list_mutex); - - priv->count--; - - if (!priv->count) { - tda_dbg("destroying instance @ %d-%04x\n", - i2c_adapter_id(priv->i2c_adap), - priv->i2c_addr); - list_del(&priv->tda18271_list); - - kfree(priv); - } - mutex_unlock(&tda18271_list_mutex); - - fe->tuner_priv = NULL; - - return 0; -} - -static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; -} - -static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) -{ - struct tda18271_priv *priv = fe->tuner_priv; - *bandwidth = priv->bandwidth; - return 0; -} - -/* ------------------------------------------------------------------ */ - -#define tda18271_update_std(std_cfg, name) do { \ - if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) { \ - tda_dbg("Using custom std config for %s\n", name); \ - memcpy(&std->std_cfg, &map->std_cfg, \ - sizeof(struct tda18271_std_map_item)); \ - } } while (0) - -#define tda18271_dump_std_item(std_cfg, name) do { \ - tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n", \ - name, std->std_cfg.if_freq, std->std_cfg.std_bits); \ - } while (0) - -static int tda18271_dump_std_map(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std = &priv->std; - - tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); - tda18271_dump_std_item(fm_radio, "fm"); - tda18271_dump_std_item(atv_b, "pal b"); - tda18271_dump_std_item(atv_dk, "pal dk"); - tda18271_dump_std_item(atv_gh, "pal gh"); - tda18271_dump_std_item(atv_i, "pal i"); - tda18271_dump_std_item(atv_l, "pal l"); - tda18271_dump_std_item(atv_lc, "pal l'"); - tda18271_dump_std_item(atv_mn, "atv mn"); - tda18271_dump_std_item(atsc_6, "atsc 6"); - tda18271_dump_std_item(dvbt_6, "dvbt 6"); - tda18271_dump_std_item(dvbt_7, "dvbt 7"); - tda18271_dump_std_item(dvbt_8, "dvbt 8"); - tda18271_dump_std_item(qam_6, "qam 6"); - tda18271_dump_std_item(qam_8, "qam 8"); - - return 0; -} - -static int tda18271_update_std_map(struct dvb_frontend *fe, - struct tda18271_std_map *map) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_std_map *std = &priv->std; - - if (!map) - return -EINVAL; - - tda18271_update_std(fm_radio, "fm"); - tda18271_update_std(atv_b, "atv b"); - tda18271_update_std(atv_dk, "atv dk"); - tda18271_update_std(atv_gh, "atv gh"); - tda18271_update_std(atv_i, "atv i"); - tda18271_update_std(atv_l, "atv l"); - tda18271_update_std(atv_lc, "atv l'"); - tda18271_update_std(atv_mn, "atv mn"); - tda18271_update_std(atsc_6, "atsc 6"); - tda18271_update_std(dvbt_6, "dvbt 6"); - tda18271_update_std(dvbt_7, "dvbt 7"); - tda18271_update_std(dvbt_8, "dvbt 8"); - tda18271_update_std(qam_6, "qam 6"); - tda18271_update_std(qam_8, "qam 8"); - - return 0; -} - -static int tda18271_get_id(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - char *name; - int ret = 0; - - mutex_lock(&priv->lock); - tda18271_read_regs(fe); - mutex_unlock(&priv->lock); - - switch (regs[R_ID] & 0x7f) { - case 3: - name = "TDA18271HD/C1"; - priv->id = TDA18271HDC1; - break; - case 4: - name = "TDA18271HD/C2"; - priv->id = TDA18271HDC2; - break; - default: - name = "Unknown device"; - ret = -EINVAL; - break; - } - - tda_info("%s detected @ %d-%04x%s\n", name, - i2c_adapter_id(priv->i2c_adap), priv->i2c_addr, - (0 == ret) ? "" : ", device not supported."); - - return ret; -} - -static struct dvb_tuner_ops tda18271_tuner_ops = { - .info = { - .name = "NXP TDA18271HD", - .frequency_min = 45000000, - .frequency_max = 864000000, - .frequency_step = 62500 - }, - .init = tda18271_init, - .sleep = tda18271_sleep, - .set_params = tda18271_set_params, - .set_analog_params = tda18271_set_analog_params, - .release = tda18271_release, - .get_frequency = tda18271_get_frequency, - .get_bandwidth = tda18271_get_bandwidth, -}; - -struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg) -{ - struct tda18271_priv *priv = NULL; - int state_found = 0; - - mutex_lock(&tda18271_list_mutex); - - list_for_each_entry(priv, &tda18271_list, tda18271_list) { - if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) && - (priv->i2c_addr == addr)) { - tda_dbg("attaching existing tuner @ %d-%04x\n", - i2c_adapter_id(priv->i2c_adap), - priv->i2c_addr); - priv->count++; - fe->tuner_priv = priv; - state_found = 1; - /* allow dvb driver to override i2c gate setting */ - if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG)) - priv->gate = cfg->gate; - break; - } - } - if (state_found == 0) { - tda_dbg("creating new tuner instance @ %d-%04x\n", - i2c_adapter_id(i2c), addr); - - priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); - if (priv == NULL) { - mutex_unlock(&tda18271_list_mutex); - return NULL; - } - - priv->i2c_addr = addr; - priv->i2c_adap = i2c; - priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; - priv->cal_initialized = false; - mutex_init(&priv->lock); - priv->count++; - - fe->tuner_priv = priv; - - list_add_tail(&priv->tda18271_list, &tda18271_list); - - if (tda18271_get_id(fe) < 0) - goto fail; - - if (tda18271_assign_map_layout(fe) < 0) - goto fail; - - mutex_lock(&priv->lock); - tda18271_init_regs(fe); - - if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2)) - tda18271_rf_cal_init(fe); - - mutex_unlock(&priv->lock); - } - - /* override default std map with values in config struct */ - if ((cfg) && (cfg->std_map)) - tda18271_update_std_map(fe, cfg->std_map); - - mutex_unlock(&tda18271_list_mutex); - - memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if (tda18271_debug & DBG_MAP) - tda18271_dump_std_map(fe); - - return fe; -fail: - mutex_unlock(&tda18271_list_mutex); - - tda18271_release(fe); - return NULL; -} -EXPORT_SYMBOL_GPL(tda18271_attach); -MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); -MODULE_AUTHOR("Michael Krufky "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.2"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/trunk/drivers/media/dvb/frontends/tda18271-priv.h b/trunk/drivers/media/dvb/frontends/tda18271-priv.h deleted file mode 100644 index 7b939a5325fb..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda18271-priv.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - tda18271-priv.h - private header for the NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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 __TDA18271_PRIV_H__ -#define __TDA18271_PRIV_H__ - -#include -#include -#include -#include "tda18271.h" - -#define R_ID 0x00 /* ID byte */ -#define R_TM 0x01 /* Thermo byte */ -#define R_PL 0x02 /* Power level byte */ -#define R_EP1 0x03 /* Easy Prog byte 1 */ -#define R_EP2 0x04 /* Easy Prog byte 2 */ -#define R_EP3 0x05 /* Easy Prog byte 3 */ -#define R_EP4 0x06 /* Easy Prog byte 4 */ -#define R_EP5 0x07 /* Easy Prog byte 5 */ -#define R_CPD 0x08 /* Cal Post-Divider byte */ -#define R_CD1 0x09 /* Cal Divider byte 1 */ -#define R_CD2 0x0a /* Cal Divider byte 2 */ -#define R_CD3 0x0b /* Cal Divider byte 3 */ -#define R_MPD 0x0c /* Main Post-Divider byte */ -#define R_MD1 0x0d /* Main Divider byte 1 */ -#define R_MD2 0x0e /* Main Divider byte 2 */ -#define R_MD3 0x0f /* Main Divider byte 3 */ -#define R_EB1 0x10 /* Extended byte 1 */ -#define R_EB2 0x11 /* Extended byte 2 */ -#define R_EB3 0x12 /* Extended byte 3 */ -#define R_EB4 0x13 /* Extended byte 4 */ -#define R_EB5 0x14 /* Extended byte 5 */ -#define R_EB6 0x15 /* Extended byte 6 */ -#define R_EB7 0x16 /* Extended byte 7 */ -#define R_EB8 0x17 /* Extended byte 8 */ -#define R_EB9 0x18 /* Extended byte 9 */ -#define R_EB10 0x19 /* Extended byte 10 */ -#define R_EB11 0x1a /* Extended byte 11 */ -#define R_EB12 0x1b /* Extended byte 12 */ -#define R_EB13 0x1c /* Extended byte 13 */ -#define R_EB14 0x1d /* Extended byte 14 */ -#define R_EB15 0x1e /* Extended byte 15 */ -#define R_EB16 0x1f /* Extended byte 16 */ -#define R_EB17 0x20 /* Extended byte 17 */ -#define R_EB18 0x21 /* Extended byte 18 */ -#define R_EB19 0x22 /* Extended byte 19 */ -#define R_EB20 0x23 /* Extended byte 20 */ -#define R_EB21 0x24 /* Extended byte 21 */ -#define R_EB22 0x25 /* Extended byte 22 */ -#define R_EB23 0x26 /* Extended byte 23 */ - -#define TDA18271_NUM_REGS 39 - -/*---------------------------------------------------------------------*/ - -struct tda18271_rf_tracking_filter_cal { - u32 rfmax; - u8 rfband; - u32 rf1_def; - u32 rf2_def; - u32 rf3_def; - u32 rf1; - u32 rf2; - u32 rf3; - int rf_a1; - int rf_b1; - int rf_a2; - int rf_b2; -}; - -enum tda18271_mode { - TDA18271_ANALOG, - TDA18271_DIGITAL, -}; - -struct tda18271_map_layout; - -enum tda18271_ver { - TDA18271HDC1, - TDA18271HDC2, -}; - -struct tda18271_priv { - u8 i2c_addr; - struct i2c_adapter *i2c_adap; - unsigned char tda18271_regs[TDA18271_NUM_REGS]; - - struct list_head tda18271_list; - - enum tda18271_mode mode; - enum tda18271_i2c_gate gate; - enum tda18271_ver id; - - unsigned int count; - unsigned int tm_rfcal; - unsigned int cal_initialized:1; - - struct tda18271_map_layout *maps; - struct tda18271_std_map std; - struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; - - struct mutex lock; - - u32 frequency; - u32 bandwidth; -}; - -/*---------------------------------------------------------------------*/ - -extern int tda18271_debug; - -#define DBG_INFO 1 -#define DBG_MAP 2 -#define DBG_REG 4 -#define DBG_ADV 8 -#define DBG_CAL 16 - -#define tda_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt, __FUNCTION__, ##arg) - -#define dprintk(kern, lvl, fmt, arg...) do {\ - if (tda18271_debug & lvl) \ - tda_printk(kern, fmt, ##arg); } while (0) - -#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) -#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg) -#define tda_err(fmt, arg...) tda_printk(KERN_ERR, fmt, ##arg) -#define tda_dbg(fmt, arg...) dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg) -#define tda_map(fmt, arg...) dprintk(KERN_DEBUG, DBG_MAP, fmt, ##arg) -#define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg) -#define tda_cal(fmt, arg...) dprintk(KERN_DEBUG, DBG_CAL, fmt, ##arg) - -/*---------------------------------------------------------------------*/ - -enum tda18271_map_type { - /* tda18271_pll_map */ - MAIN_PLL, - CAL_PLL, - /* tda18271_map */ - RF_CAL, - RF_CAL_KMCO, - RF_CAL_DC_OVER_DT, - BP_FILTER, - RF_BAND, - GAIN_TAPER, - IR_MEASURE, -}; - -extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *post_div, u8 *div); -extern int tda18271_lookup_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *val); - -extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); - -extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, - u32 *freq, u8 *rf_band); - -extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, - u32 *freq, u8 *cid_target, - u16 *count_limit); - -extern int tda18271_assign_map_layout(struct dvb_frontend *fe); - -/*---------------------------------------------------------------------*/ - -extern int tda18271_read_regs(struct dvb_frontend *fe); -extern int tda18271_read_extended(struct dvb_frontend *fe); -extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); -extern int tda18271_init_regs(struct dvb_frontend *fe); - -extern int tda18271_set_standby_mode(struct dvb_frontend *fe, - int sm, int sm_lt, int sm_xt); - -extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); -extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); - -extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); -extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); - -#endif /* __TDA18271_PRIV_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/trunk/drivers/media/dvb/frontends/tda18271-tables.c b/trunk/drivers/media/dvb/frontends/tda18271-tables.c deleted file mode 100644 index e94afcfdc5bc..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda18271-tables.c +++ /dev/null @@ -1,1285 +0,0 @@ -/* - tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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 "tda18271-priv.h" - -struct tda18271_pll_map { - u32 lomax; - u8 pd; /* post div */ - u8 d; /* div */ -}; - -struct tda18271_map { - u32 rfmax; - u8 val; -}; - -/*---------------------------------------------------------------------*/ - -static struct tda18271_pll_map tda18271c1_main_pll[] = { - { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, - { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, - { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, - { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, - { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, - { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, - { .lomax = 54000, .pd = 0x59, .d = 0x90 }, - { .lomax = 61000, .pd = 0x58, .d = 0x80 }, - { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, - { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, - { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, - { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, - { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, - { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, - { .lomax = 109000, .pd = 0x49, .d = 0x48 }, - { .lomax = 123000, .pd = 0x48, .d = 0x40 }, - { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, - { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, - { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, - { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, - { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, - { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, - { .lomax = 219000, .pd = 0x39, .d = 0x24 }, - { .lomax = 246000, .pd = 0x38, .d = 0x20 }, - { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, - { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, - { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, - { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, - { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, - { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, - { .lomax = 438000, .pd = 0x29, .d = 0x12 }, - { .lomax = 493000, .pd = 0x28, .d = 0x10 }, - { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, - { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, - { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, - { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, - { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, - { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, - { .lomax = 877000, .pd = 0x19, .d = 0x09 }, - { .lomax = 987000, .pd = 0x18, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c2_main_pll[] = { - { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, - { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, - { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, - { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, - { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, - { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, - { .lomax = 55188, .pd = 0x51, .d = 0x90 }, - { .lomax = 62125, .pd = 0x50, .d = 0x80 }, - { .lomax = 66250, .pd = 0x47, .d = 0x78 }, - { .lomax = 71000, .pd = 0x46, .d = 0x70 }, - { .lomax = 76375, .pd = 0x45, .d = 0x68 }, - { .lomax = 82750, .pd = 0x44, .d = 0x60 }, - { .lomax = 90250, .pd = 0x43, .d = 0x58 }, - { .lomax = 99375, .pd = 0x42, .d = 0x50 }, - { .lomax = 110375, .pd = 0x41, .d = 0x48 }, - { .lomax = 124250, .pd = 0x40, .d = 0x40 }, - { .lomax = 132500, .pd = 0x37, .d = 0x3c }, - { .lomax = 142000, .pd = 0x36, .d = 0x38 }, - { .lomax = 152750, .pd = 0x35, .d = 0x34 }, - { .lomax = 165500, .pd = 0x34, .d = 0x30 }, - { .lomax = 180500, .pd = 0x33, .d = 0x2c }, - { .lomax = 198750, .pd = 0x32, .d = 0x28 }, - { .lomax = 220750, .pd = 0x31, .d = 0x24 }, - { .lomax = 248500, .pd = 0x30, .d = 0x20 }, - { .lomax = 265000, .pd = 0x27, .d = 0x1e }, - { .lomax = 284000, .pd = 0x26, .d = 0x1c }, - { .lomax = 305500, .pd = 0x25, .d = 0x1a }, - { .lomax = 331000, .pd = 0x24, .d = 0x18 }, - { .lomax = 361000, .pd = 0x23, .d = 0x16 }, - { .lomax = 397500, .pd = 0x22, .d = 0x14 }, - { .lomax = 441500, .pd = 0x21, .d = 0x12 }, - { .lomax = 497000, .pd = 0x20, .d = 0x10 }, - { .lomax = 530000, .pd = 0x17, .d = 0x0f }, - { .lomax = 568000, .pd = 0x16, .d = 0x0e }, - { .lomax = 611000, .pd = 0x15, .d = 0x0d }, - { .lomax = 662000, .pd = 0x14, .d = 0x0c }, - { .lomax = 722000, .pd = 0x13, .d = 0x0b }, - { .lomax = 795000, .pd = 0x12, .d = 0x0a }, - { .lomax = 883000, .pd = 0x11, .d = 0x09 }, - { .lomax = 994000, .pd = 0x10, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c1_cal_pll[] = { - { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, - { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, - { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, - { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, - { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, - { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, - { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, - { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, - { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, - { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, - { .lomax = 88000, .pd = 0xca, .d = 0x50 }, - { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, - { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, - { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, - { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, - { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, - { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, - { .lomax = 176000, .pd = 0xba, .d = 0x28 }, - { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, - { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, - { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, - { .lomax = 271000, .pd = 0xad, .d = 0x1a }, - { .lomax = 294000, .pd = 0xac, .d = 0x18 }, - { .lomax = 321000, .pd = 0xab, .d = 0x16 }, - { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, - { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, - { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, - { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, - { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, - { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, - { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, - { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, - { .lomax = 785000, .pd = 0x99, .d = 0x09 }, - { .lomax = 883000, .pd = 0x98, .d = 0x08 }, - { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_pll_map tda18271c2_cal_pll[] = { - { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, - { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, - { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, - { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, - { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, - { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, - { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, - { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, - { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, - { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, - { .lomax = 87875, .pd = 0xca, .d = 0x50 }, - { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, - { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, - { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, - { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, - { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, - { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, - { .lomax = 175750, .pd = 0xba, .d = 0x28 }, - { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, - { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, - { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, - { .lomax = 270500, .pd = 0xad, .d = 0x1a }, - { .lomax = 293000, .pd = 0xac, .d = 0x18 }, - { .lomax = 319500, .pd = 0xab, .d = 0x16 }, - { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, - { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, - { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, - { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, - { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, - { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, - { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, - { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, - { .lomax = 781000, .pd = 0x99, .d = 0x09 }, - { .lomax = 879000, .pd = 0x98, .d = 0x08 }, - { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_bp_filter[] = { - { .rfmax = 62000, .val = 0x00 }, - { .rfmax = 84000, .val = 0x01 }, - { .rfmax = 100000, .val = 0x02 }, - { .rfmax = 140000, .val = 0x03 }, - { .rfmax = 170000, .val = 0x04 }, - { .rfmax = 180000, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c1_km[] = { - { .rfmax = 61100, .val = 0x74 }, - { .rfmax = 350000, .val = 0x40 }, - { .rfmax = 720000, .val = 0x30 }, - { .rfmax = 865000, .val = 0x40 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c2_km[] = { - { .rfmax = 47900, .val = 0x38 }, - { .rfmax = 61100, .val = 0x44 }, - { .rfmax = 350000, .val = 0x30 }, - { .rfmax = 720000, .val = 0x24 }, - { .rfmax = 865000, .val = 0x3c }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_band[] = { - { .rfmax = 47900, .val = 0x00 }, - { .rfmax = 61100, .val = 0x01 }, -/* { .rfmax = 152600, .val = 0x02 }, */ - { .rfmax = 121200, .val = 0x02 }, - { .rfmax = 164700, .val = 0x03 }, - { .rfmax = 203500, .val = 0x04 }, - { .rfmax = 457800, .val = 0x05 }, - { .rfmax = 865000, .val = 0x06 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_gain_taper[] = { - { .rfmax = 45400, .val = 0x1f }, - { .rfmax = 45800, .val = 0x1e }, - { .rfmax = 46200, .val = 0x1d }, - { .rfmax = 46700, .val = 0x1c }, - { .rfmax = 47100, .val = 0x1b }, - { .rfmax = 47500, .val = 0x1a }, - { .rfmax = 47900, .val = 0x19 }, - { .rfmax = 49600, .val = 0x17 }, - { .rfmax = 51200, .val = 0x16 }, - { .rfmax = 52900, .val = 0x15 }, - { .rfmax = 54500, .val = 0x14 }, - { .rfmax = 56200, .val = 0x13 }, - { .rfmax = 57800, .val = 0x12 }, - { .rfmax = 59500, .val = 0x11 }, - { .rfmax = 61100, .val = 0x10 }, - { .rfmax = 67600, .val = 0x0d }, - { .rfmax = 74200, .val = 0x0c }, - { .rfmax = 80700, .val = 0x0b }, - { .rfmax = 87200, .val = 0x0a }, - { .rfmax = 93800, .val = 0x09 }, - { .rfmax = 100300, .val = 0x08 }, - { .rfmax = 106900, .val = 0x07 }, - { .rfmax = 113400, .val = 0x06 }, - { .rfmax = 119900, .val = 0x05 }, - { .rfmax = 126500, .val = 0x04 }, - { .rfmax = 133000, .val = 0x03 }, - { .rfmax = 139500, .val = 0x02 }, - { .rfmax = 146100, .val = 0x01 }, - { .rfmax = 152600, .val = 0x00 }, - { .rfmax = 154300, .val = 0x1f }, - { .rfmax = 156100, .val = 0x1e }, - { .rfmax = 157800, .val = 0x1d }, - { .rfmax = 159500, .val = 0x1c }, - { .rfmax = 161200, .val = 0x1b }, - { .rfmax = 163000, .val = 0x1a }, - { .rfmax = 164700, .val = 0x19 }, - { .rfmax = 170200, .val = 0x17 }, - { .rfmax = 175800, .val = 0x16 }, - { .rfmax = 181300, .val = 0x15 }, - { .rfmax = 186900, .val = 0x14 }, - { .rfmax = 192400, .val = 0x13 }, - { .rfmax = 198000, .val = 0x12 }, - { .rfmax = 203500, .val = 0x11 }, - { .rfmax = 216200, .val = 0x14 }, - { .rfmax = 228900, .val = 0x13 }, - { .rfmax = 241600, .val = 0x12 }, - { .rfmax = 254400, .val = 0x11 }, - { .rfmax = 267100, .val = 0x10 }, - { .rfmax = 279800, .val = 0x0f }, - { .rfmax = 292500, .val = 0x0e }, - { .rfmax = 305200, .val = 0x0d }, - { .rfmax = 317900, .val = 0x0c }, - { .rfmax = 330700, .val = 0x0b }, - { .rfmax = 343400, .val = 0x0a }, - { .rfmax = 356100, .val = 0x09 }, - { .rfmax = 368800, .val = 0x08 }, - { .rfmax = 381500, .val = 0x07 }, - { .rfmax = 394200, .val = 0x06 }, - { .rfmax = 406900, .val = 0x05 }, - { .rfmax = 419700, .val = 0x04 }, - { .rfmax = 432400, .val = 0x03 }, - { .rfmax = 445100, .val = 0x02 }, - { .rfmax = 457800, .val = 0x01 }, - { .rfmax = 476300, .val = 0x19 }, - { .rfmax = 494800, .val = 0x18 }, - { .rfmax = 513300, .val = 0x17 }, - { .rfmax = 531800, .val = 0x16 }, - { .rfmax = 550300, .val = 0x15 }, - { .rfmax = 568900, .val = 0x14 }, - { .rfmax = 587400, .val = 0x13 }, - { .rfmax = 605900, .val = 0x12 }, - { .rfmax = 624400, .val = 0x11 }, - { .rfmax = 642900, .val = 0x10 }, - { .rfmax = 661400, .val = 0x0f }, - { .rfmax = 679900, .val = 0x0e }, - { .rfmax = 698400, .val = 0x0d }, - { .rfmax = 716900, .val = 0x0c }, - { .rfmax = 735400, .val = 0x0b }, - { .rfmax = 753900, .val = 0x0a }, - { .rfmax = 772500, .val = 0x09 }, - { .rfmax = 791000, .val = 0x08 }, - { .rfmax = 809500, .val = 0x07 }, - { .rfmax = 828000, .val = 0x06 }, - { .rfmax = 846500, .val = 0x05 }, - { .rfmax = 865000, .val = 0x04 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c1_rf_cal[] = { - { .rfmax = 41000, .val = 0x1e }, - { .rfmax = 43000, .val = 0x30 }, - { .rfmax = 45000, .val = 0x43 }, - { .rfmax = 46000, .val = 0x4d }, - { .rfmax = 47000, .val = 0x54 }, - { .rfmax = 47900, .val = 0x64 }, - { .rfmax = 49100, .val = 0x20 }, - { .rfmax = 50000, .val = 0x22 }, - { .rfmax = 51000, .val = 0x2a }, - { .rfmax = 53000, .val = 0x32 }, - { .rfmax = 55000, .val = 0x35 }, - { .rfmax = 56000, .val = 0x3c }, - { .rfmax = 57000, .val = 0x3f }, - { .rfmax = 58000, .val = 0x48 }, - { .rfmax = 59000, .val = 0x4d }, - { .rfmax = 60000, .val = 0x58 }, - { .rfmax = 61100, .val = 0x5f }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271c2_rf_cal[] = { - { .rfmax = 41000, .val = 0x0f }, - { .rfmax = 43000, .val = 0x1c }, - { .rfmax = 45000, .val = 0x2f }, - { .rfmax = 46000, .val = 0x39 }, - { .rfmax = 47000, .val = 0x40 }, - { .rfmax = 47900, .val = 0x50 }, - { .rfmax = 49100, .val = 0x16 }, - { .rfmax = 50000, .val = 0x18 }, - { .rfmax = 51000, .val = 0x20 }, - { .rfmax = 53000, .val = 0x28 }, - { .rfmax = 55000, .val = 0x2b }, - { .rfmax = 56000, .val = 0x32 }, - { .rfmax = 57000, .val = 0x35 }, - { .rfmax = 58000, .val = 0x3e }, - { .rfmax = 59000, .val = 0x43 }, - { .rfmax = 60000, .val = 0x4e }, - { .rfmax = 61100, .val = 0x55 }, - { .rfmax = 63000, .val = 0x0f }, - { .rfmax = 64000, .val = 0x11 }, - { .rfmax = 65000, .val = 0x12 }, - { .rfmax = 66000, .val = 0x15 }, - { .rfmax = 67000, .val = 0x16 }, - { .rfmax = 68000, .val = 0x17 }, - { .rfmax = 70000, .val = 0x19 }, - { .rfmax = 71000, .val = 0x1c }, - { .rfmax = 72000, .val = 0x1d }, - { .rfmax = 73000, .val = 0x1f }, - { .rfmax = 74000, .val = 0x20 }, - { .rfmax = 75000, .val = 0x21 }, - { .rfmax = 76000, .val = 0x24 }, - { .rfmax = 77000, .val = 0x25 }, - { .rfmax = 78000, .val = 0x27 }, - { .rfmax = 80000, .val = 0x28 }, - { .rfmax = 81000, .val = 0x29 }, - { .rfmax = 82000, .val = 0x2d }, - { .rfmax = 83000, .val = 0x2e }, - { .rfmax = 84000, .val = 0x2f }, - { .rfmax = 85000, .val = 0x31 }, - { .rfmax = 86000, .val = 0x33 }, - { .rfmax = 87000, .val = 0x34 }, - { .rfmax = 88000, .val = 0x35 }, - { .rfmax = 89000, .val = 0x37 }, - { .rfmax = 90000, .val = 0x38 }, - { .rfmax = 91000, .val = 0x39 }, - { .rfmax = 93000, .val = 0x3c }, - { .rfmax = 94000, .val = 0x3e }, - { .rfmax = 95000, .val = 0x3f }, - { .rfmax = 96000, .val = 0x40 }, - { .rfmax = 97000, .val = 0x42 }, - { .rfmax = 99000, .val = 0x45 }, - { .rfmax = 100000, .val = 0x46 }, - { .rfmax = 102000, .val = 0x48 }, - { .rfmax = 103000, .val = 0x4a }, - { .rfmax = 105000, .val = 0x4d }, - { .rfmax = 106000, .val = 0x4e }, - { .rfmax = 107000, .val = 0x50 }, - { .rfmax = 108000, .val = 0x51 }, - { .rfmax = 110000, .val = 0x54 }, - { .rfmax = 111000, .val = 0x56 }, - { .rfmax = 112000, .val = 0x57 }, - { .rfmax = 113000, .val = 0x58 }, - { .rfmax = 114000, .val = 0x59 }, - { .rfmax = 115000, .val = 0x5c }, - { .rfmax = 116000, .val = 0x5d }, - { .rfmax = 117000, .val = 0x5f }, - { .rfmax = 119000, .val = 0x60 }, - { .rfmax = 120000, .val = 0x64 }, - { .rfmax = 121000, .val = 0x65 }, - { .rfmax = 122000, .val = 0x66 }, - { .rfmax = 123000, .val = 0x68 }, - { .rfmax = 124000, .val = 0x69 }, - { .rfmax = 125000, .val = 0x6c }, - { .rfmax = 126000, .val = 0x6d }, - { .rfmax = 127000, .val = 0x6e }, - { .rfmax = 128000, .val = 0x70 }, - { .rfmax = 129000, .val = 0x71 }, - { .rfmax = 130000, .val = 0x75 }, - { .rfmax = 131000, .val = 0x77 }, - { .rfmax = 132000, .val = 0x78 }, - { .rfmax = 133000, .val = 0x7b }, - { .rfmax = 134000, .val = 0x7e }, - { .rfmax = 135000, .val = 0x81 }, - { .rfmax = 136000, .val = 0x82 }, - { .rfmax = 137000, .val = 0x87 }, - { .rfmax = 138000, .val = 0x88 }, - { .rfmax = 139000, .val = 0x8d }, - { .rfmax = 140000, .val = 0x8e }, - { .rfmax = 141000, .val = 0x91 }, - { .rfmax = 142000, .val = 0x95 }, - { .rfmax = 143000, .val = 0x9a }, - { .rfmax = 144000, .val = 0x9d }, - { .rfmax = 145000, .val = 0xa1 }, - { .rfmax = 146000, .val = 0xa2 }, - { .rfmax = 147000, .val = 0xa4 }, - { .rfmax = 148000, .val = 0xa9 }, - { .rfmax = 149000, .val = 0xae }, - { .rfmax = 150000, .val = 0xb0 }, - { .rfmax = 151000, .val = 0xb1 }, - { .rfmax = 152000, .val = 0xb7 }, - { .rfmax = 153000, .val = 0xbd }, - { .rfmax = 154000, .val = 0x20 }, - { .rfmax = 155000, .val = 0x22 }, - { .rfmax = 156000, .val = 0x24 }, - { .rfmax = 157000, .val = 0x25 }, - { .rfmax = 158000, .val = 0x27 }, - { .rfmax = 159000, .val = 0x29 }, - { .rfmax = 160000, .val = 0x2c }, - { .rfmax = 161000, .val = 0x2d }, - { .rfmax = 163000, .val = 0x2e }, - { .rfmax = 164000, .val = 0x2f }, - { .rfmax = 165000, .val = 0x30 }, - { .rfmax = 166000, .val = 0x11 }, - { .rfmax = 167000, .val = 0x12 }, - { .rfmax = 168000, .val = 0x13 }, - { .rfmax = 169000, .val = 0x14 }, - { .rfmax = 170000, .val = 0x15 }, - { .rfmax = 172000, .val = 0x16 }, - { .rfmax = 173000, .val = 0x17 }, - { .rfmax = 174000, .val = 0x18 }, - { .rfmax = 175000, .val = 0x1a }, - { .rfmax = 176000, .val = 0x1b }, - { .rfmax = 178000, .val = 0x1d }, - { .rfmax = 179000, .val = 0x1e }, - { .rfmax = 180000, .val = 0x1f }, - { .rfmax = 181000, .val = 0x20 }, - { .rfmax = 182000, .val = 0x21 }, - { .rfmax = 183000, .val = 0x22 }, - { .rfmax = 184000, .val = 0x24 }, - { .rfmax = 185000, .val = 0x25 }, - { .rfmax = 186000, .val = 0x26 }, - { .rfmax = 187000, .val = 0x27 }, - { .rfmax = 188000, .val = 0x29 }, - { .rfmax = 189000, .val = 0x2a }, - { .rfmax = 190000, .val = 0x2c }, - { .rfmax = 191000, .val = 0x2d }, - { .rfmax = 192000, .val = 0x2e }, - { .rfmax = 193000, .val = 0x2f }, - { .rfmax = 194000, .val = 0x30 }, - { .rfmax = 195000, .val = 0x33 }, - { .rfmax = 196000, .val = 0x35 }, - { .rfmax = 198000, .val = 0x36 }, - { .rfmax = 200000, .val = 0x38 }, - { .rfmax = 201000, .val = 0x3c }, - { .rfmax = 202000, .val = 0x3d }, - { .rfmax = 203500, .val = 0x3e }, - { .rfmax = 206000, .val = 0x0e }, - { .rfmax = 208000, .val = 0x0f }, - { .rfmax = 212000, .val = 0x10 }, - { .rfmax = 216000, .val = 0x11 }, - { .rfmax = 217000, .val = 0x12 }, - { .rfmax = 218000, .val = 0x13 }, - { .rfmax = 220000, .val = 0x14 }, - { .rfmax = 222000, .val = 0x15 }, - { .rfmax = 225000, .val = 0x16 }, - { .rfmax = 228000, .val = 0x17 }, - { .rfmax = 231000, .val = 0x18 }, - { .rfmax = 234000, .val = 0x19 }, - { .rfmax = 235000, .val = 0x1a }, - { .rfmax = 236000, .val = 0x1b }, - { .rfmax = 237000, .val = 0x1c }, - { .rfmax = 240000, .val = 0x1d }, - { .rfmax = 242000, .val = 0x1f }, - { .rfmax = 247000, .val = 0x20 }, - { .rfmax = 249000, .val = 0x21 }, - { .rfmax = 252000, .val = 0x22 }, - { .rfmax = 253000, .val = 0x23 }, - { .rfmax = 254000, .val = 0x24 }, - { .rfmax = 256000, .val = 0x25 }, - { .rfmax = 259000, .val = 0x26 }, - { .rfmax = 262000, .val = 0x27 }, - { .rfmax = 264000, .val = 0x28 }, - { .rfmax = 267000, .val = 0x29 }, - { .rfmax = 269000, .val = 0x2a }, - { .rfmax = 271000, .val = 0x2b }, - { .rfmax = 273000, .val = 0x2c }, - { .rfmax = 275000, .val = 0x2d }, - { .rfmax = 277000, .val = 0x2e }, - { .rfmax = 279000, .val = 0x2f }, - { .rfmax = 282000, .val = 0x30 }, - { .rfmax = 284000, .val = 0x31 }, - { .rfmax = 286000, .val = 0x32 }, - { .rfmax = 287000, .val = 0x33 }, - { .rfmax = 290000, .val = 0x34 }, - { .rfmax = 293000, .val = 0x35 }, - { .rfmax = 295000, .val = 0x36 }, - { .rfmax = 297000, .val = 0x37 }, - { .rfmax = 300000, .val = 0x38 }, - { .rfmax = 303000, .val = 0x39 }, - { .rfmax = 305000, .val = 0x3a }, - { .rfmax = 306000, .val = 0x3b }, - { .rfmax = 307000, .val = 0x3c }, - { .rfmax = 310000, .val = 0x3d }, - { .rfmax = 312000, .val = 0x3e }, - { .rfmax = 315000, .val = 0x3f }, - { .rfmax = 318000, .val = 0x40 }, - { .rfmax = 320000, .val = 0x41 }, - { .rfmax = 323000, .val = 0x42 }, - { .rfmax = 324000, .val = 0x43 }, - { .rfmax = 325000, .val = 0x44 }, - { .rfmax = 327000, .val = 0x45 }, - { .rfmax = 331000, .val = 0x46 }, - { .rfmax = 334000, .val = 0x47 }, - { .rfmax = 337000, .val = 0x48 }, - { .rfmax = 339000, .val = 0x49 }, - { .rfmax = 340000, .val = 0x4a }, - { .rfmax = 341000, .val = 0x4b }, - { .rfmax = 343000, .val = 0x4c }, - { .rfmax = 345000, .val = 0x4d }, - { .rfmax = 349000, .val = 0x4e }, - { .rfmax = 352000, .val = 0x4f }, - { .rfmax = 353000, .val = 0x50 }, - { .rfmax = 355000, .val = 0x51 }, - { .rfmax = 357000, .val = 0x52 }, - { .rfmax = 359000, .val = 0x53 }, - { .rfmax = 361000, .val = 0x54 }, - { .rfmax = 362000, .val = 0x55 }, - { .rfmax = 364000, .val = 0x56 }, - { .rfmax = 368000, .val = 0x57 }, - { .rfmax = 370000, .val = 0x58 }, - { .rfmax = 372000, .val = 0x59 }, - { .rfmax = 375000, .val = 0x5a }, - { .rfmax = 376000, .val = 0x5b }, - { .rfmax = 377000, .val = 0x5c }, - { .rfmax = 379000, .val = 0x5d }, - { .rfmax = 382000, .val = 0x5e }, - { .rfmax = 384000, .val = 0x5f }, - { .rfmax = 385000, .val = 0x60 }, - { .rfmax = 386000, .val = 0x61 }, - { .rfmax = 388000, .val = 0x62 }, - { .rfmax = 390000, .val = 0x63 }, - { .rfmax = 393000, .val = 0x64 }, - { .rfmax = 394000, .val = 0x65 }, - { .rfmax = 396000, .val = 0x66 }, - { .rfmax = 397000, .val = 0x67 }, - { .rfmax = 398000, .val = 0x68 }, - { .rfmax = 400000, .val = 0x69 }, - { .rfmax = 402000, .val = 0x6a }, - { .rfmax = 403000, .val = 0x6b }, - { .rfmax = 407000, .val = 0x6c }, - { .rfmax = 408000, .val = 0x6d }, - { .rfmax = 409000, .val = 0x6e }, - { .rfmax = 410000, .val = 0x6f }, - { .rfmax = 411000, .val = 0x70 }, - { .rfmax = 412000, .val = 0x71 }, - { .rfmax = 413000, .val = 0x72 }, - { .rfmax = 414000, .val = 0x73 }, - { .rfmax = 417000, .val = 0x74 }, - { .rfmax = 418000, .val = 0x75 }, - { .rfmax = 420000, .val = 0x76 }, - { .rfmax = 422000, .val = 0x77 }, - { .rfmax = 423000, .val = 0x78 }, - { .rfmax = 424000, .val = 0x79 }, - { .rfmax = 427000, .val = 0x7a }, - { .rfmax = 428000, .val = 0x7b }, - { .rfmax = 429000, .val = 0x7d }, - { .rfmax = 432000, .val = 0x7f }, - { .rfmax = 434000, .val = 0x80 }, - { .rfmax = 435000, .val = 0x81 }, - { .rfmax = 436000, .val = 0x83 }, - { .rfmax = 437000, .val = 0x84 }, - { .rfmax = 438000, .val = 0x85 }, - { .rfmax = 439000, .val = 0x86 }, - { .rfmax = 440000, .val = 0x87 }, - { .rfmax = 441000, .val = 0x88 }, - { .rfmax = 442000, .val = 0x89 }, - { .rfmax = 445000, .val = 0x8a }, - { .rfmax = 446000, .val = 0x8b }, - { .rfmax = 447000, .val = 0x8c }, - { .rfmax = 448000, .val = 0x8e }, - { .rfmax = 449000, .val = 0x8f }, - { .rfmax = 450000, .val = 0x90 }, - { .rfmax = 452000, .val = 0x91 }, - { .rfmax = 453000, .val = 0x93 }, - { .rfmax = 454000, .val = 0x94 }, - { .rfmax = 456000, .val = 0x96 }, - { .rfmax = 457000, .val = 0x98 }, - { .rfmax = 461000, .val = 0x11 }, - { .rfmax = 468000, .val = 0x12 }, - { .rfmax = 472000, .val = 0x13 }, - { .rfmax = 473000, .val = 0x14 }, - { .rfmax = 474000, .val = 0x15 }, - { .rfmax = 481000, .val = 0x16 }, - { .rfmax = 486000, .val = 0x17 }, - { .rfmax = 491000, .val = 0x18 }, - { .rfmax = 498000, .val = 0x19 }, - { .rfmax = 499000, .val = 0x1a }, - { .rfmax = 501000, .val = 0x1b }, - { .rfmax = 506000, .val = 0x1c }, - { .rfmax = 511000, .val = 0x1d }, - { .rfmax = 516000, .val = 0x1e }, - { .rfmax = 520000, .val = 0x1f }, - { .rfmax = 521000, .val = 0x20 }, - { .rfmax = 525000, .val = 0x21 }, - { .rfmax = 529000, .val = 0x22 }, - { .rfmax = 533000, .val = 0x23 }, - { .rfmax = 539000, .val = 0x24 }, - { .rfmax = 541000, .val = 0x25 }, - { .rfmax = 547000, .val = 0x26 }, - { .rfmax = 549000, .val = 0x27 }, - { .rfmax = 551000, .val = 0x28 }, - { .rfmax = 556000, .val = 0x29 }, - { .rfmax = 561000, .val = 0x2a }, - { .rfmax = 563000, .val = 0x2b }, - { .rfmax = 565000, .val = 0x2c }, - { .rfmax = 569000, .val = 0x2d }, - { .rfmax = 571000, .val = 0x2e }, - { .rfmax = 577000, .val = 0x2f }, - { .rfmax = 580000, .val = 0x30 }, - { .rfmax = 582000, .val = 0x31 }, - { .rfmax = 584000, .val = 0x32 }, - { .rfmax = 588000, .val = 0x33 }, - { .rfmax = 591000, .val = 0x34 }, - { .rfmax = 596000, .val = 0x35 }, - { .rfmax = 598000, .val = 0x36 }, - { .rfmax = 603000, .val = 0x37 }, - { .rfmax = 604000, .val = 0x38 }, - { .rfmax = 606000, .val = 0x39 }, - { .rfmax = 612000, .val = 0x3a }, - { .rfmax = 615000, .val = 0x3b }, - { .rfmax = 617000, .val = 0x3c }, - { .rfmax = 621000, .val = 0x3d }, - { .rfmax = 622000, .val = 0x3e }, - { .rfmax = 625000, .val = 0x3f }, - { .rfmax = 632000, .val = 0x40 }, - { .rfmax = 633000, .val = 0x41 }, - { .rfmax = 634000, .val = 0x42 }, - { .rfmax = 642000, .val = 0x43 }, - { .rfmax = 643000, .val = 0x44 }, - { .rfmax = 647000, .val = 0x45 }, - { .rfmax = 650000, .val = 0x46 }, - { .rfmax = 652000, .val = 0x47 }, - { .rfmax = 657000, .val = 0x48 }, - { .rfmax = 661000, .val = 0x49 }, - { .rfmax = 662000, .val = 0x4a }, - { .rfmax = 665000, .val = 0x4b }, - { .rfmax = 667000, .val = 0x4c }, - { .rfmax = 670000, .val = 0x4d }, - { .rfmax = 673000, .val = 0x4e }, - { .rfmax = 676000, .val = 0x4f }, - { .rfmax = 677000, .val = 0x50 }, - { .rfmax = 681000, .val = 0x51 }, - { .rfmax = 683000, .val = 0x52 }, - { .rfmax = 686000, .val = 0x53 }, - { .rfmax = 688000, .val = 0x54 }, - { .rfmax = 689000, .val = 0x55 }, - { .rfmax = 691000, .val = 0x56 }, - { .rfmax = 695000, .val = 0x57 }, - { .rfmax = 698000, .val = 0x58 }, - { .rfmax = 703000, .val = 0x59 }, - { .rfmax = 704000, .val = 0x5a }, - { .rfmax = 705000, .val = 0x5b }, - { .rfmax = 707000, .val = 0x5c }, - { .rfmax = 710000, .val = 0x5d }, - { .rfmax = 712000, .val = 0x5e }, - { .rfmax = 717000, .val = 0x5f }, - { .rfmax = 718000, .val = 0x60 }, - { .rfmax = 721000, .val = 0x61 }, - { .rfmax = 722000, .val = 0x62 }, - { .rfmax = 723000, .val = 0x63 }, - { .rfmax = 725000, .val = 0x64 }, - { .rfmax = 727000, .val = 0x65 }, - { .rfmax = 730000, .val = 0x66 }, - { .rfmax = 732000, .val = 0x67 }, - { .rfmax = 735000, .val = 0x68 }, - { .rfmax = 740000, .val = 0x69 }, - { .rfmax = 741000, .val = 0x6a }, - { .rfmax = 742000, .val = 0x6b }, - { .rfmax = 743000, .val = 0x6c }, - { .rfmax = 745000, .val = 0x6d }, - { .rfmax = 747000, .val = 0x6e }, - { .rfmax = 748000, .val = 0x6f }, - { .rfmax = 750000, .val = 0x70 }, - { .rfmax = 752000, .val = 0x71 }, - { .rfmax = 754000, .val = 0x72 }, - { .rfmax = 757000, .val = 0x73 }, - { .rfmax = 758000, .val = 0x74 }, - { .rfmax = 760000, .val = 0x75 }, - { .rfmax = 763000, .val = 0x76 }, - { .rfmax = 764000, .val = 0x77 }, - { .rfmax = 766000, .val = 0x78 }, - { .rfmax = 767000, .val = 0x79 }, - { .rfmax = 768000, .val = 0x7a }, - { .rfmax = 773000, .val = 0x7b }, - { .rfmax = 774000, .val = 0x7c }, - { .rfmax = 776000, .val = 0x7d }, - { .rfmax = 777000, .val = 0x7e }, - { .rfmax = 778000, .val = 0x7f }, - { .rfmax = 779000, .val = 0x80 }, - { .rfmax = 781000, .val = 0x81 }, - { .rfmax = 783000, .val = 0x82 }, - { .rfmax = 784000, .val = 0x83 }, - { .rfmax = 785000, .val = 0x84 }, - { .rfmax = 786000, .val = 0x85 }, - { .rfmax = 793000, .val = 0x86 }, - { .rfmax = 794000, .val = 0x87 }, - { .rfmax = 795000, .val = 0x88 }, - { .rfmax = 797000, .val = 0x89 }, - { .rfmax = 799000, .val = 0x8a }, - { .rfmax = 801000, .val = 0x8b }, - { .rfmax = 802000, .val = 0x8c }, - { .rfmax = 803000, .val = 0x8d }, - { .rfmax = 804000, .val = 0x8e }, - { .rfmax = 810000, .val = 0x90 }, - { .rfmax = 811000, .val = 0x91 }, - { .rfmax = 812000, .val = 0x92 }, - { .rfmax = 814000, .val = 0x93 }, - { .rfmax = 816000, .val = 0x94 }, - { .rfmax = 817000, .val = 0x96 }, - { .rfmax = 818000, .val = 0x97 }, - { .rfmax = 820000, .val = 0x98 }, - { .rfmax = 821000, .val = 0x99 }, - { .rfmax = 822000, .val = 0x9a }, - { .rfmax = 828000, .val = 0x9b }, - { .rfmax = 829000, .val = 0x9d }, - { .rfmax = 830000, .val = 0x9f }, - { .rfmax = 831000, .val = 0xa0 }, - { .rfmax = 833000, .val = 0xa1 }, - { .rfmax = 835000, .val = 0xa2 }, - { .rfmax = 836000, .val = 0xa3 }, - { .rfmax = 837000, .val = 0xa4 }, - { .rfmax = 838000, .val = 0xa6 }, - { .rfmax = 840000, .val = 0xa8 }, - { .rfmax = 842000, .val = 0xa9 }, - { .rfmax = 845000, .val = 0xaa }, - { .rfmax = 846000, .val = 0xab }, - { .rfmax = 847000, .val = 0xad }, - { .rfmax = 848000, .val = 0xae }, - { .rfmax = 852000, .val = 0xaf }, - { .rfmax = 853000, .val = 0xb0 }, - { .rfmax = 858000, .val = 0xb1 }, - { .rfmax = 860000, .val = 0xb2 }, - { .rfmax = 861000, .val = 0xb3 }, - { .rfmax = 862000, .val = 0xb4 }, - { .rfmax = 863000, .val = 0xb6 }, - { .rfmax = 864000, .val = 0xb8 }, - { .rfmax = 865000, .val = 0xb9 }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -static struct tda18271_map tda18271_ir_measure[] = { - { .rfmax = 30000, .val = 4 }, - { .rfmax = 200000, .val = 5 }, - { .rfmax = 600000, .val = 6 }, - { .rfmax = 865000, .val = 7 }, - { .rfmax = 0, .val = 0 }, /* end */ -}; - -static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { - { .rfmax = 47900, .val = 0x00 }, - { .rfmax = 55000, .val = 0x00 }, - { .rfmax = 61100, .val = 0x0a }, - { .rfmax = 64000, .val = 0x0a }, - { .rfmax = 82000, .val = 0x14 }, - { .rfmax = 84000, .val = 0x19 }, - { .rfmax = 119000, .val = 0x1c }, - { .rfmax = 124000, .val = 0x20 }, - { .rfmax = 129000, .val = 0x2a }, - { .rfmax = 134000, .val = 0x32 }, - { .rfmax = 139000, .val = 0x39 }, - { .rfmax = 144000, .val = 0x3e }, - { .rfmax = 149000, .val = 0x3f }, - { .rfmax = 152600, .val = 0x40 }, - { .rfmax = 154000, .val = 0x40 }, - { .rfmax = 164700, .val = 0x41 }, - { .rfmax = 203500, .val = 0x32 }, - { .rfmax = 353000, .val = 0x19 }, - { .rfmax = 356000, .val = 0x1a }, - { .rfmax = 359000, .val = 0x1b }, - { .rfmax = 363000, .val = 0x1c }, - { .rfmax = 366000, .val = 0x1d }, - { .rfmax = 369000, .val = 0x1e }, - { .rfmax = 373000, .val = 0x1f }, - { .rfmax = 376000, .val = 0x20 }, - { .rfmax = 379000, .val = 0x21 }, - { .rfmax = 383000, .val = 0x22 }, - { .rfmax = 386000, .val = 0x23 }, - { .rfmax = 389000, .val = 0x24 }, - { .rfmax = 393000, .val = 0x25 }, - { .rfmax = 396000, .val = 0x26 }, - { .rfmax = 399000, .val = 0x27 }, - { .rfmax = 402000, .val = 0x28 }, - { .rfmax = 404000, .val = 0x29 }, - { .rfmax = 407000, .val = 0x2a }, - { .rfmax = 409000, .val = 0x2b }, - { .rfmax = 412000, .val = 0x2c }, - { .rfmax = 414000, .val = 0x2d }, - { .rfmax = 417000, .val = 0x2e }, - { .rfmax = 419000, .val = 0x2f }, - { .rfmax = 422000, .val = 0x30 }, - { .rfmax = 424000, .val = 0x31 }, - { .rfmax = 427000, .val = 0x32 }, - { .rfmax = 429000, .val = 0x33 }, - { .rfmax = 432000, .val = 0x34 }, - { .rfmax = 434000, .val = 0x35 }, - { .rfmax = 437000, .val = 0x36 }, - { .rfmax = 439000, .val = 0x37 }, - { .rfmax = 442000, .val = 0x38 }, - { .rfmax = 444000, .val = 0x39 }, - { .rfmax = 447000, .val = 0x3a }, - { .rfmax = 449000, .val = 0x3b }, - { .rfmax = 457800, .val = 0x3c }, - { .rfmax = 465000, .val = 0x0f }, - { .rfmax = 477000, .val = 0x12 }, - { .rfmax = 483000, .val = 0x14 }, - { .rfmax = 502000, .val = 0x19 }, - { .rfmax = 508000, .val = 0x1b }, - { .rfmax = 519000, .val = 0x1c }, - { .rfmax = 522000, .val = 0x1d }, - { .rfmax = 524000, .val = 0x1e }, - { .rfmax = 534000, .val = 0x1f }, - { .rfmax = 549000, .val = 0x20 }, - { .rfmax = 554000, .val = 0x22 }, - { .rfmax = 584000, .val = 0x24 }, - { .rfmax = 589000, .val = 0x26 }, - { .rfmax = 658000, .val = 0x27 }, - { .rfmax = 664000, .val = 0x2c }, - { .rfmax = 669000, .val = 0x2d }, - { .rfmax = 699000, .val = 0x2e }, - { .rfmax = 704000, .val = 0x30 }, - { .rfmax = 709000, .val = 0x31 }, - { .rfmax = 714000, .val = 0x32 }, - { .rfmax = 724000, .val = 0x33 }, - { .rfmax = 729000, .val = 0x36 }, - { .rfmax = 739000, .val = 0x38 }, - { .rfmax = 744000, .val = 0x39 }, - { .rfmax = 749000, .val = 0x3b }, - { .rfmax = 754000, .val = 0x3c }, - { .rfmax = 759000, .val = 0x3d }, - { .rfmax = 764000, .val = 0x3e }, - { .rfmax = 769000, .val = 0x3f }, - { .rfmax = 774000, .val = 0x40 }, - { .rfmax = 779000, .val = 0x41 }, - { .rfmax = 784000, .val = 0x43 }, - { .rfmax = 789000, .val = 0x46 }, - { .rfmax = 794000, .val = 0x48 }, - { .rfmax = 799000, .val = 0x4b }, - { .rfmax = 804000, .val = 0x4f }, - { .rfmax = 809000, .val = 0x54 }, - { .rfmax = 814000, .val = 0x59 }, - { .rfmax = 819000, .val = 0x5d }, - { .rfmax = 824000, .val = 0x61 }, - { .rfmax = 829000, .val = 0x68 }, - { .rfmax = 834000, .val = 0x6e }, - { .rfmax = 839000, .val = 0x75 }, - { .rfmax = 844000, .val = 0x7e }, - { .rfmax = 849000, .val = 0x82 }, - { .rfmax = 854000, .val = 0x84 }, - { .rfmax = 859000, .val = 0x8f }, - { .rfmax = 865000, .val = 0x9a }, - { .rfmax = 0, .val = 0x00 }, /* end */ -}; - -/*---------------------------------------------------------------------*/ - -struct tda18271_thermo_map { - u8 d; - u8 r0; - u8 r1; -}; - -static struct tda18271_thermo_map tda18271_thermometer[] = { - { .d = 0x00, .r0 = 60, .r1 = 92 }, - { .d = 0x01, .r0 = 62, .r1 = 94 }, - { .d = 0x02, .r0 = 66, .r1 = 98 }, - { .d = 0x03, .r0 = 64, .r1 = 96 }, - { .d = 0x04, .r0 = 74, .r1 = 106 }, - { .d = 0x05, .r0 = 72, .r1 = 104 }, - { .d = 0x06, .r0 = 68, .r1 = 100 }, - { .d = 0x07, .r0 = 70, .r1 = 102 }, - { .d = 0x08, .r0 = 90, .r1 = 122 }, - { .d = 0x09, .r0 = 88, .r1 = 120 }, - { .d = 0x0a, .r0 = 84, .r1 = 116 }, - { .d = 0x0b, .r0 = 86, .r1 = 118 }, - { .d = 0x0c, .r0 = 76, .r1 = 108 }, - { .d = 0x0d, .r0 = 78, .r1 = 110 }, - { .d = 0x0e, .r0 = 82, .r1 = 114 }, - { .d = 0x0f, .r0 = 80, .r1 = 112 }, - { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ -}; - -int tda18271_lookup_thermometer(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - unsigned char *regs = priv->tda18271_regs; - int val, i = 0; - - while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { - if (tda18271_thermometer[i + 1].d == 0) - break; - i++; - } - - if ((regs[R_TM] & 0x20) == 0x20) - val = tda18271_thermometer[i].r1; - else - val = tda18271_thermometer[i].r0; - - tda_map("(%d) tm = %d\n", i, val); - - return val; -} - -/*---------------------------------------------------------------------*/ - -struct tda18271_cid_target_map { - u32 rfmax; - u8 target; - u16 limit; -}; - -static struct tda18271_cid_target_map tda18271_cid_target[] = { - { .rfmax = 46000, .target = 0x04, .limit = 1800 }, - { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, - { .rfmax = 79100, .target = 0x01, .limit = 4000 }, - { .rfmax = 136800, .target = 0x18, .limit = 4000 }, - { .rfmax = 156700, .target = 0x18, .limit = 4000 }, - { .rfmax = 156700, .target = 0x18, .limit = 4000 }, - { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, - { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, - { .rfmax = 345000, .target = 0x18, .limit = 4000 }, - { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, - { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, - { .rfmax = 697500, .target = 0x32, .limit = 4000 }, - { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, - { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ -}; - -int tda18271_lookup_cid_target(struct dvb_frontend *fe, - u32 *freq, u8 *cid_target, u16 *count_limit) -{ - int i = 0; - - while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { - if (tda18271_cid_target[i + 1].rfmax == 0) - break; - i++; - } - *cid_target = tda18271_cid_target[i].target; - *count_limit = tda18271_cid_target[i].limit; - - tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, - tda18271_cid_target[i].target, tda18271_cid_target[i].limit); - - return 0; -} - -/*---------------------------------------------------------------------*/ - -static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { - { .rfmax = 47900, .rfband = 0x00, - .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 61100, .rfband = 0x01, - .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 152600, .rfband = 0x02, - .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, - { .rfmax = 164700, .rfband = 0x03, - .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 203500, .rfband = 0x04, - .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, - { .rfmax = 457800, .rfband = 0x05, - .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, - { .rfmax = 865000, .rfband = 0x06, - .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, - { .rfmax = 0, .rfband = 0x00, - .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ -}; - -int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; - int i = 0; - - while ((map[i].rfmax * 1000) < *freq) { - if (tda18271_debug & DBG_ADV) - tda_map("(%d) rfmax = %d < freq = %d, " - "rf1_def = %d, rf2_def = %d, rf3_def = %d, " - "rf1 = %d, rf2 = %d, rf3 = %d, " - "rf_a1 = %d, rf_a2 = %d, " - "rf_b1 = %d, rf_b2 = %d\n", - i, map[i].rfmax * 1000, *freq, - map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, - map[i].rf1, map[i].rf2, map[i].rf3, - map[i].rf_a1, map[i].rf_a2, - map[i].rf_b1, map[i].rf_b2); - if (map[i].rfmax == 0) - return -EINVAL; - i++; - } - if (rf_band) - *rf_band = map[i].rfband; - - tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); - - return i; -} - -/*---------------------------------------------------------------------*/ - -struct tda18271_map_layout { - struct tda18271_pll_map *main_pll; - struct tda18271_pll_map *cal_pll; - - struct tda18271_map *rf_cal; - struct tda18271_map *rf_cal_kmco; - struct tda18271_map *rf_cal_dc_over_dt; - - struct tda18271_map *bp_filter; - struct tda18271_map *rf_band; - struct tda18271_map *gain_taper; - struct tda18271_map *ir_measure; -}; - -/*---------------------------------------------------------------------*/ - -int tda18271_lookup_pll_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *post_div, u8 *div) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_pll_map *map = NULL; - unsigned int i = 0; - char *map_name; - int ret = 0; - - BUG_ON(!priv->maps); - - switch (map_type) { - case MAIN_PLL: - map = priv->maps->main_pll; - map_name = "main_pll"; - break; - case CAL_PLL: - map = priv->maps->cal_pll; - map_name = "cal_pll"; - break; - default: - /* we should never get here */ - map_name = "undefined"; - break; - } - - if (!map) { - tda_warn("%s map is not set!\n", map_name); - ret = -EINVAL; - goto fail; - } - - while ((map[i].lomax * 1000) < *freq) { - if (map[i + 1].lomax == 0) { - tda_map("%s: frequency (%d) out of range\n", - map_name, *freq); - ret = -ERANGE; - break; - } - i++; - } - *post_div = map[i].pd; - *div = map[i].d; - - tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", - i, map_name, *post_div, *div); -fail: - return ret; -} - -int tda18271_lookup_map(struct dvb_frontend *fe, - enum tda18271_map_type map_type, - u32 *freq, u8 *val) -{ - struct tda18271_priv *priv = fe->tuner_priv; - struct tda18271_map *map = NULL; - unsigned int i = 0; - char *map_name; - int ret = 0; - - BUG_ON(!priv->maps); - - switch (map_type) { - case BP_FILTER: - map = priv->maps->bp_filter; - map_name = "bp_filter"; - break; - case RF_CAL_KMCO: - map = priv->maps->rf_cal_kmco; - map_name = "km"; - break; - case RF_BAND: - map = priv->maps->rf_band; - map_name = "rf_band"; - break; - case GAIN_TAPER: - map = priv->maps->gain_taper; - map_name = "gain_taper"; - break; - case RF_CAL: - map = priv->maps->rf_cal; - map_name = "rf_cal"; - break; - case IR_MEASURE: - map = priv->maps->ir_measure; - map_name = "ir_measure"; - break; - case RF_CAL_DC_OVER_DT: - map = priv->maps->rf_cal_dc_over_dt; - map_name = "rf_cal_dc_over_dt"; - break; - default: - /* we should never get here */ - map_name = "undefined"; - break; - } - - if (!map) { - tda_warn("%s map is not set!\n", map_name); - ret = -EINVAL; - goto fail; - } - - while ((map[i].rfmax * 1000) < *freq) { - if (map[i + 1].rfmax == 0) { - tda_map("%s: frequency (%d) out of range\n", - map_name, *freq); - ret = -ERANGE; - break; - } - i++; - } - *val = map[i].val; - - tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); -fail: - return ret; -} - -/*---------------------------------------------------------------------*/ - -static struct tda18271_std_map tda18271c1_std_map = { - .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, - .atv_b = { .if_freq = 6750, .std_bits = 0x0e }, - .atv_dk = { .if_freq = 7750, .std_bits = 0x0f }, - .atv_gh = { .if_freq = 7750, .std_bits = 0x0f }, - .atv_i = { .if_freq = 7750, .std_bits = 0x0f }, - .atv_l = { .if_freq = 7750, .std_bits = 0x0f }, - .atv_lc = { .if_freq = 1250, .std_bits = 0x0f }, - .atv_mn = { .if_freq = 5750, .std_bits = 0x0d }, - .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c }, - .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c }, - .dvbt_7 = { .if_freq = 3800, .std_bits = 0x1d }, - .dvbt_8 = { .if_freq = 4300, .std_bits = 0x1e }, - .qam_6 = { .if_freq = 4000, .std_bits = 0x1d }, - .qam_8 = { .if_freq = 5000, .std_bits = 0x1f }, -}; - -static struct tda18271_std_map tda18271c2_std_map = { - .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, - .atv_b = { .if_freq = 6000, .std_bits = 0x0d }, - .atv_dk = { .if_freq = 6900, .std_bits = 0x0e }, - .atv_gh = { .if_freq = 7100, .std_bits = 0x0e }, - .atv_i = { .if_freq = 7250, .std_bits = 0x0e }, - .atv_l = { .if_freq = 6900, .std_bits = 0x0e }, - .atv_lc = { .if_freq = 1250, .std_bits = 0x0e }, - .atv_mn = { .if_freq = 5400, .std_bits = 0x0c }, - .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c }, - .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c }, - .dvbt_7 = { .if_freq = 3500, .std_bits = 0x1c }, - .dvbt_8 = { .if_freq = 4000, .std_bits = 0x1d }, - .qam_6 = { .if_freq = 4000, .std_bits = 0x1d }, - .qam_8 = { .if_freq = 5000, .std_bits = 0x1f }, -}; - -/*---------------------------------------------------------------------*/ - -static struct tda18271_map_layout tda18271c1_map_layout = { - .main_pll = tda18271c1_main_pll, - .cal_pll = tda18271c1_cal_pll, - - .rf_cal = tda18271c1_rf_cal, - .rf_cal_kmco = tda18271c1_km, - - .bp_filter = tda18271_bp_filter, - .rf_band = tda18271_rf_band, - .gain_taper = tda18271_gain_taper, - .ir_measure = tda18271_ir_measure, -}; - -static struct tda18271_map_layout tda18271c2_map_layout = { - .main_pll = tda18271c2_main_pll, - .cal_pll = tda18271c2_cal_pll, - - .rf_cal = tda18271c2_rf_cal, - .rf_cal_kmco = tda18271c2_km, - - .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, - - .bp_filter = tda18271_bp_filter, - .rf_band = tda18271_rf_band, - .gain_taper = tda18271_gain_taper, - .ir_measure = tda18271_ir_measure, -}; - -int tda18271_assign_map_layout(struct dvb_frontend *fe) -{ - struct tda18271_priv *priv = fe->tuner_priv; - int ret = 0; - - switch (priv->id) { - case TDA18271HDC1: - priv->maps = &tda18271c1_map_layout; - memcpy(&priv->std, &tda18271c1_std_map, - sizeof(struct tda18271_std_map)); - break; - case TDA18271HDC2: - priv->maps = &tda18271c2_map_layout; - memcpy(&priv->std, &tda18271c2_std_map, - sizeof(struct tda18271_std_map)); - break; - default: - ret = -EINVAL; - break; - } - memcpy(priv->rf_cal_state, &tda18271_rf_band_template, - sizeof(tda18271_rf_band_template)); - - return ret; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/trunk/drivers/media/dvb/frontends/tda18271.h b/trunk/drivers/media/dvb/frontends/tda18271.h deleted file mode 100644 index 24b0e35a2ab3..000000000000 --- a/trunk/drivers/media/dvb/frontends/tda18271.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - tda18271.h - header for the Philips / NXP TDA18271 silicon tuner - - Copyright (C) 2007, 2008 Michael Krufky - - 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 __TDA18271_H__ -#define __TDA18271_H__ - -#include -#include "dvb_frontend.h" - -struct tda18271_std_map_item { - u16 if_freq; - u8 std_bits; -}; - -struct tda18271_std_map { - struct tda18271_std_map_item fm_radio; - struct tda18271_std_map_item atv_b; - struct tda18271_std_map_item atv_dk; - struct tda18271_std_map_item atv_gh; - struct tda18271_std_map_item atv_i; - struct tda18271_std_map_item atv_l; - struct tda18271_std_map_item atv_lc; - struct tda18271_std_map_item atv_mn; - struct tda18271_std_map_item atsc_6; - struct tda18271_std_map_item dvbt_6; - struct tda18271_std_map_item dvbt_7; - struct tda18271_std_map_item dvbt_8; - struct tda18271_std_map_item qam_6; - struct tda18271_std_map_item qam_8; -}; - -enum tda18271_i2c_gate { - TDA18271_GATE_AUTO = 0, - TDA18271_GATE_ANALOG, - TDA18271_GATE_DIGITAL, -}; - -struct tda18271_config { - /* override default if freq / std settings (optional) */ - struct tda18271_std_map *std_map; - - /* use i2c gate provided by analog or digital demod */ - enum tda18271_i2c_gate gate; -}; - -#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg); -#else -static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, - u8 addr, - struct i2c_adapter *i2c, - struct tda18271_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; -} -#endif - -#endif /* __TDA18271_H__ */ diff --git a/trunk/drivers/media/dvb/frontends/tda827x.c b/trunk/drivers/media/dvb/frontends/tda827x.c index 229b11987a58..256fc4bf500b 100644 --- a/trunk/drivers/media/dvb/frontends/tda827x.c +++ b/trunk/drivers/media/dvb/frontends/tda827x.c @@ -19,16 +19,12 @@ */ #include -#include #include -#include +#include #include "tda827x.h" static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - #define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "tda827x: " args); \ @@ -38,57 +34,10 @@ struct tda827x_priv { int i2c_addr; struct i2c_adapter *i2c_adap; struct tda827x_config *cfg; - - unsigned int sgIF; - unsigned char lpsel; - u32 frequency; u32 bandwidth; }; -static void tda827x_set_std(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - char *mode; - - priv->lpsel = 0; - if (params->std & V4L2_STD_MN) { - priv->sgIF = 92; - priv->lpsel = 1; - mode = "MN"; - } else if (params->std & V4L2_STD_B) { - priv->sgIF = 108; - mode = "B"; - } else if (params->std & V4L2_STD_GH) { - priv->sgIF = 124; - mode = "GH"; - } else if (params->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; - mode = "I"; - } else if (params->std & V4L2_STD_DK) { - priv->sgIF = 124; - mode = "DK"; - } else if (params->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; - mode = "L"; - } else if (params->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; - mode = "LC"; - } else { - priv->sgIF = 124; - mode = "xx"; - } - - if (params->mode == V4L2_TUNER_RADIO) - priv->sgIF = 88; /* if frequency is 5.5 MHz */ - - dprintk("setting tda827x to system %s\n", mode); -} - - -/* ------------------------------------------------------------------ */ - struct tda827x_data { u32 lomax; u8 spd; @@ -99,7 +48,7 @@ struct tda827x_data { u8 div1p5; }; -static const struct tda827x_data tda827x_table[] = { +static const struct tda827x_data tda827x_dvbt[] = { { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, @@ -157,22 +106,21 @@ static int tda827xo_set_params(struct dvb_frontend *fe, tuner_freq = params->frequency + if_freq; i = 0; - while (tda827x_table[i].lomax < tuner_freq) { - if (tda827x_table[i + 1].lomax == 0) + while (tda827x_dvbt[i].lomax < tuner_freq) { + if(tda827x_dvbt[i + 1].lomax == 0) break; i++; } - N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); + N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); buf[0] = 0; buf[1] = (N>>8) | 0x40; buf[2] = N & 0xff; buf[3] = 0; buf[4] = 0x52; - buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + - (tda827x_table[i].bs << 3) + - tda827x_table[i].bp; - buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; + buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + + (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; + buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; buf[7] = 0xbf; buf[8] = 0x2a; buf[9] = 0x05; @@ -192,7 +140,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe, msleep(500); /* correct CP value */ buf[0] = 0x30; - buf[1] = 0x50 + tda827x_table[i].cp; + buf[1] = 0x50 + tda827x_dvbt[i].cp; msg.len = 2; if (fe->ops.i2c_gate_ctrl) @@ -225,102 +173,6 @@ static int tda827xo_sleep(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ -static int tda827xo_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[8]; - unsigned char reg2[2]; - u32 N; - int i; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; - unsigned int freq = params->frequency; - - tda827x_set_std(fe, params); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - - i = 0; - while (tda827x_table[i].lomax < N * 62500) { - if (tda827x_table[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827x_table[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (priv->lpsel << 5); - tuner_reg[5] = (tda827x_table[i].spd << 6) + - (tda827x_table[i].div1p5 << 5) + - (tda827x_table[i].bs << 3) + tda827x_table[i].bp; - tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); - tuner_reg[7] = 0x8f; - - msg.buf = tuner_reg; - msg.len = 8; - i2c_transfer(priv->i2c_adap, &msg, 1); - - msg.buf = reg2; - msg.len = 2; - reg2[0] = 0x80; - reg2[1] = 0; - i2c_transfer(priv->i2c_adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0xbf; - i2c_transfer(priv->i2c_adap, &msg, 1); - - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 0x80; - i2c_transfer(priv->i2c_adap, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 4; - i2c_transfer(priv->i2c_adap, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4]; - i2c_transfer(priv->i2c_adap, &msg, 1); - - msleep(550); - reg2[0] = 0x30; - reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; - i2c_transfer(priv->i2c_adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0x3f; - i2c_transfer(priv->i2c_adap, &msg, 1); - - reg2[0] = 0x80; - reg2[1] = 0x08; /* Vsync en */ - i2c_transfer(priv->i2c_adap, &msg, 1); - - priv->frequency = freq * 62500; - - return 0; -} - -static void tda827xo_agcf(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char data[] = { 0x80, 0x0c }; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = data, .len = 2}; - - i2c_transfer(priv->i2c_adap, &msg, 1); -} - -/* ------------------------------------------------------------------ */ - struct tda827xa_data { u32 lomax; u8 svco; @@ -360,35 +212,6 @@ static const struct tda827xa_data tda827xa_dvbt[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} }; -static struct tda827xa_data tda827xa_analog[] = { - { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, - { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, - { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, - { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, - { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, - { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, - { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, - { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, - { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, - { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, - { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, - { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} -}; - static int tda827xa_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { @@ -545,163 +368,6 @@ static int tda827xa_sleep(struct dvb_frontend *fe) return 0; } -/* ------------------------------------------------------------------ */ - -static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, - struct analog_parameters *params) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char buf[] = {0x22, 0x01}; - int arg; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = buf, .len = sizeof(buf) }; - - if (NULL == priv->cfg) { - dprintk("tda827x_config not defined, cannot set LNA gain!\n"); - return; - } - - if (priv->cfg->config) { - if (high) - dprintk("setting LNA to high gain\n"); - else - dprintk("setting LNA to low gain\n"); - } - switch (*priv->cfg->config) { - case 0: /* no LNA */ - break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - /* turn Vsync on */ - if (params->std & V4L2_STD_MN) - arg = 1; - else - arg = 0; - if (priv->cfg->tuner_callback) - priv->cfg->tuner_callback(priv->i2c_adap->algo_data, - 1, arg); - buf[1] = high ? 0 : 1; - if (*priv->cfg->config == 2) - buf[1] = high ? 1 : 0; - i2c_transfer(priv->i2c_adap, &msg, 1); - break; - case 3: /* switch with GPIO of saa713x */ - if (priv->cfg->tuner_callback) - priv->cfg->tuner_callback(priv->i2c_adap->algo_data, - 0, high); - break; - } -} - -static int tda827xa_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[11]; - u32 N; - int i; - struct tda827x_priv *priv = fe->tuner_priv; - struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, - .buf = tuner_reg, .len = sizeof(tuner_reg) }; - unsigned int freq = params->frequency; - - tda827x_set_std(fe, params); - - tda827xa_lna_gain(fe, 1, params); - msleep(10); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - - i = 0; - while (tda827xa_analog[i].lomax < N * 62500) { - if (tda827xa_analog[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827xa_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0; - tuner_reg[4] = 0x16; - tuner_reg[5] = (tda827xa_analog[i].spd << 5) + - (tda827xa_analog[i].svco << 3) + - tda827xa_analog[i].sbs; - tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); - tuner_reg[7] = 0x1c; - tuner_reg[8] = 4; - tuner_reg[9] = 0x20; - tuner_reg[10] = 0x00; - msg.len = 11; - i2c_transfer(priv->i2c_adap, &msg, 1); - - tuner_reg[0] = 0x90; - tuner_reg[1] = 0xff; - tuner_reg[2] = 0xe0; - tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (priv->lpsel << 1); - msg.len = 5; - i2c_transfer(priv->i2c_adap, &msg, 1); - - tuner_reg[0] = 0xa0; - tuner_reg[1] = 0xc0; - msg.len = 2; - i2c_transfer(priv->i2c_adap, &msg, 1); - - tuner_reg[0] = 0x30; - tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - i2c_transfer(priv->i2c_adap, &msg, 1); - - msg.flags = I2C_M_RD; - i2c_transfer(priv->i2c_adap, &msg, 1); - msg.flags = 0; - tuner_reg[1] >>= 4; - dprintk("AGC2 gain is: %d\n", tuner_reg[1]); - if (tuner_reg[1] < 1) - tda827xa_lna_gain(fe, 0, params); - - msleep(100); - tuner_reg[0] = 0x60; - tuner_reg[1] = 0x3c; - i2c_transfer(priv->i2c_adap, &msg, 1); - - msleep(163); - tuner_reg[0] = 0x50; - tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - i2c_transfer(priv->i2c_adap, &msg, 1); - - tuner_reg[0] = 0x80; - tuner_reg[1] = 0x28; - i2c_transfer(priv->i2c_adap, &msg, 1); - - tuner_reg[0] = 0xb0; - tuner_reg[1] = 0x01; - i2c_transfer(priv->i2c_adap, &msg, 1); - - tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (priv->lpsel << 1); - i2c_transfer(priv->i2c_adap, &msg, 1); - - priv->frequency = freq * 62500; - - return 0; -} - -static void tda827xa_agcf(struct dvb_frontend *fe) -{ - struct tda827x_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x2c}; - struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, - .buf = data, .len = 2}; - i2c_transfer(priv->i2c_adap, &msg, 1); -} - -/* ------------------------------------------------------------------ */ - static int tda827x_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); @@ -764,7 +430,6 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = { .init = tda827x_initial_init, .sleep = tda827x_initial_sleep, .set_params = tda827xo_set_params, - .set_analog_params = tda827xo_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -780,7 +445,6 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = { .init = tda827x_init, .sleep = tda827xa_sleep, .set_params = tda827xa_set_params, - .set_analog_params = tda827xa_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -801,13 +465,9 @@ static int tda827x_probe_version(struct dvb_frontend *fe) dprintk("tda827x tuner found\n"); fe->ops.tuner_ops.init = tda827x_init; fe->ops.tuner_ops.sleep = tda827xo_sleep; - if (priv->cfg) - priv->cfg->agcf = tda827xo_agcf; } else { dprintk("tda827xa tuner found\n"); memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); - if (priv->cfg) - priv->cfg->agcf = tda827xa_agcf; } return 0; } @@ -827,13 +487,16 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, priv->i2c_adap = i2c; priv->cfg = cfg; memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); + fe->tuner_priv = priv; return fe; } -EXPORT_SYMBOL_GPL(tda827x_attach); + +EXPORT_SYMBOL(tda827x_attach); + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann "); diff --git a/trunk/drivers/media/dvb/frontends/tda827x.h b/trunk/drivers/media/dvb/frontends/tda827x.h index 92eb65b4012b..69e8263d6d59 100644 --- a/trunk/drivers/media/dvb/frontends/tda827x.h +++ b/trunk/drivers/media/dvb/frontends/tda827x.h @@ -29,16 +29,9 @@ struct tda827x_config { - /* saa7134 - provided callbacks */ void (*lna_gain) (struct dvb_frontend *fe, int high); int (*init) (struct dvb_frontend *fe); int (*sleep) (struct dvb_frontend *fe); - - /* interface to tda829x driver */ - unsigned int *config; - int (*tuner_callback) (void *dev, int command, int arg); - - void (*agcf)(struct dvb_frontend *fe); }; diff --git a/trunk/drivers/media/dvb/frontends/ves1820.c b/trunk/drivers/media/dvb/frontends/ves1820.c index 8791701c8f25..60433b5011fd 100644 --- a/trunk/drivers/media/dvb/frontends/ves1820.c +++ b/trunk/drivers/media/dvb/frontends/ves1820.c @@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("ves1820: %s(): writereg error (reg == 0x%02x, " + printk("ves1820: %s(): writereg error (reg == 0x%02x," "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; @@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("ves1820: %s(): readreg error (reg == 0x%02x, " + printk("ves1820: %s(): readreg error (reg == 0x%02x," "ret == %i)\n", __FUNCTION__, reg, ret); return b1[0]; diff --git a/trunk/drivers/media/dvb/frontends/xc5000.c b/trunk/drivers/media/dvb/frontends/xc5000.c deleted file mode 100644 index f642ca200b59..000000000000 --- a/trunk/drivers/media/dvb/frontends/xc5000.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Xceive Corporation - * Copyright (c) 2007 Steven Toth - * - * 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 -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#include "xc5000.h" -#include "xc5000_priv.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); - -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) - -#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw" -#define XC5000_DEFAULT_FIRMWARE_SIZE 12332 - -/* Misc Defines */ -#define MAX_TV_STANDARD 23 -#define XC_MAX_I2C_WRITE_LENGTH 64 - -/* Signal Types */ -#define XC_RF_MODE_AIR 0 -#define XC_RF_MODE_CABLE 1 - -/* Result codes */ -#define XC_RESULT_SUCCESS 0 -#define XC_RESULT_RESET_FAILURE 1 -#define XC_RESULT_I2C_WRITE_FAILURE 2 -#define XC_RESULT_I2C_READ_FAILURE 3 -#define XC_RESULT_OUT_OF_RANGE 5 - -/* Product id */ -#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 -#define XC_PRODUCT_ID_FW_LOADED 0x1388 - -/* Registers */ -#define XREG_INIT 0x00 -#define XREG_VIDEO_MODE 0x01 -#define XREG_AUDIO_MODE 0x02 -#define XREG_RF_FREQ 0x03 -#define XREG_D_CODE 0x04 -#define XREG_IF_OUT 0x05 -#define XREG_SEEK_MODE 0x07 -#define XREG_POWER_DOWN 0x0A -#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ -#define XREG_SMOOTHEDCVBS 0x0E -#define XREG_XTALFREQ 0x0F -#define XREG_FINERFFREQ 0x10 -#define XREG_DDIMODE 0x11 - -#define XREG_ADC_ENV 0x00 -#define XREG_QUALITY 0x01 -#define XREG_FRAME_LINES 0x02 -#define XREG_HSYNC_FREQ 0x03 -#define XREG_LOCK 0x04 -#define XREG_FREQ_ERROR 0x05 -#define XREG_SNR 0x06 -#define XREG_VERSION 0x07 -#define XREG_PRODUCT_ID 0x08 -#define XREG_BUSY 0x09 - -/* - Basic firmware description. This will remain with - the driver for documentation purposes. - - This represents an I2C firmware file encoded as a - string of unsigned char. Format is as follows: - - char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB - char[1 ]=len0_LSB -> length of first write transaction - char[2 ]=data0 -> first byte to be sent - char[3 ]=data1 - char[4 ]=data2 - char[ ]=... - char[M ]=dataN -> last byte to be sent - char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB - char[M+2]=len1_LSB -> length of second write transaction - char[M+3]=data0 - char[M+4]=data1 - ... - etc. - - The [len] value should be interpreted as follows: - - len= len_MSB _ len_LSB - len=1111_1111_1111_1111 : End of I2C_SEQUENCE - len=0000_0000_0000_0000 : Reset command: Do hardware reset - len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) - len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms - - For the RESET and WAIT commands, the two following bytes will contain - immediately the length of the following transaction. - -*/ -typedef struct { - char *Name; - u16 AudioMode; - u16 VideoMode; -} XC_TV_STANDARD; - -/* Tuner standards */ -#define MN_NTSC_PAL_BTSC 0 -#define MN_NTSC_PAL_A2 1 -#define MN_NTSC_PAL_EIAJ 2 -#define MN_NTSC_PAL_Mono 3 -#define BG_PAL_A2 4 -#define BG_PAL_NICAM 5 -#define BG_PAL_MONO 6 -#define I_PAL_NICAM 7 -#define I_PAL_NICAM_MONO 8 -#define DK_PAL_A2 9 -#define DK_PAL_NICAM 10 -#define DK_PAL_MONO 11 -#define DK_SECAM_A2DK1 12 -#define DK_SECAM_A2LDK3 13 -#define DK_SECAM_A2MONO 14 -#define L_SECAM_NICAM 15 -#define LC_SECAM_NICAM 16 -#define DTV6 17 -#define DTV8 18 -#define DTV7_8 19 -#define DTV7 20 -#define FM_Radio_INPUT2 21 -#define FM_Radio_INPUT1 22 - -XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { - {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, - {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, - {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, - {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, - {"B/G-PAL-A2", 0x0A00, 0x8049}, - {"B/G-PAL-NICAM", 0x0C04, 0x8049}, - {"B/G-PAL-MONO", 0x0878, 0x8059}, - {"I-PAL-NICAM", 0x1080, 0x8009}, - {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, - {"D/K-PAL-A2", 0x1600, 0x8009}, - {"D/K-PAL-NICAM", 0x0E80, 0x8009}, - {"D/K-PAL-MONO", 0x1478, 0x8009}, - {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, - {"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009}, - {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, - {"L-SECAM-NICAM", 0x8E82, 0x0009}, - {"L'-SECAM-NICAM", 0x8E82, 0x4009}, - {"DTV6", 0x00C0, 0x8002}, - {"DTV8", 0x00C0, 0x800B}, - {"DTV7/8", 0x00C0, 0x801B}, - {"DTV7", 0x00C0, 0x8007}, - {"FM Radio-INPUT2", 0x9802, 0x9002}, - {"FM Radio-INPUT1", 0x0208, 0x9002} -}; - -static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len); -static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len); -static void xc5000_TunerReset(struct dvb_frontend *fe); - -static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) -{ - return xc5000_writeregs(priv, buf, len) - ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS; -} - -static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) -{ - return xc5000_readregs(priv, buf, len) - ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS; -} - -static int xc_reset(struct dvb_frontend *fe) -{ - xc5000_TunerReset(fe); - return XC_RESULT_SUCCESS; -} - -static void xc_wait(int wait_ms) -{ - msleep(wait_ms); -} - -static void xc5000_TunerReset(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - dprintk(1, "%s()\n", __FUNCTION__); - - if (priv->cfg->tuner_callback) { - ret = priv->cfg->tuner_callback(priv->cfg->priv, - XC5000_TUNER_RESET, 0); - if (ret) - printk(KERN_ERR "xc5000: reset failed\n"); - } else - printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); -} - -static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) -{ - u8 buf[4]; - int WatchDogTimer = 5; - int result; - - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - buf[2] = (i2cData >> 8) & 0xFF; - buf[3] = i2cData & 0xFF; - result = xc_send_i2c_data(priv, buf, 4); - if (result == XC_RESULT_SUCCESS) { - /* wait for busy flag to clear */ - while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { - buf[0] = 0; - buf[1] = XREG_BUSY; - - result = xc_send_i2c_data(priv, buf, 2); - if (result == XC_RESULT_SUCCESS) { - result = xc_read_i2c_data(priv, buf, 2); - if (result == XC_RESULT_SUCCESS) { - if ((buf[0] == 0) && (buf[1] == 0)) { - /* busy flag cleared */ - break; - } else { - xc_wait(100); /* wait 5 ms */ - WatchDogTimer--; - } - } - } - } - } - if (WatchDogTimer < 0) - result = XC_RESULT_I2C_WRITE_FAILURE; - - return result; -} - -static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData) -{ - u8 buf[2]; - int result; - - buf[0] = (regAddr >> 8) & 0xFF; - buf[1] = regAddr & 0xFF; - result = xc_send_i2c_data(priv, buf, 2); - if (result != XC_RESULT_SUCCESS) - return result; - - result = xc_read_i2c_data(priv, buf, 2); - if (result != XC_RESULT_SUCCESS) - return result; - - *i2cData = buf[0] * 256 + buf[1]; - return result; -} - -static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[]) -{ - struct xc5000_priv *priv = fe->tuner_priv; - - int i, nbytes_to_send, result; - unsigned int len, pos, index; - u8 buf[XC_MAX_I2C_WRITE_LENGTH]; - - index=0; - while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { - len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; - if (len == 0x0000) { - /* RESET command */ - result = xc_reset(fe); - index += 2; - if (result != XC_RESULT_SUCCESS) - return result; - } else if (len & 0x8000) { - /* WAIT command */ - xc_wait(len & 0x7FFF); - index += 2; - } else { - /* Send i2c data whilst ensuring individual transactions - * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. - */ - index += 2; - buf[0] = i2c_sequence[index]; - buf[1] = i2c_sequence[index + 1]; - pos = 2; - while (pos < len) { - if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) { - nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH; - } else { - nbytes_to_send = (len - pos + 2); - } - for (i=2; ivideo_standard].Name); - - ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); - if (ret == XC_RESULT_SUCCESS) - ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); - - return ret; -} - -static int xc_shutdown(struct xc5000_priv *priv) -{ - return 0; - /* Fixme: cannot bring tuner back alive once shutdown - * without reloading the driver modules. - * return xc_write_reg(priv, XREG_POWER_DOWN, 0); - */ -} - -static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) -{ - dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode, - rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); - - if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) - { - rf_mode = XC_RF_MODE_CABLE; - printk(KERN_ERR - "%s(), Invalid mode, defaulting to CABLE", - __FUNCTION__); - } - return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); -} - -static const struct dvb_tuner_ops xc5000_tuner_ops; - -static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) -{ - u16 freq_code; - - dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); - - if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || - (freq_hz < xc5000_tuner_ops.info.frequency_min)) - return XC_RESULT_OUT_OF_RANGE; - - freq_code = (u16)(freq_hz / 15625); - - return xc_write_reg(priv, XREG_RF_FREQ, freq_code); -} - - -static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) -{ - u32 freq_code = (freq_khz * 1024)/1000; - dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", - __FUNCTION__, freq_khz, freq_code); - - return xc_write_reg(priv, XREG_IF_OUT, freq_code); -} - - -static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) -{ - return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope); -} - -static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) -{ - int result; - u16 regData; - u32 tmp; - - result = xc_read_reg(priv, XREG_FREQ_ERROR, ®Data); - if (result) - return result; - - tmp = (u32)regData; - (*freq_error_hz) = (tmp * 15625) / 1000; - return result; -} - -static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) -{ - return xc_read_reg(priv, XREG_LOCK, lock_status); -} - -static int xc_get_version(struct xc5000_priv *priv, - u8 *hw_majorversion, u8 *hw_minorversion, - u8 *fw_majorversion, u8 *fw_minorversion) -{ - u16 data; - int result; - - result = xc_read_reg(priv, XREG_VERSION, &data); - if (result) - return result; - - (*hw_majorversion) = (data >> 12) & 0x0F; - (*hw_minorversion) = (data >> 8) & 0x0F; - (*fw_majorversion) = (data >> 4) & 0x0F; - (*fw_minorversion) = data & 0x0F; - - return 0; -} - -static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) -{ - u16 regData; - int result; - - result = xc_read_reg(priv, XREG_HSYNC_FREQ, ®Data); - if (result) - return result; - - (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; - return result; -} - -static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) -{ - return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines); -} - -static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) -{ - return xc_read_reg(priv, XREG_QUALITY, quality); -} - -static u16 WaitForLock(struct xc5000_priv *priv) -{ - u16 lockState = 0; - int watchDogCount = 40; - - while ((lockState == 0) && (watchDogCount > 0)) { - xc_get_lock_status(priv, &lockState); - if (lockState != 1) { - xc_wait(5); - watchDogCount--; - } - } - return lockState; -} - -static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) -{ - int found = 0; - - dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); - - if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) - return 0; - - if (WaitForLock(priv) == 1) - found = 1; - - return found; -} - -static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) -{ - u8 buf[2] = { reg >> 8, reg & 0xff }; - u8 bval[2] = { 0, 0 }; - struct i2c_msg msg[2] = { - { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = &buf[0], .len = 2 }, - { .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, - }; - - if (i2c_transfer(priv->i2c, msg, 2) != 2) { - printk(KERN_WARNING "xc5000: I2C read failed\n"); - return -EREMOTEIO; - } - - *val = (bval[0] << 8) | bval[1]; - return 0; -} - -static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, - .flags = 0, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", - (int)len); - return -EREMOTEIO; - } - return 0; -} - -static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) -{ - struct i2c_msg msg = { .addr = priv->cfg->i2c_address, - .flags = I2C_M_RD, .buf = buf, .len = len }; - - if (i2c_transfer(priv->i2c, &msg, 1) != 1) { - printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len); - return -EREMOTEIO; - } - return 0; -} - -static int xc5000_fwupload(struct dvb_frontend* fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - const struct firmware *fw; - int ret; - - /* request the firmware, this will block and timeout */ - printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", - XC5000_DEFAULT_FIRMWARE); - - ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev); - if (ret) { - printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); - ret = XC_RESULT_RESET_FAILURE; - goto out; - } else { - printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n", - fw->size); - ret = XC_RESULT_SUCCESS; - } - - if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { - printk(KERN_ERR "xc5000: firmware incorrect size\n"); - ret = XC_RESULT_RESET_FAILURE; - } else { - printk(KERN_INFO "xc5000: firmware upload\n"); - ret = xc_load_i2c_sequence(fe, fw->data ); - } - -out: - release_firmware(fw); - return ret; -} - -static void xc_debug_dump(struct xc5000_priv *priv) -{ - u16 adc_envelope; - u32 freq_error_hz = 0; - u16 lock_status; - u32 hsync_freq_hz = 0; - u16 frame_lines; - u16 quality; - u8 hw_majorversion = 0, hw_minorversion = 0; - u8 fw_majorversion = 0, fw_minorversion = 0; - - /* Wait for stats to stabilize. - * Frame Lines needs two frame times after initial lock - * before it is valid. - */ - xc_wait(100); - - xc_get_ADC_Envelope(priv, &adc_envelope); - dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); - - xc_get_frequency_error(priv, &freq_error_hz); - dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); - - xc_get_lock_status(priv, &lock_status); - dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", - lock_status); - - xc_get_version(priv, &hw_majorversion, &hw_minorversion, - &fw_majorversion, &fw_minorversion); - dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", - hw_majorversion, hw_minorversion, - fw_majorversion, fw_minorversion); - - xc_get_hsync_freq(priv, &hsync_freq_hz); - dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); - - xc_get_frame_lines(priv, &frame_lines); - dprintk(1, "*** Frame lines = %d\n", frame_lines); - - xc_get_quality(priv, &quality); - dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); -} - -static int xc5000_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency); - - switch(params->u.vsb.modulation) { - case VSB_8: - case VSB_16: - dprintk(1, "%s() VSB modulation\n", __FUNCTION__); - priv->rf_mode = XC_RF_MODE_AIR; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - dprintk(1, "%s() QAM modulation\n", __FUNCTION__); - priv->rf_mode = XC_RF_MODE_CABLE; - priv->freq_hz = params->frequency - 1750000; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->video_standard = DTV6; - break; - default: - return -EINVAL; - } - - dprintk(1, "%s() frequency=%d (compensated)\n", - __FUNCTION__, priv->freq_hz); - - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - ret = xc_set_IF_frequency(priv, priv->cfg->if_khz); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", - priv->cfg->if_khz); - return -EIO; - } - - xc_tune_channel(priv, priv->freq_hz); - - if (debug) - xc_debug_dump(priv); - - return 0; -} - -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); - -static int xc5000_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - if(priv->fwloaded == 0) - xc_load_fw_and_init_tuner(fe); - - dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", - __FUNCTION__, params->frequency); - - priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */ - - /* params->frequency is in units of 62.5khz */ - priv->freq_hz = params->frequency * 62500; - - /* FIX ME: Some video standards may have several possible audio - standards. We simply default to one of them here. - */ - if(params->std & V4L2_STD_MN) { - /* default to BTSC audio standard */ - priv->video_standard = MN_NTSC_PAL_BTSC; - goto tune_channel; - } - - if(params->std & V4L2_STD_PAL_BG) { - /* default to NICAM audio standard */ - priv->video_standard = BG_PAL_NICAM; - goto tune_channel; - } - - if(params->std & V4L2_STD_PAL_I) { - /* default to NICAM audio standard */ - priv->video_standard = I_PAL_NICAM; - goto tune_channel; - } - - if(params->std & V4L2_STD_PAL_DK) { - /* default to NICAM audio standard */ - priv->video_standard = DK_PAL_NICAM; - goto tune_channel; - } - - if(params->std & V4L2_STD_SECAM_DK) { - /* default to A2 DK1 audio standard */ - priv->video_standard = DK_SECAM_A2DK1; - goto tune_channel; - } - - if(params->std & V4L2_STD_SECAM_L) { - priv->video_standard = L_SECAM_NICAM; - goto tune_channel; - } - - if(params->std & V4L2_STD_SECAM_LC) { - priv->video_standard = LC_SECAM_NICAM; - goto tune_channel; - } - -tune_channel: - ret = xc_SetSignalSource(priv, priv->rf_mode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: xc_SetSignalSource(%d) failed\n", - priv->rf_mode); - return -EREMOTEIO; - } - - ret = xc_SetTVStandard(priv, - XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); - if (ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); - return -EREMOTEIO; - } - - xc_tune_channel(priv, priv->freq_hz); - - if (debug) - xc_debug_dump(priv); - - return 0; -} - -static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __FUNCTION__); - *freq = priv->freq_hz; - return 0; -} - -static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __FUNCTION__); - - *bw = priv->bandwidth; - return 0; -} - -static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) -{ - struct xc5000_priv *priv = fe->tuner_priv; - u16 lock_status = 0; - - xc_get_lock_status(priv, &lock_status); - - dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status); - - *status = lock_status; - - return 0; -} - -static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret = 0; - - if (priv->fwloaded == 0) { - ret = xc5000_fwupload(fe); - if (ret != XC_RESULT_SUCCESS) - return ret; - priv->fwloaded = 1; - } - - /* Start the tuner self-calibration process */ - ret |= xc_initialize(priv); - - /* Wait for calibration to complete. - * We could continue but XC5000 will clock stretch subsequent - * I2C transactions until calibration is complete. This way we - * don't have to rely on clock stretching working. - */ - xc_wait( 100 ); - - /* Default to "CABLE" mode */ - ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); - - return ret; -} - -static int xc5000_sleep(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - int ret; - - dprintk(1, "%s()\n", __FUNCTION__); - - /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized - * once shutdown without reloading the driver. Maybe I am not - * doing something right. - * - */ - - ret = xc_shutdown(priv); - if(ret != XC_RESULT_SUCCESS) { - printk(KERN_ERR - "xc5000: %s() unable to shutdown tuner\n", - __FUNCTION__); - return -EREMOTEIO; - } - else { - /* priv->fwloaded = 0; */ - return XC_RESULT_SUCCESS; - } -} - -static int xc5000_init(struct dvb_frontend *fe) -{ - struct xc5000_priv *priv = fe->tuner_priv; - dprintk(1, "%s()\n", __FUNCTION__); - - if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { - printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); - return -EREMOTEIO; - } - - if (debug) - xc_debug_dump(priv); - - return 0; -} - -static int xc5000_release(struct dvb_frontend *fe) -{ - dprintk(1, "%s()\n", __FUNCTION__); - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - -static const struct dvb_tuner_ops xc5000_tuner_ops = { - .info = { - .name = "Xceive XC5000", - .frequency_min = 1000000, - .frequency_max = 1023000000, - .frequency_step = 50000, - }, - - .release = xc5000_release, - .init = xc5000_init, - .sleep = xc5000_sleep, - - .set_params = xc5000_set_params, - .set_analog_params = xc5000_set_analog_params, - .get_frequency = xc5000_get_frequency, - .get_bandwidth = xc5000_get_bandwidth, - .get_status = xc5000_get_status -}; - -struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct xc5000_config *cfg) -{ - struct xc5000_priv *priv = NULL; - u16 id = 0; - - dprintk(1, "%s()\n", __FUNCTION__); - - priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - - priv->cfg = cfg; - priv->bandwidth = BANDWIDTH_6_MHZ; - priv->i2c = i2c; - - /* Check if firmware has been loaded. It is possible that another - instance of the driver has loaded the firmware. - */ - if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { - kfree(priv); - return NULL; - } - - switch(id) { - case XC_PRODUCT_ID_FW_LOADED: - printk(KERN_INFO - "xc5000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc5000: Firmware has been loaded previously\n"); - priv->fwloaded = 1; - break; - case XC_PRODUCT_ID_FW_NOT_LOADED: - printk(KERN_INFO - "xc5000: Successfully identified at address 0x%02x\n", - cfg->i2c_address); - printk(KERN_INFO - "xc5000: Firmware has not been loaded previously\n"); - priv->fwloaded = 0; - break; - default: - printk(KERN_ERR - "xc5000: Device not found at addr 0x%02x (0x%x)\n", - cfg->i2c_address, id); - kfree(priv); - return NULL; - } - - memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - fe->tuner_priv = priv; - - return fe; -} -EXPORT_SYMBOL(xc5000_attach); - -MODULE_AUTHOR("Steven Toth"); -MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/media/dvb/frontends/xc5000.h b/trunk/drivers/media/dvb/frontends/xc5000.h deleted file mode 100644 index e0e84562aed1..000000000000 --- a/trunk/drivers/media/dvb/frontends/xc5000.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Steven Toth - * - * 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 __XC5000_H__ -#define __XC5000_H__ - -#include - -struct dvb_frontend; -struct i2c_adapter; - -struct xc5000_config { - u8 i2c_address; - u32 if_khz; - - /* For each bridge framework, when it attaches either analog or digital, - * it has to store a reference back to its _core equivalent structure, - * so that it can service the hardware by steering gpio's etc. - * Each bridge implementation is different so cast priv accordingly. - * The xc5000 driver cares not for this value, other than ensuring - * it's passed back to a bridge during tuner_callback(). - */ - void *priv; - int (*tuner_callback) (void *priv, int command, int arg); -}; - -/* xc5000 callback command */ -#define XC5000_TUNER_RESET 0 - -#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) -extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct xc5000_config *cfg); -#else -static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct xc5000_config *cfg) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; -} -#endif // CONFIG_DVB_TUNER_XC5000 - -#endif // __XC5000_H__ diff --git a/trunk/drivers/media/dvb/frontends/xc5000_priv.h b/trunk/drivers/media/dvb/frontends/xc5000_priv.h deleted file mode 100644 index 13b2d19341da..000000000000 --- a/trunk/drivers/media/dvb/frontends/xc5000_priv.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" - * - * Copyright (c) 2007 Steven Toth - * - * 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 XC5000_PRIV_H -#define XC5000_PRIV_H - -struct xc5000_priv { - struct xc5000_config *cfg; - struct i2c_adapter *i2c; - - u32 freq_hz; - u32 bandwidth; - u8 video_standard; - u8 rf_mode; - u8 fwloaded; -}; - -#endif diff --git a/trunk/drivers/media/dvb/frontends/zl10353.c b/trunk/drivers/media/dvb/frontends/zl10353.c index 276e3b631dc2..0106df4c55e8 100644 --- a/trunk/drivers/media/dvb/frontends/zl10353.c +++ b/trunk/drivers/media/dvb/frontends/zl10353.c @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006, 2007 Christopher Pascoe + * Copyright (C) 2006 Christopher Pascoe * * 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 @@ -16,7 +16,7 @@ * * 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. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= */ #include @@ -25,7 +25,6 @@ #include #include #include -#include #include "dvb_frontend.h" #include "zl10353_priv.h" @@ -36,8 +35,6 @@ struct zl10353_state { struct dvb_frontend frontend; struct zl10353_config config; - - enum fe_bandwidth bandwidth; }; static int debug; @@ -125,10 +122,9 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, enum fe_bandwidth bandwidth, u16 *nominal_rate) { - struct zl10353_state *state = fe->demodulator_priv; - u32 adc_clock = 450560; /* 45.056 MHz */ - u64 value; + u32 adc_clock = 45056; /* 45.056 MHz */ u8 bw; + struct zl10353_state *state = fe->demodulator_priv; if (state->config.adc_clock) adc_clock = state->config.adc_clock; @@ -146,44 +142,12 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, break; } - value = (u64)10 * (1 << 23) / 7 * 125; - value = (bw * value) + adc_clock / 2; - do_div(value, adc_clock); - *nominal_rate = value; + *nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock; dprintk("%s: bw %d, adc_clock %d => 0x%x\n", __FUNCTION__, bw, adc_clock, *nominal_rate); } -static void zl10353_calc_input_freq(struct dvb_frontend *fe, - u16 *input_freq) -{ - struct zl10353_state *state = fe->demodulator_priv; - u32 adc_clock = 450560; /* 45.056 MHz */ - int if2 = 361667; /* 36.1667 MHz */ - int ife; - u64 value; - - if (state->config.adc_clock) - adc_clock = state->config.adc_clock; - if (state->config.if2) - if2 = state->config.if2; - - if (adc_clock >= if2 * 2) - ife = if2; - else { - ife = adc_clock - (if2 % adc_clock); - if (ife > adc_clock / 2) - ife = adc_clock - ife; - } - value = (u64)65536 * ife + adc_clock / 2; - do_div(value, adc_clock); - *input_freq = -value; - - dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", - __FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq); -} - static int zl10353_sleep(struct dvb_frontend *fe) { static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 }; @@ -196,276 +160,64 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { struct zl10353_state *state = fe->demodulator_priv; - u16 nominal_rate, input_freq; - u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; - u16 tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + u16 nominal_rate; + u8 pllbuf[6] = { 0x67 }; - zl10353_single_write(fe, RESET, 0x80); + /* These settings set "auto-everything" and start the FSM. */ + zl10353_single_write(fe, 0x55, 0x80); udelay(200); zl10353_single_write(fe, 0xEA, 0x01); udelay(200); zl10353_single_write(fe, 0xEA, 0x00); - zl10353_single_write(fe, AGC_TARGET, 0x28); - - if (op->transmission_mode != TRANSMISSION_MODE_AUTO) - acq_ctl |= (1 << 0); - if (op->guard_interval != GUARD_INTERVAL_AUTO) - acq_ctl |= (1 << 1); - zl10353_single_write(fe, ACQ_CTL, acq_ctl); + zl10353_single_write(fe, 0x56, 0x28); + zl10353_single_write(fe, 0x89, 0x20); + zl10353_single_write(fe, 0x5E, 0x00); - switch (op->bandwidth) { - case BANDWIDTH_6_MHZ: - /* These are extrapolated from the 7 and 8MHz values */ - zl10353_single_write(fe, MCLK_RATIO, 0x97); - zl10353_single_write(fe, 0x64, 0x34); - break; - case BANDWIDTH_7_MHZ: - zl10353_single_write(fe, MCLK_RATIO, 0x86); - zl10353_single_write(fe, 0x64, 0x35); - break; - case BANDWIDTH_8_MHZ: - default: - zl10353_single_write(fe, MCLK_RATIO, 0x75); - zl10353_single_write(fe, 0x64, 0x36); - } - - zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); + zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate); zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); - state->bandwidth = op->bandwidth; - - zl10353_calc_input_freq(fe, &input_freq); - zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); - zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); - - /* Hint at TPS settings */ - switch (op->code_rate_HP) { - case FEC_2_3: - tps |= (1 << 7); - break; - case FEC_3_4: - tps |= (2 << 7); - break; - case FEC_5_6: - tps |= (3 << 7); - break; - case FEC_7_8: - tps |= (4 << 7); - break; - case FEC_1_2: - case FEC_AUTO: - break; - default: - return -EINVAL; - } - - switch (op->code_rate_LP) { - case FEC_2_3: - tps |= (1 << 4); - break; - case FEC_3_4: - tps |= (2 << 4); - break; - case FEC_5_6: - tps |= (3 << 4); - break; - case FEC_7_8: - tps |= (4 << 4); - break; - case FEC_1_2: - case FEC_AUTO: - break; - case FEC_NONE: - if (op->hierarchy_information == HIERARCHY_AUTO || - op->hierarchy_information == HIERARCHY_NONE) - break; - default: - return -EINVAL; - } - - switch (op->constellation) { - case QPSK: - break; - case QAM_AUTO: - case QAM_16: - tps |= (1 << 13); - break; - case QAM_64: - tps |= (2 << 13); - break; - default: - return -EINVAL; - } - - switch (op->transmission_mode) { - case TRANSMISSION_MODE_2K: - case TRANSMISSION_MODE_AUTO: - break; - case TRANSMISSION_MODE_8K: - tps |= (1 << 0); - break; - default: - return -EINVAL; - } - - switch (op->guard_interval) { - case GUARD_INTERVAL_1_32: - case GUARD_INTERVAL_AUTO: - break; - case GUARD_INTERVAL_1_16: - tps |= (1 << 2); - break; - case GUARD_INTERVAL_1_8: - tps |= (2 << 2); - break; - case GUARD_INTERVAL_1_4: - tps |= (3 << 2); - break; - default: - return -EINVAL; - } - - switch (op->hierarchy_information) { - case HIERARCHY_AUTO: - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - tps |= (1 << 10); - break; - case HIERARCHY_2: - tps |= (2 << 10); - break; - case HIERARCHY_4: - tps |= (3 << 10); - break; - default: - return -EINVAL; - } - - zl10353_single_write(fe, TPS_GIVEN_1, msb(tps)); - zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps)); + zl10353_single_write(fe, 0x6C, 0xCD); + zl10353_single_write(fe, 0x6D, 0x7E); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - /* - * If there is no tuner attached to the secondary I2C bus, we call - * set_params to program a potential tuner attached somewhere else. - * Otherwise, we update the PLL registers via calc_regs. - */ + // if there is no attached secondary tuner, we call set_params to program + // a potential tuner attached somewhere else if (state->config.no_tuner) { if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, param); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - } else if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5); - pllbuf[1] <<= 1; - zl10353_write(fe, pllbuf, sizeof(pllbuf)); } - zl10353_single_write(fe, 0x5F, 0x13); - - /* If no attached tuner or invalid PLL registers, just start the FSM. */ - if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL) - zl10353_single_write(fe, FSM_GO, 0x01); - else - zl10353_single_write(fe, TUNER_GO, 0x01); - - return 0; -} - -static int zl10353_get_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *param) -{ - struct zl10353_state *state = fe->demodulator_priv; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - int s6, s9; - u16 tps; - static const u8 tps_fec_to_api[8] = { - FEC_1_2, - FEC_2_3, - FEC_3_4, - FEC_5_6, - FEC_7_8, - FEC_AUTO, - FEC_AUTO, - FEC_AUTO - }; - - s6 = zl10353_read_register(state, STATUS_6); - s9 = zl10353_read_register(state, STATUS_9); - if (s6 < 0 || s9 < 0) - return -EREMOTEIO; - if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0) - return -EINVAL; /* no FE or TPS lock */ - - tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | - zl10353_read_register(state, TPS_RECEIVED_0); - - op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; - op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; - - switch ((tps >> 13) & 3) { - case 0: - op->constellation = QPSK; - break; - case 1: - op->constellation = QAM_16; - break; - case 2: - op->constellation = QAM_64; - break; - default: - op->constellation = QAM_AUTO; - break; - } - - op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : - TRANSMISSION_MODE_2K; - - switch ((tps >> 2) & 3) { - case 0: - op->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - op->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - op->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - op->guard_interval = GUARD_INTERVAL_1_4; - break; - default: - op->guard_interval = GUARD_INTERVAL_AUTO; - break; + // if pllbuf is defined, retrieve the settings + if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5); + pllbuf[1] <<= 1; + } else { + // fake pllbuf settings + pllbuf[1] = 0x61 << 1; + pllbuf[2] = 0; + pllbuf[3] = 0; + pllbuf[3] = 0; + pllbuf[4] = 0; } - switch ((tps >> 10) & 7) { - case 0: - op->hierarchy_information = HIERARCHY_NONE; - break; - case 1: - op->hierarchy_information = HIERARCHY_1; - break; - case 2: - op->hierarchy_information = HIERARCHY_2; - break; - case 3: - op->hierarchy_information = HIERARCHY_4; - break; - default: - op->hierarchy_information = HIERARCHY_AUTO; - break; - } + // there is no call to _just_ start decoding, so we send the pllbuf anyway + // even if there isn't a PLL attached to the secondary bus + zl10353_write(fe, pllbuf, sizeof(pllbuf)); - param->frequency = 0; - op->bandwidth = state->bandwidth; - param->inversion = INVERSION_AUTO; + zl10353_single_write(fe, 0x5F, 0x13); + zl10353_single_write(fe, 0x70, 0x01); + udelay(250); + zl10353_single_write(fe, 0xE4, 0x00); + zl10353_single_write(fe, 0xE5, 0x2A); + zl10353_single_write(fe, 0xE9, 0x02); + zl10353_single_write(fe, 0xE7, 0x40); + zl10353_single_write(fe, 0xE8, 0x10); return 0; } @@ -654,7 +406,6 @@ static struct dvb_frontend_ops zl10353_ops = { .write = zl10353_write, .set_frontend = zl10353_set_parameters, - .get_frontend = zl10353_get_parameters, .get_tune_settings = zl10353_get_tune_settings, .read_status = zl10353_read_status, diff --git a/trunk/drivers/media/dvb/frontends/zl10353.h b/trunk/drivers/media/dvb/frontends/zl10353.h index fc734c22b5fa..1c3d494a6da9 100644 --- a/trunk/drivers/media/dvb/frontends/zl10353.h +++ b/trunk/drivers/media/dvb/frontends/zl10353.h @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006, 2007 Christopher Pascoe + * Copyright (C) 2006 Christopher Pascoe * * 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 @@ -29,9 +29,8 @@ struct zl10353_config /* demodulator's I2C address */ u8 demod_address; - /* frequencies in units of 0.1kHz */ - int adc_clock; /* default: 450560 (45.056 MHz) */ - int if2; /* default: 361667 (36.1667 MHz) */ + /* frequencies in kHz */ + int adc_clock; /* default: 45056 */ /* set if no pll is connected to the secondary i2c bus */ int no_tuner; @@ -50,6 +49,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif /* CONFIG_DVB_ZL10353 */ +#endif // CONFIG_DVB_ZL10353 #endif /* ZL10353_H */ diff --git a/trunk/drivers/media/dvb/frontends/zl10353_priv.h b/trunk/drivers/media/dvb/frontends/zl10353_priv.h index 055ff1f7e349..4962434b35e7 100644 --- a/trunk/drivers/media/dvb/frontends/zl10353_priv.h +++ b/trunk/drivers/media/dvb/frontends/zl10353_priv.h @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006, 2007 Christopher Pascoe + * Copyright (C) 2006 Christopher Pascoe * * 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 @@ -16,7 +16,7 @@ * * 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. + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= */ #ifndef _ZL10353_PRIV_ @@ -46,28 +46,9 @@ enum zl10353_reg_addr { RS_ERR_CNT_0 = 0x13, RS_UBC_1 = 0x14, RS_UBC_0 = 0x15, - TPS_RECEIVED_1 = 0x1D, - TPS_RECEIVED_0 = 0x1E, - TPS_CURRENT_1 = 0x1F, - TPS_CURRENT_0 = 0x20, - RESET = 0x55, - AGC_TARGET = 0x56, - MCLK_RATIO = 0x5C, - ACQ_CTL = 0x5E, TRL_NOMINAL_RATE_1 = 0x65, TRL_NOMINAL_RATE_0 = 0x66, - INPUT_FREQ_1 = 0x6C, - INPUT_FREQ_0 = 0x6D, - TPS_GIVEN_1 = 0x6E, - TPS_GIVEN_0 = 0x6F, - TUNER_GO = 0x70, - FSM_GO = 0x71, CHIP_ID = 0x7F, - CHAN_STEP_1 = 0xE4, - CHAN_STEP_0 = 0xE5, - OFDM_LOCK_TIME = 0xE7, - FEC_LOCK_TIME = 0xE8, - ACQ_DELAY = 0xE9, }; #endif /* _ZL10353_PRIV_ */ diff --git a/trunk/drivers/media/dvb/ttpci/Kconfig b/trunk/drivers/media/dvb/ttpci/Kconfig index ae882432dd3d..54b91f26ca63 100644 --- a/trunk/drivers/media/dvb/ttpci/Kconfig +++ b/trunk/drivers/media/dvb/ttpci/Kconfig @@ -1,14 +1,8 @@ -config TTPCI_EEPROM - tristate - default n - config DVB_AV7110 tristate "AV7110 cards" - depends on DVB_CORE && PCI && I2C + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select FW_LOADER if !DVB_AV7110_FIRMWARE - select TTPCI_EEPROM select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE @@ -63,19 +57,10 @@ config DVB_AV7110_OSD All other people say N. -config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" - depends on DVB_CORE && PCI && I2C - select VIDEO_SAA7146 - select TTPCI_EEPROM - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. - config DVB_BUDGET tristate "Budget cards" - depends on DVB_BUDGET_CORE && I2C + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + select VIDEO_SAA7146 select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_VES1820 if !DVB_FE_CUSTOMISE @@ -88,9 +73,9 @@ config DVB_BUDGET select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE help - Support for simple SAA7146 based DVB cards (so called Budget- - or Nova-PCI cards) without onboard MPEG2 decoder, and without - analog inputs or an onboard Common Interface connector. + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder. Say Y if you own such a card and want to use it. @@ -99,7 +84,8 @@ config DVB_BUDGET config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" - depends on DVB_BUDGET_CORE && I2C + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT + select VIDEO_SAA7146 select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -120,9 +106,8 @@ config DVB_BUDGET_CI config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" - depends on DVB_BUDGET_CORE && I2C + depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -142,8 +127,8 @@ config DVB_BUDGET_AV config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" - depends on DVB_BUDGET_CORE && I2C - depends on DVB_AV7110 + depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 + select DVB_AV7110 select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE diff --git a/trunk/drivers/media/dvb/ttpci/Makefile b/trunk/drivers/media/dvb/ttpci/Makefile index d7483f1a9b3f..2c1145236ee6 100644 --- a/trunk/drivers/media/dvb/ttpci/Makefile +++ b/trunk/drivers/media/dvb/ttpci/Makefile @@ -5,13 +5,11 @@ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o -obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o -obj-$(CONFIG_DVB_BUDGET) += budget.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o +obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/trunk/drivers/media/dvb/ttpci/av7110.c b/trunk/drivers/media/dvb/ttpci/av7110.c index 0e5701bdff19..0d36c155695b 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110.c +++ b/trunk/drivers/media/dvb/ttpci/av7110.c @@ -2595,8 +2595,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, mutex_init(&av7110->osd_mutex); /* TV standard */ - av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC - : AV7110_VIDEO_MODE_PAL; + av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; /* ARM "watchdog" */ init_waitqueue_head(&av7110->arm_wait); diff --git a/trunk/drivers/media/dvb/ttpci/av7110.h b/trunk/drivers/media/dvb/ttpci/av7110.h index 39fbf7d5cffb..0cb439527498 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110.h +++ b/trunk/drivers/media/dvb/ttpci/av7110.h @@ -46,11 +46,6 @@ extern int av7110_debug; enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; -enum av7110_video_mode { - AV7110_VIDEO_MODE_PAL = 0, - AV7110_VIDEO_MODE_NTSC = 1 -}; - struct av7110_p2t { u8 pes[TS_SIZE]; u8 counter; @@ -175,7 +170,7 @@ struct av7110 { ca_slot_info_t ci_slot[2]; - enum av7110_video_mode vidmode; + int vidmode; struct dmxdev dmxdev; struct dvb_demux demux; diff --git a/trunk/drivers/media/dvb/ttpci/av7110_av.c b/trunk/drivers/media/dvb/ttpci/av7110_av.c index aef6e36d7c5c..d75e7e48addc 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_av.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_av.c @@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) return 0; } -int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) +int av7110_set_vidmode(struct av7110 *av7110, int mode) { int ret; dprintk(2, "av7110:%p, \n", av7110); @@ -348,15 +348,11 @@ int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) } -static enum av7110_video_mode sw2mode[16] = { - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, - AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, +static int sw2mode[16] = { + VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, + VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, + VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, + VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, }; static int get_video_format(struct av7110 *av7110, u8 *buf, int count) diff --git a/trunk/drivers/media/dvb/ttpci/av7110_av.h b/trunk/drivers/media/dvb/ttpci/av7110_av.h index 5f02ef85e47d..45dc144b8b43 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_av.h +++ b/trunk/drivers/media/dvb/ttpci/av7110_av.h @@ -3,8 +3,7 @@ struct av7110; -extern int av7110_set_vidmode(struct av7110 *av7110, - enum av7110_video_mode mode); +extern int av7110_set_vidmode(struct av7110 *av7110, int mode); extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); diff --git a/trunk/drivers/media/dvb/ttpci/av7110_v4l.c b/trunk/drivers/media/dvb/ttpci/av7110_v4l.c index e2f066fb7967..76cca003252f 100644 --- a/trunk/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/trunk/drivers/media/dvb/ttpci/av7110_v4l.c @@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) struct av7110 *av7110 = (struct av7110*) dev->ext_priv; if (std->id & V4L2_STD_PAL) { - av7110->vidmode = AV7110_VIDEO_MODE_PAL; + av7110->vidmode = VIDEO_MODE_PAL; av7110_set_vidmode(av7110, av7110->vidmode); } else if (std->id & V4L2_STD_NTSC) { - av7110->vidmode = AV7110_VIDEO_MODE_NTSC; + av7110->vidmode = VIDEO_MODE_NTSC; av7110_set_vidmode(av7110, av7110->vidmode); } else diff --git a/trunk/drivers/media/radio/Kconfig b/trunk/drivers/media/radio/Kconfig index 8d5214f18cf0..11e962f1a97f 100644 --- a/trunk/drivers/media/radio/Kconfig +++ b/trunk/drivers/media/radio/Kconfig @@ -351,14 +351,4 @@ config USB_DSBR To compile this driver as a module, choose M here: the module will be called dsbr100. -config USB_SI470X - tristate "Silicon Labs Si470x FM Radio Receiver support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called radio-silabs. - endif # RADIO_ADAPTERS diff --git a/trunk/drivers/media/radio/Makefile b/trunk/drivers/media/radio/Makefile index a30159f6fa42..cf55a18e3ddf 100644 --- a/trunk/drivers/media/radio/Makefile +++ b/trunk/drivers/media/radio/Makefile @@ -21,6 +21,5 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o obj-$(CONFIG_USB_DSBR) += dsbr100.o -obj-$(CONFIG_USB_SI470X) += radio-si470x.o EXTRA_CFLAGS += -Isound diff --git a/trunk/drivers/media/radio/dsbr100.c b/trunk/drivers/media/radio/dsbr100.c index 36c0e3651502..3bd07f7e3774 100644 --- a/trunk/drivers/media/radio/dsbr100.c +++ b/trunk/drivers/media/radio/dsbr100.c @@ -33,9 +33,6 @@ History: - Version 0.43: - Oliver Neukum: avoided DMA coherency issue - Version 0.42: Converted dsbr100 to use video_ioctl2 by Douglas Landgraf @@ -138,7 +135,7 @@ module_param(radio_nr, int, 0); struct dsbr100_device { struct usb_device *usbdev; struct video_device *videodev; - u8 *transfer_buffer; + unsigned char transfer_buffer[TB_LEN]; int curfreq; int stereo; int users; @@ -240,7 +237,10 @@ static void dsbr100_getstat(struct dsbr100_device *radio) /* handle unplugging of the device, release data structures if nothing keeps us from doing it. If something is still keeping us busy, the release callback of v4l will take care -of releasing it. */ +of releasing it. stv680.c does not relase its private +data, so I don't do this here either. Checking out the +code I'd expect I better did that, but if there's a memory +leak here it's tiny (~50 bytes per disconnect) */ static void usb_dsbr100_disconnect(struct usb_interface *intf) { struct dsbr100_device *radio = usb_get_intfdata(intf); @@ -250,7 +250,6 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf) video_unregister_device(radio->videodev); radio->videodev = NULL; if (radio->users) { - kfree(radio->transfer_buffer); kfree(radio); } else { radio->removed = 1; @@ -426,7 +425,6 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file) return -ENODEV; radio->users = 0; if (radio->removed) { - kfree(radio->transfer_buffer); kfree(radio); } return 0; @@ -473,12 +471,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL))) return -ENOMEM; - if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) { - kfree(radio); - return -ENOMEM; - } if (!(radio->videodev = video_device_alloc())) { - kfree(radio->transfer_buffer); kfree(radio); return -ENOMEM; } @@ -492,7 +485,6 @@ static int usb_dsbr100_probe(struct usb_interface *intf, if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) { warn("Could not register video device"); video_device_release(radio->videodev); - kfree(radio->transfer_buffer); kfree(radio); return -EIO; } diff --git a/trunk/drivers/media/radio/radio-gemtek.c b/trunk/drivers/media/radio/radio-gemtek.c index 246422b49267..5e4b9ddb23c0 100644 --- a/trunk/drivers/media/radio/radio-gemtek.c +++ b/trunk/drivers/media/radio/radio-gemtek.c @@ -58,10 +58,10 @@ static int initmute = 1; static int radio_nr = -1; module_param(io, int, 0444); -MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic" "probing is disabled or fails. The most common I/O ports are: 0x20c " "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " - "work for the combined sound/radiocard)."); + " work for the combined sound/radiocard)."); module_param(probe, bool, 0444); MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " @@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = { } }; -static const struct file_operations gemtek_fops = { +static struct file_operations gemtek_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/trunk/drivers/media/radio/radio-maestro.c b/trunk/drivers/media/radio/radio-maestro.c index bc51f4d23a5a..8e33a19a22a3 100644 --- a/trunk/drivers/media/radio/radio-maestro.c +++ b/trunk/drivers/media/radio/radio-maestro.c @@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev, errunr: video_unregister_device(maestro_radio_inst); errfr1: - video_device_release(maestro_radio_inst); + kfree(maestro_radio_inst); errfr: kfree(radio_unit); err: diff --git a/trunk/drivers/media/radio/radio-sf16fmi.c b/trunk/drivers/media/radio/radio-sf16fmi.c index 3118bdab3183..395165367f37 100644 --- a/trunk/drivers/media/radio/radio-sf16fmi.c +++ b/trunk/drivers/media/radio/radio-sf16fmi.c @@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = { MODULE_DEVICE_TABLE(isapnp, id_table); -static int __init isapnp_fmi_probe(void) +static int isapnp_fmi_probe(void) { int i = 0; diff --git a/trunk/drivers/media/radio/radio-sf16fmr2.c b/trunk/drivers/media/radio/radio-sf16fmr2.c index f7c8b000404f..c432c44bd634 100644 --- a/trunk/drivers/media/radio/radio-sf16fmr2.c +++ b/trunk/drivers/media/radio/radio-sf16fmr2.c @@ -476,7 +476,8 @@ static int __init fmr2_init(void) return -EBUSY; } - if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { + if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1) + { release_region(io, 2); return -EINVAL; } diff --git a/trunk/drivers/media/radio/radio-si470x.c b/trunk/drivers/media/radio/radio-si470x.c deleted file mode 100644 index 8e4bd4769048..000000000000 --- a/trunk/drivers/media/radio/radio-si470x.c +++ /dev/null @@ -1,1432 +0,0 @@ -/* - * drivers/media/radio/radio-si470x.c - * - * Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers: - * - Silicon Labs USB FM Radio Reference Design - * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) - * - * Copyright (c) 2008 Tobias Lorenz - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -/* - * History: - * 2008-01-12 Tobias Lorenz - * Version 1.0.0 - * - First working version - * 2008-01-13 Tobias Lorenz - * Version 1.0.1 - * - Improved error handling, every function now returns errno - * - Improved multi user access (start/mute/stop) - * - Channel doesn't get lost anymore after start/mute/stop - * - RDS support added (polling mode via interrupt EP 1) - * - marked default module parameters with *value* - * - switched from bit structs to bit masks - * - header file cleaned and integrated - * 2008-01-14 Tobias Lorenz - * Version 1.0.2 - * - hex values are now lower case - * - commented USB ID for ADS/Tech moved on todo list - * - blacklisted si470x in hid-quirks.c - * - rds buffer handling functions integrated into *_work, *_read - * - rds_command in si470x_poll exchanged against simple retval - * - check for firmware version 15 - * - code order and prototypes still remain the same - * - spacing and bottom of band codes remain the same - * 2008-01-16 Tobias Lorenz - * Version 1.0.3 - * - code reordered to avoid function prototypes - * - switch/case defaults are now more user-friendly - * - unified comment style - * - applied all checkpatch.pl v1.12 suggestions - * except the warning about the too long lines with bit comments - * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) - * 2008-01-22 Tobias Lorenz - * Version 1.0.4 - * - avoid poss. locking when doing copy_to_user which may sleep - * - RDS is automatically activated on read now - * - code cleaned of unnecessary rds_commands - * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified - * (thanks to Guillaume RAMOUSSE) - * - * ToDo: - * - add seeking support - * - add firmware download/update support - * - RDS support: interrupt mode, instead of polling - * - add LED status output (check if that's not already done in firmware) - */ - - -/* driver definitions */ -#define DRIVER_AUTHOR "Tobias Lorenz " -#define DRIVER_NAME "radio-si470x" -#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4) -#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" -#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" - - -/* kernel includes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* USB Device ID List */ -static struct usb_device_id si470x_usb_driver_id_table[] = { - /* Silicon Labs USB FM Radio Reference Design */ - { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, - /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, - /* Terminating entry */ - { } -}; -MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); - - - -/************************************************************************** - * Module Parameters - **************************************************************************/ - -/* Radio Nr */ -static int radio_nr = -1; -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, "Radio Nr"); - -/* Spacing (kHz) */ -/* 0: 200 kHz (USA, Australia) */ -/* 1: 100 kHz (Europe, Japan) */ -/* 2: 50 kHz */ -static int space = 2; -module_param(space, int, 0); -MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); - -/* Bottom of Band (MHz) */ -/* 0: 87.5 - 108 MHz (USA, Europe)*/ -/* 1: 76 - 108 MHz (Japan wide band) */ -/* 2: 76 - 90 MHz (Japan) */ -static int band = 1; -module_param(band, int, 0); -MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); - -/* De-emphasis */ -/* 0: 75 us (USA) */ -/* 1: 50 us (Europe, Australia, Japan) */ -static int de = 1; -module_param(de, int, 0); -MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*"); - -/* USB timeout */ -static int usb_timeout = 500; -module_param(usb_timeout, int, 0); -MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*"); - -/* Seek retries */ -static int seek_retries = 100; -module_param(seek_retries, int, 0); -MODULE_PARM_DESC(seek_retries, "Seek retries: *100*"); - -/* RDS buffer blocks */ -static int rds_buf = 100; -module_param(rds_buf, int, 0); -MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); - -/* RDS maximum block errors */ -static int max_rds_errors = 1; -/* 0 means 0 errors requiring correction */ -/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ -/* 2 means 3-5 errors requiring correction */ -/* 3 means 6+ errors or errors in checkword, correction not possible */ -module_param(max_rds_errors, int, 0); -MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); - -/* RDS poll frequency */ -static int rds_poll_time = 40; -/* 40 is used by the original USBRadio.exe */ -/* 50 is used by radio-cadet */ -/* 75 should be okay */ -/* 80 is the usual RDS receive interval */ -module_param(rds_poll_time, int, 0); -MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); - - - -/************************************************************************** - * Register Definitions - **************************************************************************/ -#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ -#define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ -#define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ - -#define DEVICEID 0 /* Device ID */ -#define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */ -#define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */ - -#define CHIPID 1 /* Chip ID */ -#define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ -#define CHIPID_DEV 0x0200 /* bits 09..09: Device */ -#define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ - -#define POWERCFG 2 /* Power Configuration */ -#define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */ -#define POWERCFG_DMUTE 0x4000 /* bits 14..14: Mute Disable */ -#define POWERCFG_MONO 0x2000 /* bits 13..13: Mono Select */ -#define POWERCFG_RDSM 0x0800 /* bits 11..11: RDS Mode (Si4701 only) */ -#define POWERCFG_SKMODE 0x0400 /* bits 10..10: Seek Mode */ -#define POWERCFG_SEEKUP 0x0200 /* bits 09..09: Seek Direction */ -#define POWERCFG_SEEK 0x0100 /* bits 08..08: Seek */ -#define POWERCFG_DISABLE 0x0040 /* bits 06..06: Powerup Disable */ -#define POWERCFG_ENABLE 0x0001 /* bits 00..00: Powerup Enable */ - -#define CHANNEL 3 /* Channel */ -#define CHANNEL_TUNE 0x8000 /* bits 15..15: Tune */ -#define CHANNEL_CHAN 0x03ff /* bits 09..00: Channel Select */ - -#define SYSCONFIG1 4 /* System Configuration 1 */ -#define SYSCONFIG1_RDSIEN 0x8000 /* bits 15..15: RDS Interrupt Enable (Si4701 only) */ -#define SYSCONFIG1_STCIEN 0x4000 /* bits 14..14: Seek/Tune Complete Interrupt Enable */ -#define SYSCONFIG1_RDS 0x1000 /* bits 12..12: RDS Enable (Si4701 only) */ -#define SYSCONFIG1_DE 0x0800 /* bits 11..11: De-emphasis (0=75us 1=50us) */ -#define SYSCONFIG1_AGCD 0x0400 /* bits 10..10: AGC Disable */ -#define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ -#define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ -#define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ -#define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ - -#define SYSCONFIG2 5 /* System Configuration 2 */ -#define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */ -#define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */ -#define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */ -#define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */ - -#define SYSCONFIG3 6 /* System Configuration 3 */ -#define SYSCONFIG3_SMUTER 0xc000 /* bits 15..14: Softmute Attack/Recover Rate */ -#define SYSCONFIG3_SMUTEA 0x3000 /* bits 13..12: Softmute Attenuation */ -#define SYSCONFIG3_SKSNR 0x00f0 /* bits 07..04: Seek SNR Threshold */ -#define SYSCONFIG3_SKCNT 0x000f /* bits 03..00: Seek FM Impulse Detection Threshold */ - -#define TEST1 7 /* Test 1 */ -#define TEST1_AHIZEN 0x4000 /* bits 14..14: Audio High-Z Enable */ - -#define TEST2 8 /* Test 2 */ -/* TEST2 only contains reserved bits */ - -#define BOOTCONFIG 9 /* Boot Configuration */ -/* BOOTCONFIG only contains reserved bits */ - -#define STATUSRSSI 10 /* Status RSSI */ -#define STATUSRSSI_RDSR 0x8000 /* bits 15..15: RDS Ready (Si4701 only) */ -#define STATUSRSSI_STC 0x4000 /* bits 14..14: Seek/Tune Complete */ -#define STATUSRSSI_SF 0x2000 /* bits 13..13: Seek Fail/Band Limit */ -#define STATUSRSSI_AFCRL 0x1000 /* bits 12..12: AFC Rail */ -#define STATUSRSSI_RDSS 0x0800 /* bits 11..11: RDS Synchronized (Si4701 only) */ -#define STATUSRSSI_BLERA 0x0600 /* bits 10..09: RDS Block A Errors (Si4701 only) */ -#define STATUSRSSI_ST 0x0100 /* bits 08..08: Stereo Indicator */ -#define STATUSRSSI_RSSI 0x00ff /* bits 07..00: RSSI (Received Signal Strength Indicator) */ - -#define READCHAN 11 /* Read Channel */ -#define READCHAN_BLERB 0xc000 /* bits 15..14: RDS Block D Errors (Si4701 only) */ -#define READCHAN_BLERC 0x3000 /* bits 13..12: RDS Block C Errors (Si4701 only) */ -#define READCHAN_BLERD 0x0c00 /* bits 11..10: RDS Block B Errors (Si4701 only) */ -#define READCHAN_READCHAN 0x03ff /* bits 09..00: Read Channel */ - -#define RDSA 12 /* RDSA */ -#define RDSA_RDSA 0xffff /* bits 15..00: RDS Block A Data (Si4701 only) */ - -#define RDSB 13 /* RDSB */ -#define RDSB_RDSB 0xffff /* bits 15..00: RDS Block B Data (Si4701 only) */ - -#define RDSC 14 /* RDSC */ -#define RDSC_RDSC 0xffff /* bits 15..00: RDS Block C Data (Si4701 only) */ - -#define RDSD 15 /* RDSD */ -#define RDSD_RDSD 0xffff /* bits 15..00: RDS Block D Data (Si4701 only) */ - - - -/************************************************************************** - * USB HID Reports - **************************************************************************/ - -/* Reports 1-16 give direct read/write access to the 16 Si470x registers */ -/* with the (REPORT_ID - 1) corresponding to the register address across USB */ -/* endpoint 0 using GET_REPORT and SET_REPORT */ -#define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1) -#define REGISTER_REPORT(reg) ((reg) + 1) - -/* Report 17 gives direct read/write access to the entire Si470x register */ -/* map across endpoint 0 using GET_REPORT and SET_REPORT */ -#define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) -#define ENTIRE_REPORT 17 - -/* Report 18 is used to send the lowest 6 Si470x registers up the HID */ -/* interrupt endpoint 1 to Windows every 20 milliseconds for status */ -#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) -#define RDS_REPORT 18 - -/* Report 19: LED state */ -#define LED_REPORT_SIZE 3 -#define LED_REPORT 19 - -/* Report 19: stream */ -#define STREAM_REPORT_SIZE 3 -#define STREAM_REPORT 19 - -/* Report 20: scratch */ -#define SCRATCH_PAGE_SIZE 63 -#define SCRATCH_REPORT_SIZE (SCRATCH_PAGE_SIZE + 1) -#define SCRATCH_REPORT 20 - -/* Reports 19-22: flash upgrade of the C8051F321 */ -#define WRITE_REPORT 19 -#define FLASH_REPORT 20 -#define CRC_REPORT 21 -#define RESPONSE_REPORT 22 - -/* Report 23: currently unused, but can accept 60 byte reports on the HID */ -/* interrupt out endpoint 2 every 1 millisecond */ -#define UNUSED_REPORT 23 - - - -/************************************************************************** - * Software/Hardware Versions - **************************************************************************/ -#define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 -#define RADIO_SW_VERSION 7 -#define RADIO_SW_VERSION_CURRENT 15 -#define RADIO_HW_VERSION 1 - -#define SCRATCH_PAGE_SW_VERSION 1 -#define SCRATCH_PAGE_HW_VERSION 2 - - - -/************************************************************************** - * LED State Definitions - **************************************************************************/ -#define LED_COMMAND 0x35 - -#define NO_CHANGE_LED 0x00 -#define ALL_COLOR_LED 0x01 /* streaming state */ -#define BLINK_GREEN_LED 0x02 /* connect state */ -#define BLINK_RED_LED 0x04 -#define BLINK_ORANGE_LED 0x10 /* disconnect state */ -#define SOLID_GREEN_LED 0x20 /* tuning/seeking state */ -#define SOLID_RED_LED 0x40 /* bootload state */ -#define SOLID_ORANGE_LED 0x80 - - - -/************************************************************************** - * Stream State Definitions - **************************************************************************/ -#define STREAM_COMMAND 0x36 -#define STREAM_VIDPID 0x00 -#define STREAM_AUDIO 0xff - - - -/************************************************************************** - * Bootloader / Flash Commands - **************************************************************************/ - -/* unique id sent to bootloader and required to put into a bootload state */ -#define UNIQUE_BL_ID 0x34 - -/* mask for the flash data */ -#define FLASH_DATA_MASK 0x55 - -/* bootloader commands */ -#define GET_SW_VERSION_COMMAND 0x00 -#define SET_PAGE_COMMAND 0x01 -#define ERASE_PAGE_COMMAND 0x02 -#define WRITE_PAGE_COMMAND 0x03 -#define CRC_ON_PAGE_COMMAND 0x04 -#define READ_FLASH_BYTE_COMMAND 0x05 -#define RESET_DEVICE_COMMAND 0x06 -#define GET_HW_VERSION_COMMAND 0x07 -#define BLANK 0xff - -/* bootloader command responses */ -#define COMMAND_OK 0x01 -#define COMMAND_FAILED 0x02 -#define COMMAND_PENDING 0x03 - -/* buffer sizes */ -#define COMMAND_BUFFER_SIZE 4 -#define RESPONSE_BUFFER_SIZE 2 -#define FLASH_BUFFER_SIZE 64 -#define CRC_BUFFER_SIZE 3 - - - -/************************************************************************** - * General Driver Definitions - **************************************************************************/ - -/* - * si470x_device - private data - */ -struct si470x_device { - /* reference to USB and video device */ - struct usb_device *usbdev; - struct video_device *videodev; - - /* are these really necessary ? */ - int users; - - /* report buffer (maximum 64 bytes) */ - unsigned char buf[64]; - - /* Silabs internal registers (0..15) */ - unsigned short registers[RADIO_REGISTER_NUM]; - - /* RDS receive buffer */ - struct work_struct work; - wait_queue_head_t read_queue; - struct timer_list timer; - spinlock_t lock; /* buffer locking */ - unsigned char *buffer; /* size is always multiple of three */ - unsigned int buf_size; - unsigned int rd_index; - unsigned int wr_index; -}; - - -/* - * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, - * 62.5 kHz otherwise. - * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. - * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW - * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 - */ -#define FREQ_MUL (1000000 / 62.5) - - - -/************************************************************************** - * General Driver Functions - **************************************************************************/ - -/* - * si470x_get_report - receive a HID report - */ -static int si470x_get_report(struct si470x_device *radio, int size) -{ - return usb_control_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 0), - HID_REQ_GET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - radio->buf[0], 2, - radio->buf, size, usb_timeout); -} - - -/* - * si470x_set_report - send a HID report - */ -static int si470x_set_report(struct si470x_device *radio, int size) -{ - return usb_control_msg(radio->usbdev, - usb_sndctrlpipe(radio->usbdev, 0), - HID_REQ_SET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - radio->buf[0], 2, - radio->buf, size, usb_timeout); -} - - -/* - * si470x_get_register - read register - */ -static int si470x_get_register(struct si470x_device *radio, int regnr) -{ - int retval; - - radio->buf[0] = REGISTER_REPORT(regnr); - - retval = si470x_get_report(radio, REGISTER_REPORT_SIZE); - if (retval >= 0) - radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2]; - - return (retval < 0) ? -EINVAL : 0; -} - - -/* - * si470x_set_register - write register - */ -static int si470x_set_register(struct si470x_device *radio, int regnr) -{ - int retval; - - radio->buf[0] = REGISTER_REPORT(regnr); - radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8; - radio->buf[2] = (radio->registers[regnr] & 0x00ff); - - retval = si470x_set_report(radio, REGISTER_REPORT_SIZE); - - return (retval < 0) ? -EINVAL : 0; -} - - -/* - * si470x_get_all_registers - read entire registers - */ -static int si470x_get_all_registers(struct si470x_device *radio) -{ - int retval; - int regnr; - - radio->buf[0] = ENTIRE_REPORT; - - retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE); - - if (retval >= 0) - for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) - radio->registers[regnr] = - (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | - radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; - - return (retval < 0) ? -EINVAL : 0; -} - - -/* - * si470x_get_rds_registers - read rds registers - */ -static int si470x_get_rds_registers(struct si470x_device *radio) -{ - int retval; - int regnr; - int size; - - radio->buf[0] = RDS_REPORT; - - retval = usb_interrupt_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 1), - radio->buf, RDS_REPORT_SIZE, &size, usb_timeout); - - if (retval >= 0) - for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) - radio->registers[STATUSRSSI + regnr] = - (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | - radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; - - return (retval < 0) ? -EINVAL : 0; -} - - -/* - * si470x_set_chan - set the channel - */ -static int si470x_set_chan(struct si470x_device *radio, int chan) -{ - int retval, i; - - /* start tuning */ - radio->registers[CHANNEL] &= ~CHANNEL_CHAN; - radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; - retval = si470x_set_register(radio, CHANNEL); - if (retval < 0) - return retval; - - /* wait till seek operation has completed */ - i = 0; - do { - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - return retval; - } while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) && - (++i < seek_retries)); - if (i >= seek_retries) - printk(KERN_WARNING DRIVER_NAME - ": seek does not finish after %d tries\n", i); - - /* stop tuning */ - radio->registers[CHANNEL] &= ~CHANNEL_TUNE; - return si470x_set_register(radio, CHANNEL); -} - - -/* - * si470x_get_freq - get the frequency - */ -static int si470x_get_freq(struct si470x_device *radio) -{ - int spacing, band_bottom, chan, freq; - int retval; - - /* Spacing (kHz) */ - switch (space) { - /* 0: 200 kHz (USA, Australia) */ - case 0 : spacing = 0.200 * FREQ_MUL; break; - /* 1: 100 kHz (Europe, Japan) */ - case 1 : spacing = 0.100 * FREQ_MUL; break; - /* 2: 50 kHz */ - default: spacing = 0.050 * FREQ_MUL; break; - }; - - /* Bottom of Band (MHz) */ - switch (band) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - case 0 : band_bottom = 87.5 * FREQ_MUL; break; - /* 1: 76 - 108 MHz (Japan wide band) */ - default: band_bottom = 76 * FREQ_MUL; break; - /* 2: 76 - 90 MHz (Japan) */ - case 2 : band_bottom = 76 * FREQ_MUL; break; - }; - - /* read channel */ - retval = si470x_get_register(radio, READCHAN); - if (retval < 0) - return retval; - chan = radio->registers[READCHAN] & READCHAN_READCHAN; - - /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ - freq = chan * spacing + band_bottom; - - return freq; -} - - -/* - * si470x_set_freq - set the frequency - */ -static int si470x_set_freq(struct si470x_device *radio, int freq) -{ - int spacing, band_bottom, chan; - - /* Spacing (kHz) */ - switch (space) { - /* 0: 200 kHz (USA, Australia) */ - case 0 : spacing = 0.200 * FREQ_MUL; break; - /* 1: 100 kHz (Europe, Japan) */ - case 1 : spacing = 0.100 * FREQ_MUL; break; - /* 2: 50 kHz */ - default: spacing = 0.050 * FREQ_MUL; break; - }; - - /* Bottom of Band (MHz) */ - switch (band) { - /* 0: 87.5 - 108 MHz (USA, Europe) */ - case 0 : band_bottom = 87.5 * FREQ_MUL; break; - /* 1: 76 - 108 MHz (Japan wide band) */ - default: band_bottom = 76 * FREQ_MUL; break; - /* 2: 76 - 90 MHz (Japan) */ - case 2 : band_bottom = 76 * FREQ_MUL; break; - }; - - /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ - chan = (freq - band_bottom) / spacing; - - return si470x_set_chan(radio, chan); -} - - -/* - * si470x_start - switch on radio - */ -static int si470x_start(struct si470x_device *radio) -{ - int retval; - - /* powercfg */ - radio->registers[POWERCFG] = - POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; - retval = si470x_set_register(radio, POWERCFG); - if (retval < 0) - return retval; - - /* sysconfig 1 */ - radio->registers[SYSCONFIG1] = SYSCONFIG1_DE; - retval = si470x_set_register(radio, SYSCONFIG1); - if (retval < 0) - return retval; - - /* sysconfig 2 */ - radio->registers[SYSCONFIG2] = - (0x3f << 8) | /* SEEKTH */ - (band << 6) | /* BAND */ - (space << 4) | /* SPACE */ - 15; /* VOLUME (max) */ - retval = si470x_set_register(radio, SYSCONFIG2); - if (retval < 0) - return retval; - - /* reset last channel */ - return si470x_set_chan(radio, - radio->registers[CHANNEL] & CHANNEL_CHAN); -} - - -/* - * si470x_stop - switch off radio - */ -static int si470x_stop(struct si470x_device *radio) -{ - int retval; - - /* sysconfig 1 */ - radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; - retval = si470x_set_register(radio, SYSCONFIG1); - if (retval < 0) - return retval; - - /* powercfg */ - radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; - /* POWERCFG_ENABLE has to automatically go low */ - radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; - return si470x_set_register(radio, POWERCFG); -} - - -/* - * si470x_rds_on - switch on rds reception - */ -static int si470x_rds_on(struct si470x_device *radio) -{ - /* sysconfig 1 */ - radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; - return si470x_set_register(radio, SYSCONFIG1); -} - - - -/************************************************************************** - * RDS Driver Functions - **************************************************************************/ - -/* - * si470x_rds - rds processing function - */ -static void si470x_rds(struct si470x_device *radio) -{ - unsigned char tmpbuf[3]; - unsigned char blocknum; - unsigned char bler; /* rds block errors */ - unsigned short rds; - unsigned int i; - - /* get rds blocks */ - if (si470x_get_rds_registers(radio) < 0) - return; - if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { - /* No RDS group ready */ - return; - } - if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) { - /* RDS decoder not synchronized */ - return; - } - - /* copy four RDS blocks to internal buffer */ - if (spin_trylock(&radio->lock)) { - /* process each rds block */ - for (blocknum = 0; blocknum < 4; blocknum++) { - switch (blocknum) { - default: - bler = (radio->registers[STATUSRSSI] & - STATUSRSSI_BLERA) >> 9; - rds = radio->registers[RDSA]; - break; - case 1: - bler = (radio->registers[READCHAN] & - READCHAN_BLERB) >> 14; - rds = radio->registers[RDSB]; - break; - case 2: - bler = (radio->registers[READCHAN] & - READCHAN_BLERC) >> 12; - rds = radio->registers[RDSC]; - break; - case 3: - bler = (radio->registers[READCHAN] & - READCHAN_BLERD) >> 10; - rds = radio->registers[RDSD]; - break; - }; - - /* Fill the V4L2 RDS buffer */ - tmpbuf[0] = rds & 0x00ff; /* LSB */ - tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ - tmpbuf[2] = blocknum; /* offset name */ - tmpbuf[2] |= blocknum << 3; /* received offset */ - if (bler > max_rds_errors) - tmpbuf[2] |= 0x80; /* uncorrectable errors */ - else if (bler > 0) - tmpbuf[2] |= 0x40; /* corrected error(s) */ - - /* copy RDS block to internal buffer */ - for (i = 0; i < 3; i++) { - radio->buffer[radio->wr_index] = tmpbuf[i]; - radio->wr_index++; - } - - /* wrap write pointer */ - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - /* check for overflow */ - if (radio->wr_index == radio->rd_index) { - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - } - } - spin_unlock(&radio->lock); - } - - /* wake up read queue */ - if (radio->wr_index != radio->rd_index) - wake_up_interruptible(&radio->read_queue); -} - - -/* - * si470x_timer - rds timer function - */ -static void si470x_timer(unsigned long data) -{ - struct si470x_device *radio = (struct si470x_device *) data; - - schedule_work(&radio->work); -} - - -/* - * si470x_work - rds work function - */ -static void si470x_work(struct work_struct *work) -{ - struct si470x_device *radio = container_of(work, struct si470x_device, - work); - - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) - return; - - si470x_rds(radio); - mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time)); -} - - - -/************************************************************************** - * File Operations Interface - **************************************************************************/ - -/* - * si470x_fops_read - read RDS data - */ -static ssize_t si470x_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - int retval = 0; - unsigned int block_count = 0; - - /* switch on rds reception */ - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { - si470x_rds_on(radio); - schedule_work(&radio->work); - } - - /* block if no new data available */ - while (radio->wr_index == radio->rd_index) { - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - interruptible_sleep_on(&radio->read_queue); - } - - /* calculate block count from byte count */ - count /= 3; - - /* copy RDS block out of internal buffer and to user buffer */ - if (spin_trylock(&radio->lock)) { - while (block_count < count) { - if (radio->rd_index == radio->wr_index) - break; - - /* always transfer rds complete blocks */ - if (copy_to_user(buf, - &radio->buffer[radio->rd_index], 3)) - /* retval = -EFAULT; */ - break; - - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - - /* increment counters */ - block_count++; - buf += 3; - retval += 3; - } - - spin_unlock(&radio->lock); - } - - return retval; -} - - -/* - * si470x_fops_poll - poll RDS data - */ -static unsigned int si470x_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - /* switch on rds reception */ - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { - si470x_rds_on(radio); - schedule_work(&radio->work); - } - - poll_wait(file, &radio->read_queue, pts); - - if (radio->rd_index != radio->wr_index) - return POLLIN | POLLRDNORM; - - return 0; -} - - -/* - * si470x_fops_open - file open - */ -static int si470x_fops_open(struct inode *inode, struct file *file) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - radio->users++; - if (radio->users == 1) - return si470x_start(radio); - - return 0; -} - - -/* - * si470x_fops_release - file release - */ -static int si470x_fops_release(struct inode *inode, struct file *file) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - if (!radio) - return -ENODEV; - - radio->users--; - if (radio->users == 0) { - /* stop rds reception */ - del_timer_sync(&radio->timer); - flush_scheduled_work(); - - /* cancel read processes */ - wake_up_interruptible(&radio->read_queue); - - return si470x_stop(radio); - } - - return 0; -} - - -/* - * si470x_fops - file operations interface - */ -static const struct file_operations si470x_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = si470x_fops_read, - .poll = si470x_fops_poll, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .open = si470x_fops_open, - .release = si470x_fops_release, -}; - - - -/************************************************************************** - * Video4Linux Interface - **************************************************************************/ - -/* - * si470x_v4l2_queryctrl - query control - */ -static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = { -/* HINT: the disabled controls are only here to satify kradio and such apps */ - { - .id = V4L2_CID_AUDIO_VOLUME, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Volume", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 15, - }, - { - .id = V4L2_CID_AUDIO_BALANCE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BASS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_TREBLE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_AUDIO_LOUDNESS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, -}; - - -/* - * si470x_vidioc_querycap - query device capabilities - */ -static int si470x_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - sprintf(capability->bus_info, "USB"); - capability->version = DRIVER_VERSION; - capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - - return 0; -} - - -/* - * si470x_vidioc_g_input - get input - */ -static int si470x_vidioc_g_input(struct file *filp, void *priv, - unsigned int *i) -{ - *i = 0; - - return 0; -} - - -/* - * si470x_vidioc_s_input - set input - */ -static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - - return 0; -} - - -/* - * si470x_vidioc_queryctrl - enumerate control items - */ -static int si470x_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) { - if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) { - memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc)); - return 0; - } - } - - return -EINVAL; -} - - -/* - * si470x_vidioc_g_ctrl - get the value of a control - */ -static int si470x_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = radio->registers[SYSCONFIG2] & - SYSCONFIG2_VOLUME; - break; - case V4L2_CID_AUDIO_MUTE: - ctrl->value = ((radio->registers[POWERCFG] & - POWERCFG_DMUTE) == 0) ? 1 : 0; - break; - } - - return 0; -} - - -/* - * si470x_vidioc_s_ctrl - set the value of a control - */ -static int si470x_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; - radio->registers[SYSCONFIG2] |= ctrl->value; - return si470x_set_register(radio, SYSCONFIG2); - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value == 1) - radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; - else - radio->registers[POWERCFG] |= POWERCFG_DMUTE; - return si470x_set_register(radio, POWERCFG); - } - - return -EINVAL; -} - - -/* - * si470x_vidioc_g_audio - get audio attributes - */ -static int si470x_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index > 1) - return -EINVAL; - - strcpy(audio->name, "Radio"); - audio->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - - -/* - * si470x_vidioc_s_audio - set audio attributes - */ -static int si470x_vidioc_s_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - - return 0; -} - - -/* - * si470x_vidioc_g_tuner - get tuner attributes - */ -static int si470x_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - int retval; - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - if (tuner->index > 0) - return -EINVAL; - - /* read status rssi */ - retval = si470x_get_register(radio, STATUSRSSI); - if (retval < 0) - return retval; - - strcpy(tuner->name, "FM"); - tuner->type = V4L2_TUNER_RADIO; - switch (band) { - /* 0: 87.5 - 108 MHz (USA, Europe, default) */ - default: - tuner->rangelow = 87.5 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 1: 76 - 108 MHz (Japan wide band) */ - case 1 : - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 108 * FREQ_MUL; - break; - /* 2: 76 - 90 MHz (Japan) */ - case 2 : - tuner->rangelow = 76 * FREQ_MUL; - tuner->rangehigh = 90 * FREQ_MUL; - break; - }; - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; - tuner->capability = V4L2_TUNER_CAP_LOW; - - /* Stereo indicator == Stereo (instead of Mono) */ - if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1) - tuner->audmode = V4L2_TUNER_MODE_STEREO; - else - tuner->audmode = V4L2_TUNER_MODE_MONO; - - /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ - tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI) - * 0x0101; - - /* automatic frequency control: -1: freq to low, 1 freq to high */ - tuner->afc = 0; - - return 0; -} - - -/* - * si470x_vidioc_s_tuner - set tuner attributes - */ -static int si470x_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - if (tuner->index > 0) - return -EINVAL; - - if (tuner->audmode == V4L2_TUNER_MODE_MONO) - radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ - else - radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ - - return si470x_set_register(radio, POWERCFG); -} - - -/* - * si470x_vidioc_g_frequency - get tuner or modulator radio frequency - */ -static int si470x_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - freq->type = V4L2_TUNER_RADIO; - freq->frequency = si470x_get_freq(radio); - - return 0; -} - - -/* - * si470x_vidioc_s_frequency - set tuner or modulator radio frequency - */ -static int si470x_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); - - if (freq->type != V4L2_TUNER_RADIO) - return -EINVAL; - - return si470x_set_freq(radio, freq->frequency); -} - - -/* - * si470x_viddev_tamples - video device interface - */ -static struct video_device si470x_viddev_template = { - .fops = &si470x_fops, - .name = DRIVER_NAME, - .type = VID_TYPE_TUNER, - .release = video_device_release, - .vidioc_querycap = si470x_vidioc_querycap, - .vidioc_g_input = si470x_vidioc_g_input, - .vidioc_s_input = si470x_vidioc_s_input, - .vidioc_queryctrl = si470x_vidioc_queryctrl, - .vidioc_g_ctrl = si470x_vidioc_g_ctrl, - .vidioc_s_ctrl = si470x_vidioc_s_ctrl, - .vidioc_g_audio = si470x_vidioc_g_audio, - .vidioc_s_audio = si470x_vidioc_s_audio, - .vidioc_g_tuner = si470x_vidioc_g_tuner, - .vidioc_s_tuner = si470x_vidioc_s_tuner, - .vidioc_g_frequency = si470x_vidioc_g_frequency, - .vidioc_s_frequency = si470x_vidioc_s_frequency, - .owner = THIS_MODULE, -}; - - - -/************************************************************************** - * USB Interface - **************************************************************************/ - -/* - * si470x_usb_driver_probe - probe for the device - */ -static int si470x_usb_driver_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct si470x_device *radio; - - /* memory and interface allocations */ - radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL); - if (!radio) - return -ENOMEM; - radio->videodev = video_device_alloc(); - if (!radio->videodev) { - kfree(radio); - return -ENOMEM; - } - memcpy(radio->videodev, &si470x_viddev_template, - sizeof(si470x_viddev_template)); - radio->users = 0; - radio->usbdev = interface_to_usbdev(intf); - video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { - printk(KERN_WARNING DRIVER_NAME - ": Could not register video device\n"); - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - usb_set_intfdata(intf, radio); - - /* show some infos about the specific device */ - if (si470x_get_all_registers(radio) < 0) { - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", - radio->registers[DEVICEID], radio->registers[CHIPID]); - - /* check if firmware is current */ - if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) - < RADIO_SW_VERSION_CURRENT) - printk(KERN_WARNING DRIVER_NAME - ": This driver is known to work with chip version %d, " - "but the device has firmware %d.\n" - DRIVER_NAME - "If you have some trouble using this driver, please " - "report to V4L ML at video4linux-list@redhat.com\n", - radio->registers[CHIPID] & CHIPID_FIRMWARE, - RADIO_SW_VERSION_CURRENT); - - /* set initial frequency */ - si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ - - /* rds initialization */ - radio->buf_size = rds_buf * 3; - radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); - if (!radio->buffer) { - video_device_release(radio->videodev); - kfree(radio); - return -ENOMEM; - } - radio->wr_index = 0; - radio->rd_index = 0; - init_waitqueue_head(&radio->read_queue); - - /* prepare polling via eventd */ - INIT_WORK(&radio->work, si470x_work); - init_timer(&radio->timer); - radio->timer.function = si470x_timer; - radio->timer.data = (unsigned long) radio; - - return 0; -} - - -/* - * si470x_usb_driver_disconnect - disconnect the device - */ -static void si470x_usb_driver_disconnect(struct usb_interface *intf) -{ - struct si470x_device *radio = usb_get_intfdata(intf); - - del_timer_sync(&radio->timer); - flush_scheduled_work(); - - usb_set_intfdata(intf, NULL); - if (radio) { - video_unregister_device(radio->videodev); - kfree(radio->buffer); - kfree(radio); - } -} - - -/* - * si470x_usb_driver - usb driver interface - */ -static struct usb_driver si470x_usb_driver = { - .name = DRIVER_NAME, - .probe = si470x_usb_driver_probe, - .disconnect = si470x_usb_driver_disconnect, - .id_table = si470x_usb_driver_id_table, -}; - - - -/************************************************************************** - * Module Interface - **************************************************************************/ - -/* - * si470x_module_init - module init - */ -static int __init si470x_module_init(void) -{ - printk(KERN_INFO DRIVER_DESC "\n"); - return usb_register(&si470x_usb_driver); -} - - -/* - * si470x_module_exit - module exit - */ -static void __exit si470x_module_exit(void) -{ - usb_deregister(&si470x_usb_driver); -} - - -module_init(si470x_module_init); -module_exit(si470x_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION("1.0.4"); diff --git a/trunk/drivers/media/video/Kconfig b/trunk/drivers/media/video/Kconfig index a2e8987a6195..c9f14bfc8544 100644 --- a/trunk/drivers/media/video/Kconfig +++ b/trunk/drivers/media/video/Kconfig @@ -45,7 +45,7 @@ comment "Audio decoders" config VIDEO_TVAUDIO tristate "Simple audio decoder chips" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L1 && I2C ---help--- Support for several audio decoder chips found on some bt8xx boards: Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, @@ -57,7 +57,7 @@ config VIDEO_TVAUDIO config VIDEO_TDA7432 tristate "Philips TDA7432 audio processor" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L1 && I2C ---help--- Support for tda7432 audio decoder chip found on some bt8xx boards. @@ -75,7 +75,7 @@ config VIDEO_TDA9840 config VIDEO_TDA9875 tristate "Philips TDA9875 audio processor" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L1 && I2C ---help--- Support for tda9875 audio decoder chip found on some bt8xx boards. @@ -109,19 +109,9 @@ config VIDEO_MSP3400 To compile this driver as a module, choose M here: the module will be called msp3400. -config VIDEO_CS5345 - tristate "Cirrus Logic CS5345 audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL - ---help--- - Support for the Cirrus Logic CS5345 24-bit, 192 kHz - stereo A/D converter. - - To compile this driver as a module, choose M here: the - module will be called cs5345. - config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL ---help--- Support for the Cirrus Logic CS53L32A low voltage stereo A/D converter. @@ -129,15 +119,6 @@ config VIDEO_CS53L32A To compile this driver as a module, choose M here: the module will be called cs53l32a. -config VIDEO_M52790 - tristate "Mitsubishi M52790 A/V switch" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL - ---help--- - Support for the Mitsubishi M52790 A/V switch. - - To compile this driver as a module, choose M here: the - module will be called m52790. - config VIDEO_TLV320AIC23B tristate "Texas Instruments TLV320AIC23B audio codec" depends on VIDEO_V4L2 && I2C && EXPERIMENTAL @@ -149,7 +130,7 @@ config VIDEO_TLV320AIC23B config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL ---help--- Support for the Wolfson Microelectronics WM8775 high performance stereo A/D Converter with a 4 channel input mixer. @@ -159,7 +140,7 @@ config VIDEO_WM8775 config VIDEO_WM8739 tristate "Wolfson Microelectronics WM8739 stereo audio ADC" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL ---help--- Support for the Wolfson Microelectronics WM8739 stereo A/D Converter. @@ -263,7 +244,7 @@ config VIDEO_SAA7114 config VIDEO_SAA711X tristate "Philips SAA7113/4/5 video decoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL ---help--- Support for the Philips SAA7113/4/5 video decoders. @@ -319,7 +300,7 @@ comment "Video encoders" config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL ---help--- Support for the Philips SAA7127/9 digital video encoders. @@ -357,7 +338,7 @@ comment "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL ---help--- Support for the NEC Electronics uPD64031A Ghost Reduction video chip. It is most often found in NTSC TV cards made for @@ -369,7 +350,7 @@ config VIDEO_UPD64031A config VIDEO_UPD64083 tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL ---help--- Support for the NEC Electronics uPD64083 3-Dimensional Y/C separation video chip. It is used to improve the quality of @@ -821,19 +802,6 @@ config USB_ZR364XX To compile this driver as a module, choose M here: the module will be called zr364xx. -config USB_STKWEBCAM - tristate "USB Syntek DC1125 Camera support" - depends on VIDEO_V4L2 && EXPERIMENTAL - ---help--- - Say Y here if you want to use this type of camera. - Supported devices are typically found in some Asus laptops, - with USB id 174f:a311 and 05e1:0501. Other Syntek cameras - may be supported by the stk11xx driver, from which this is - derived, see http://stk11xx.sourceforge.net - - To compile this driver as a module, choose M here: the - module will be called stkwebcam. - endif # V4L_USB_DRIVERS endif # VIDEO_CAPTURE_DRIVERS diff --git a/trunk/drivers/media/video/Makefile b/trunk/drivers/media/video/Makefile index 28ddd146c1c5..b5a064163e03 100644 --- a/trunk/drivers/media/video/Makefile +++ b/trunk/drivers/media/video/Makefile @@ -4,12 +4,10 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-types.o +tuner-objs := tuner-core.o tuner-types.o tda9887.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o -stkwebcam-objs := stk-webcam.o stk-sensor.o - obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ v4l2-int-device.o @@ -68,9 +66,7 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o -obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o -obj-$(CONFIG_VIDEO_M52790) += m52790.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o @@ -85,13 +81,11 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o -obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_TUNER_TDA9887) += tda9887.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o @@ -118,7 +112,6 @@ obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o obj-$(CONFIG_USB_ZR364XX) += zr364xx.o -obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o obj-$(CONFIG_USB_SN9C102) += sn9c102/ obj-$(CONFIG_USB_ET61X251) += et61x251/ @@ -136,4 +129,3 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/trunk/drivers/media/video/bt8xx/Kconfig b/trunk/drivers/media/video/bt8xx/Kconfig index cfc822bb502a..2ca162b390a2 100644 --- a/trunk/drivers/media/video/bt8xx/Kconfig +++ b/trunk/drivers/media/video/bt8xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX diff --git a/trunk/drivers/media/video/bt8xx/Makefile b/trunk/drivers/media/video/bt8xx/Makefile index 924d216d9570..a096a03418aa 100644 --- a/trunk/drivers/media/video/bt8xx/Makefile +++ b/trunk/drivers/media/video/bt8xx/Makefile @@ -4,7 +4,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o bttv-audio-hook.o + bttv-input.o obj-$(CONFIG_VIDEO_BT848) += bttv.o diff --git a/trunk/drivers/media/video/bt8xx/bttv-audio-hook.c b/trunk/drivers/media/video/bt8xx/bttv-audio-hook.c deleted file mode 100644 index 2364d16586b3..000000000000 --- a/trunk/drivers/media/video/bt8xx/bttv-audio-hook.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Handlers for board audio hooks, splitted from bttv-cards - * - * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - */ - -#include "bttv-audio-hook.h" - -#include - -/* ----------------------------------------------------------------------- */ -/* winview */ - -void winview_volume(struct bttv *btv, __u16 volume) -{ - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - int bits_out, loops, vol, data; - - /* 32 levels logarithmic */ - vol = 32 - ((volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; - data = gpio_read(); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<audmode & V4L2_TUNER_MODE_LANG1) - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x300; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x200; -/* if (t->audmode & V4L2_TUNER_MODE_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val, con; - - if (btv->radio_user) - return; - - val = gpio_read(); - if (set) { - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) { - if (t->audmode & V4L2_TUNER_MODE_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } - } - if (con != (val & 0x300)) { - gpio_bits(0x300, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); - } - } else { - switch (val & 0x70) { - case 0x10: - t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 0x30: - t->rxsubchans = V4L2_TUNER_SUB_LANG2; - break; - case 0x50: - t->rxsubchans = V4L2_TUNER_SUB_LANG1; - break; - case 0x60: - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - break; - case 0x70: - t->rxsubchans = V4L2_TUNER_SUB_MONO; - break; - default: - t->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; - } - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Mario Medina Nussbaum - * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, - * 0xdde enables mono and 0xccd enables sap - * - * Petr Vandrovec - * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select - * input/output sound connection, so both must be set for output mode. - * - * Looks like it's needed only for the "tvphone", the "tvphone 98" - * handles this with a tda9840 - * - */ - -void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x02; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1; - return; - } -} - - -void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x01; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - return; - } -} - -/* Lifetec 9415 handling */ - -void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - int val = 0; - - if (gpio_read() & 0x4000) { - t->audmode = V4L2_TUNER_MODE_MONO; - return; - } - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ - val = 0x0080; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ - val = 0x0880; - if ((t->audmode & V4L2_TUNER_MODE_LANG1) || - (t->audmode & V4L2_TUNER_MODE_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - return; - } -} - -/* TDA9821 on TerraTV+ Bt848, Bt878 */ -void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int con = 0; - - if (set) { - gpio_inout(0x180000,0x180000); - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x080000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - - -void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned long val = 0; - - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x410000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM - * revision 9B has on-board TDA9874A sound decoder). - * - * Note: There are card variants without tda9874a. Forcing the "stereo sound route" - * will mute this cards. - */ -void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val = 0; - - if (btv->radio_user) - return; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x01; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * Dariusz Kowalewski - * sound control for FlyVideo 2000S (with tda9874 decoder) - * based on pvbt878p9b_audio() - this is not tested, please fix!!! - */ -void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int val = 0xffff; - - if (btv->radio_user) - return; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x0000; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * sound control for Canopus WinDVR PCI - * Masaki Suzuki - */ -void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned long val = 0; - - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) - val = 0x040000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) - val = 0; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - val = 0x100000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} - -/* - * sound control for AD-TVK503 - * Hiroshi Takekawa - */ -void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) -{ - unsigned int con = 0xffffff; - - /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (t->audmode & V4L2_TUNER_MODE_LANG1) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x00180000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - } -} diff --git a/trunk/drivers/media/video/bt8xx/bttv-audio-hook.h b/trunk/drivers/media/video/bt8xx/bttv-audio-hook.h deleted file mode 100644 index 159d07adeff8..000000000000 --- a/trunk/drivers/media/video/bt8xx/bttv-audio-hook.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Handlers for board audio hooks, splitted from bttv-cards - * - * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License - */ - -#include "bttvp.h" - -void winview_volume (struct bttv *btv, __u16 volume); - -void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); -void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); - diff --git a/trunk/drivers/media/video/bt8xx/bttv-cards.c b/trunk/drivers/media/video/bt8xx/bttv-cards.c index 63a47cd4c161..585d1ef95afd 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-cards.c +++ b/trunk/drivers/media/video/bt8xx/bttv-cards.c @@ -39,7 +39,6 @@ #include "bttvp.h" #include #include -#include "bttv-audio-hook.h" /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); @@ -51,6 +50,20 @@ static void modtec_eeprom(struct bttv *btv); static void init_PXC200(struct bttv *btv); static void init_RTV24(struct bttv *btv); +static void winview_audio(struct bttv *btv, struct video_audio *v, int set); +static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); +static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, + int set); +static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, + int set); +static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); +static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); +static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set); +static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); +static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); +static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); +static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); +static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set); static void rv605_muxsel(struct bttv *btv, unsigned int input); static void eagle_muxsel(struct bttv *btv, unsigned int input); static void xguard_muxsel(struct bttv *btv, unsigned int input); @@ -414,7 +427,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= avermedia_tvphone_audio, + .audio_hook = avermedia_tvphone_audio, .has_remote = 1, }, [BTTV_BOARD_MATRIX_VISION] = { @@ -526,7 +539,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= avermedia_tv_stereo_audio, + .audio_hook = avermedia_tv_stereo_audio, .no_gpioirq = 1, }, [BTTV_BOARD_VHX] = { @@ -591,7 +604,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .volume_gpio = winview_volume, + .audio_hook = winview_audio, .has_radio = 1, }, [BTTV_BOARD_AVEC_INTERCAP] = { @@ -715,7 +728,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= terratv_audio, + .audio_hook = terratv_audio, }, [BTTV_BOARD_HAUPPAUG_WCAM] = { .name = "Hauppauge WinCam newer (bt878)", @@ -763,7 +776,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= terratv_audio, + .audio_hook = terratv_audio, /* GPIO wiring: External 20 pin connector (for Active Radio Upgrade board) gpio00: i2c-sda @@ -902,7 +915,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= winfast2000_audio, + .audio_hook = winfast2000_audio, .has_remote = 1, }, [BTTV_BOARD_CHRONOS_VS2] = { @@ -1022,7 +1035,7 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, - .audio_mode_gpio= avermedia_tvphone_audio, + .audio_hook = avermedia_tvphone_audio, }, [BTTV_BOARD_PV951] = { .name = "ProVideo PV951", /* pic16c54 */ @@ -1154,7 +1167,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ALPS_TSHC6_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv3pci_audio, + .audio_hook = gvbctv3pci_audio, }, [BTTV_BOARD_PXELVWPLTVPAK] = { .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", @@ -1459,7 +1472,7 @@ struct tvcard bttv_tvcards[] = { /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, .gpiomute = 0x1800, - .audio_mode_gpio= fv2000s_audio, + .audio_hook = fv2000s_audio, .no_msp34xx = 1, .no_tda9875 = 1, .needs_tvaudio = 1, @@ -1500,7 +1513,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv3pci_audio, + .audio_hook = gvbctv3pci_audio, }, /* ---- card 0x44 ---------------------------------- */ @@ -1619,7 +1632,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ + .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */ .has_radio = 1, /* Note: not all cards have radio */ .has_remote = 1, /* GPIO wiring: @@ -1697,7 +1710,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= windvr_audio, + .audio_hook = windvr_audio, }, [BTTV_BOARD_GRANDTEC_MULTI] = { .name = "GrandTec Multi Capture Card (Bt878)", @@ -1794,7 +1807,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC_M, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= gvbctv5pci_audio, + .audio_hook = gvbctv5pci_audio, .has_radio = 1, }, [BTTV_BOARD_OSPREY1x0] = { @@ -2093,7 +2106,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_mode_gpio= adtvk503_audio, + .audio_hook = adtvk503_audio, }, /* ---- card 0x64 ---------------------------------- */ @@ -3160,8 +3173,8 @@ static void flyvideo_gpio(struct bttv *btv) /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio; - /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ + if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio; + /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */ } static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, @@ -3561,12 +3574,8 @@ void __devinit bttv_init_card2(struct bttv *btv) } if (btv->tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &btv->tda9887_conf; - - bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg); + bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG, + &btv->tda9887_conf); } btv->svhs = bttv_tvcards[btv->c.type].svhs; @@ -3581,10 +3590,8 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->has_remote=1; if (!bttv_tvcards[btv->c.type].no_gpioirq) btv->gpioirq=1; - if (bttv_tvcards[btv->c.type].volume_gpio) - btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio; - if (bttv_tvcards[btv->c.type].audio_mode_gpio) - btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio; + if (bttv_tvcards[btv->c.type].audio_hook) + btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) { /* detect Bt832 chip for quartzsight digital camera */ @@ -3943,7 +3950,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) void bttv_tda9880_setnorm(struct bttv *btv, int norm) { /* fix up our card entry */ - if(norm==V4L2_STD_NTSC) { + if(norm==VIDEO_MODE_NTSC) { bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; @@ -4312,6 +4319,387 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq) tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ } + +/* ----------------------------------------------------------------------- */ +/* winview */ + +static void winview_audio(struct bttv *btv, struct video_audio *v, int set) +{ + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + if (!set) { + /* Fixed by Leandro Lucarella flags |= VIDEO_AUDIO_VOLUME; + return; + } + + /* 32 levels logarithmic */ + vol = 32 - ((v->volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; + data = gpio_read(); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<mode & VIDEO_SOUND_LANG1) + con = 0x000; + if (v->mode & VIDEO_SOUND_LANG2) + con = 0x300; + if (v->mode & VIDEO_SOUND_STEREO) + con = 0x200; +/* if (v->mode & VIDEO_SOUND_MONO) + * con = 0x100; */ + gpio_bits(0x300, con); + } else { + v->mode = VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +static void +gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val, con; + + if (btv->radio_user) + return; + + val = gpio_read(); + if (set) { + con = 0x000; + if (v->mode & VIDEO_SOUND_LANG2) { + if (v->mode & VIDEO_SOUND_LANG1) { + /* LANG1 + LANG2 */ + con = 0x100; + } + else { + /* LANG2 */ + con = 0x300; + } + } + if (con != (val & 0x300)) { + gpio_bits(0x300, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"gvbctv5pci"); + } + } else { + switch (val & 0x70) { + case 0x10: + v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + break; + case 0x30: + v->mode = VIDEO_SOUND_LANG2; + break; + case 0x50: + v->mode = VIDEO_SOUND_LANG1; + break; + case 0x60: + v->mode = VIDEO_SOUND_STEREO; + break; + case 0x70: + v->mode = VIDEO_SOUND_MONO; + break; + default: + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } + } +} + +/* + * Mario Medina Nussbaum + * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, + * 0xdde enables mono and 0xccd enables sap + * + * Petr Vandrovec + * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select + * input/output sound connection, so both must be set for output mode. + * + * Looks like it's needed only for the "tvphone", the "tvphone 98" + * handles this with a tda9840 + * + */ +static void +avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x02; + if (v->mode & VIDEO_SOUND_STEREO) + val = 0x01; + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1; + return; + } +} + +static void +avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x01; + if (v->mode & VIDEO_SOUND_STEREO) /* STEREO */ + val = 0x02; + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + return; + } +} + +/* Lifetec 9415 handling */ +static void +lt9415_audio(struct bttv *btv, struct video_audio *v, int set) +{ + int val = 0; + + if (gpio_read() & 0x4000) { + v->mode = VIDEO_SOUND_MONO; + return; + } + + if (set) { + if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */ + val = 0x0080; + if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */ + val = 0x0880; + if ((v->mode & VIDEO_SOUND_LANG1) || + (v->mode & VIDEO_SOUND_MONO)) + val = 0; + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"lt9415"); + } else { + /* autodetect doesn't work with this card :-( */ + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + return; + } +} + +/* TDA9821 on TerraTV+ Bt848, Bt878 */ +static void +terratv_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int con = 0; + + if (set) { + gpio_inout(0x180000,0x180000); + if (v->mode & VIDEO_SOUND_LANG2) + con = 0x080000; + if (v->mode & VIDEO_SOUND_STEREO) + con = 0x180000; + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"terratv"); + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +static void +winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned long val = 0; + + if (set) { + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + if (v->mode & VIDEO_SOUND_MONO) /* Mono */ + val = 0x420000; + if (v->mode & VIDEO_SOUND_LANG1) /* Mono */ + val = 0x420000; + if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ + val = 0x410000; + if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ + val = 0x020000; + if (val) { + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"winfast2000"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM + * revision 9B has on-board TDA9874A sound decoder). + * + * Note: There are card variants without tda9874a. Forcing the "stereo sound route" + * will mute this cards. + */ +static void +pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val = 0; + + if (btv->radio_user) + return; + + if (set) { + if (v->mode & VIDEO_SOUND_MONO) { + val = 0x01; + } + if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) + || (v->mode & VIDEO_SOUND_STEREO)) { + val = 0x02; + } + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pvbt878p9b"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * Dariusz Kowalewski + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +static void +fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int val = 0xffff; + + if (btv->radio_user) + return; + if (set) { + if (v->mode & VIDEO_SOUND_MONO) { + val = 0x0000; + } + if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) + || (v->mode & VIDEO_SOUND_STEREO)) { + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + } + if (val != 0xffff) { + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki + */ +static void +windvr_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned long val = 0; + + if (set) { + if (v->mode & VIDEO_SOUND_MONO) + val = 0x040000; + if (v->mode & VIDEO_SOUND_LANG1) + val = 0; + if (v->mode & VIDEO_SOUND_LANG2) + val = 0x100000; + if (v->mode & VIDEO_SOUND_STEREO) + val = 0; + if (val) { + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + +/* + * sound control for AD-TVK503 + * Hiroshi Takekawa + */ +static void +adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) +{ + unsigned int con = 0xffffff; + + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ + + if (set) { + /* btor(***, BT848_GPIO_OUT_EN); */ + if (v->mode & VIDEO_SOUND_LANG1) + con = 0x00000000; + if (v->mode & VIDEO_SOUND_LANG2) + con = 0x00180000; + if (v->mode & VIDEO_SOUND_STEREO) + con = 0x00000000; + if (v->mode & VIDEO_SOUND_MONO) + con = 0x00060000; + if (con != 0xffffff) { + gpio_bits(0x1e0000,con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); + } + } else { + v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | + VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + } +} + /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] * * This is needed because rv605 don't use a normal multiplex, but a crosspoint diff --git a/trunk/drivers/media/video/bt8xx/bttv-driver.c b/trunk/drivers/media/video/bt8xx/bttv-driver.c index 907dc62c1783..581a3c955739 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-driver.c +++ b/trunk/drivers/media/video/bt8xx/bttv-driver.c @@ -9,12 +9,6 @@ some v4l2 code lines are taken from Justin's bttv2 driver which is (c) 2000 Justin Schoeman - V4L1 removal from: - (c) 2005-2006 Nickolay V. Shmyrev - - Fixes to be fully V4L2 compliant by - (c) 2006 Mauro Carvalho Chehab - Cropping and overscan support Copyright (C) 2005, 2006 Michael H. Schimek Sponsored by OPQ Systems AB @@ -163,7 +157,7 @@ MODULE_LICENSE("GPL"); static ssize_t show_card(struct device *cd, struct device_attribute *attr, char *buf) { - struct video_device *vfd = container_of(cd, struct video_device, class_dev); + struct video_device *vfd = to_video_device(cd); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } @@ -476,27 +470,31 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); /* ----------------------------------------------------------------------- */ /* bttv format list packed pixel formats must come first */ -static const struct bttv_format formats[] = { +static const struct bttv_format bttv_formats[] = { { .name = "8 bpp, gray", + .palette = VIDEO_PALETTE_GREY, .fourcc = V4L2_PIX_FMT_GREY, .btformat = BT848_COLOR_FMT_Y8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, },{ .name = "8 bpp, dithered color", + .palette = VIDEO_PALETTE_HI240, .fourcc = V4L2_PIX_FMT_HI240, .btformat = BT848_COLOR_FMT_RGB8, .depth = 8, .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, },{ .name = "15 bpp RGB, le", + .palette = VIDEO_PALETTE_RGB555, .fourcc = V4L2_PIX_FMT_RGB555, .btformat = BT848_COLOR_FMT_RGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "15 bpp RGB, be", + .palette = -1, .fourcc = V4L2_PIX_FMT_RGB555X, .btformat = BT848_COLOR_FMT_RGB15, .btswap = 0x03, /* byteswap */ @@ -504,12 +502,14 @@ static const struct bttv_format formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, le", + .palette = VIDEO_PALETTE_RGB565, .fourcc = V4L2_PIX_FMT_RGB565, .btformat = BT848_COLOR_FMT_RGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, be", + .palette = -1, .fourcc = V4L2_PIX_FMT_RGB565X, .btformat = BT848_COLOR_FMT_RGB16, .btswap = 0x03, /* byteswap */ @@ -517,18 +517,21 @@ static const struct bttv_format formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "24 bpp RGB, le", + .palette = VIDEO_PALETTE_RGB24, .fourcc = V4L2_PIX_FMT_BGR24, .btformat = BT848_COLOR_FMT_RGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, le", + .palette = VIDEO_PALETTE_RGB32, .fourcc = V4L2_PIX_FMT_BGR32, .btformat = BT848_COLOR_FMT_RGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, be", + .palette = -1, .fourcc = V4L2_PIX_FMT_RGB32, .btformat = BT848_COLOR_FMT_RGB32, .btswap = 0x0f, /* byte+word swap */ @@ -536,18 +539,21 @@ static const struct bttv_format formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", + .palette = VIDEO_PALETTE_YUV422, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", + .palette = VIDEO_PALETTE_YUYV, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, UYVY", + .palette = VIDEO_PALETTE_UYVY, .fourcc = V4L2_PIX_FMT_UYVY, .btformat = BT848_COLOR_FMT_YUY2, .btswap = 0x03, /* byteswap */ @@ -555,6 +561,7 @@ static const struct bttv_format formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, planar, Y-Cb-Cr", + .palette = VIDEO_PALETTE_YUV422P, .fourcc = V4L2_PIX_FMT_YUV422P, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 16, @@ -563,6 +570,7 @@ static const struct bttv_format formats[] = { .vshift = 0, },{ .name = "4:2:0, planar, Y-Cb-Cr", + .palette = VIDEO_PALETTE_YUV420P, .fourcc = V4L2_PIX_FMT_YUV420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -571,6 +579,7 @@ static const struct bttv_format formats[] = { .vshift = 1, },{ .name = "4:2:0, planar, Y-Cr-Cb", + .palette = -1, .fourcc = V4L2_PIX_FMT_YVU420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -579,6 +588,7 @@ static const struct bttv_format formats[] = { .vshift = 1, },{ .name = "4:1:1, planar, Y-Cb-Cr", + .palette = VIDEO_PALETTE_YUV411P, .fourcc = V4L2_PIX_FMT_YUV411P, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 12, @@ -587,6 +597,7 @@ static const struct bttv_format formats[] = { .vshift = 0, },{ .name = "4:1:0, planar, Y-Cb-Cr", + .palette = VIDEO_PALETTE_YUV410P, .fourcc = V4L2_PIX_FMT_YUV410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -595,6 +606,7 @@ static const struct bttv_format formats[] = { .vshift = 2, },{ .name = "4:1:0, planar, Y-Cr-Cb", + .palette = -1, .fourcc = V4L2_PIX_FMT_YVU410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -603,13 +615,14 @@ static const struct bttv_format formats[] = { .vshift = 2, },{ .name = "raw scanlines", + .palette = VIDEO_PALETTE_RAW, .fourcc = -1, .btformat = BT848_COLOR_FMT_RAW, .depth = 8, .flags = FORMAT_FLAGS_RAW, } }; -static const unsigned int FORMATS = ARRAY_SIZE(formats); +static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats); /* ----------------------------------------------------------------------- */ @@ -785,17 +798,7 @@ static const struct v4l2_queryctrl bttv_ctls[] = { }; - -static const struct v4l2_queryctrl *ctrl_by_id(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) - if (bttv_ctls[i].id == id) - return bttv_ctls+i; - - return NULL; -} +static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); /* ----------------------------------------------------------------------- */ /* resource management */ @@ -1251,6 +1254,16 @@ audio_input(struct bttv *btv, int input) return audio_mux(btv, input, btv->mute); } +static void +i2c_vidiocschan(struct bttv *btv) +{ + v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id; + + bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std); + if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200) + bttv_tda9880_setnorm(btv,btv->tvnorm); +} + static void bttv_crop_calc_limits(struct bttv_crop *c) { @@ -1285,7 +1298,6 @@ static int set_tvnorm(struct bttv *btv, unsigned int norm) { const struct bttv_tvnorm *tvnorm; - v4l2_std_id id; if (norm < 0 || norm >= BTTV_TVNORMS) return -EINVAL; @@ -1322,9 +1334,6 @@ set_tvnorm(struct bttv *btv, unsigned int norm) bttv_tda9880_setnorm(btv,norm); break; } - id = tvnorm->v4l2_id; - bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id); - return 0; } @@ -1350,6 +1359,7 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm) audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ? TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN)); set_tvnorm(btv, norm); + i2c_vidiocschan(btv); } static void init_irqreg(struct bttv *btv) @@ -1442,12 +1452,38 @@ static void bttv_reinit_bt848(struct bttv *btv) set_input(btv, btv->input, btv->tvnorm); } -static int bttv_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) +static int get_control(struct bttv *btv, struct v4l2_control *c) { - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; + struct video_audio va; + int i; + for (i = 0; i < BTTV_CTLS; i++) + if (bttv_ctls[i].id == c->id) + break; + if (i == BTTV_CTLS) + return -EINVAL; + if (btv->audio_hook && i >= 4 && i <= 8) { + memset(&va,0,sizeof(va)); + btv->audio_hook(btv,&va,0); + switch (c->id) { + case V4L2_CID_AUDIO_MUTE: + c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0; + break; + case V4L2_CID_AUDIO_VOLUME: + c->value = va.volume; + break; + case V4L2_CID_AUDIO_BALANCE: + c->value = va.balance; + break; + case V4L2_CID_AUDIO_BASS: + c->value = va.bass; + break; + case V4L2_CID_AUDIO_TREBLE: + c->value = va.treble; + break; + } + return 0; + } switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = btv->bright; @@ -1467,7 +1503,7 @@ static int bttv_g_ctrl(struct file *file, void *priv, case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c); + bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: @@ -1509,44 +1545,67 @@ static int bttv_g_ctrl(struct file *file, void *priv, return 0; } -static int bttv_s_ctrl(struct file *file, void *f, - struct v4l2_control *c) +static int set_control(struct bttv *btv, struct v4l2_control *c) { - int err; - int val; - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; + struct video_audio va; + int i,val; - err = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != err) - return err; + for (i = 0; i < BTTV_CTLS; i++) + if (bttv_ctls[i].id == c->id) + break; + if (i == BTTV_CTLS) + return -EINVAL; + if (btv->audio_hook && i >= 4 && i <= 8) { + memset(&va,0,sizeof(va)); + btv->audio_hook(btv,&va,0); + switch (c->id) { + case V4L2_CID_AUDIO_MUTE: + if (c->value) { + va.flags |= VIDEO_AUDIO_MUTE; + audio_mute(btv, 1); + } else { + va.flags &= ~VIDEO_AUDIO_MUTE; + audio_mute(btv, 0); + } + break; + case V4L2_CID_AUDIO_VOLUME: + va.volume = c->value; + break; + case V4L2_CID_AUDIO_BALANCE: + va.balance = c->value; + break; + case V4L2_CID_AUDIO_BASS: + va.bass = c->value; + break; + case V4L2_CID_AUDIO_TREBLE: + va.treble = c->value; + break; + } + btv->audio_hook(btv,&va,1); + return 0; + } switch (c->id) { case V4L2_CID_BRIGHTNESS: - bt848_bright(btv, c->value); + bt848_bright(btv,c->value); break; case V4L2_CID_HUE: - bt848_hue(btv, c->value); + bt848_hue(btv,c->value); break; case V4L2_CID_CONTRAST: - bt848_contrast(btv, c->value); + bt848_contrast(btv,c->value); break; case V4L2_CID_SATURATION: - bt848_sat(btv, c->value); + bt848_sat(btv,c->value); break; case V4L2_CID_AUDIO_MUTE: audio_mute(btv, c->value); /* fall through */ case V4L2_CID_AUDIO_VOLUME: - if (btv->volume_gpio) - btv->volume_gpio(btv, c->value); - - bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); - break; case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); + bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: @@ -1573,9 +1632,8 @@ static int bttv_s_ctrl(struct file *file, void *f, break; case V4L2_CID_PRIVATE_AGC_CRUSH: btv->opt_adc_crush = c->value; - btwrite(BT848_ADC_RESERVED | - (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); + btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); break; case V4L2_CID_PRIVATE_VCR_HACK: btv->opt_vcr_hack = c->value; @@ -1634,16 +1692,30 @@ static void bttv_field_count(struct bttv *btv) } } +static const struct bttv_format* +format_by_palette(int palette) +{ + unsigned int i; + + for (i = 0; i < BTTV_FORMATS; i++) { + if (-1 == bttv_formats[i].palette) + continue; + if (bttv_formats[i].palette == palette) + return bttv_formats+i; + } + return NULL; +} + static const struct bttv_format* format_by_fourcc(int fourcc) { unsigned int i; - for (i = 0; i < FORMATS; i++) { - if (-1 == formats[i].fourcc) + for (i = 0; i < BTTV_FORMATS; i++) { + if (-1 == bttv_formats[i].fourcc) continue; - if (formats[i].fourcc == fourcc) - return formats+i; + if (bttv_formats[i].fourcc == fourcc) + return bttv_formats+i; } return NULL; } @@ -1661,7 +1733,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, dprintk("switch_overlay: enter [new=%p]\n",new); if (new) - new->vb.state = VIDEOBUF_DONE; + new->vb.state = STATE_DONE; spin_lock_irqsave(&btv->s_lock,flags); old = btv->screen; btv->screen = new; @@ -1772,7 +1844,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, } /* alloc risc memory */ - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) goto fail; @@ -1782,7 +1854,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, if (0 != (rc = bttv_buffer_risc(btv,buf))) goto fail; - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; return 0; fail: @@ -1821,7 +1893,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_fh *fh = q->priv_data; struct bttv *btv = fh->btv; - buf->vb.state = VIDEOBUF_QUEUED; + buf->vb.state = STATE_QUEUED; list_add_tail(&buf->vb.queue,&btv->capture); if (!btv->curr.frame_irq) { btv->loop_irq |= 1; @@ -1844,255 +1916,395 @@ static struct videobuf_queue_ops bttv_video_qops = { .buf_release = buffer_release, }; -static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) { - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - unsigned int i; - int err; - - err = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != err) - return err; + switch (cmd) { + case BTTV_VERSION: + return BTTV_VERSION_CODE; - for (i = 0; i < BTTV_TVNORMS; i++) - if (*id & bttv_tvnorms[i].v4l2_id) - break; - if (i == BTTV_TVNORMS) - return -EINVAL; + /* *** v4l1 *** ************************************************ */ + case VIDIOCGFREQ: + { + unsigned long *freq = arg; + *freq = btv->freq; + return 0; + } + case VIDIOCSFREQ: + { + struct v4l2_frequency freq; - mutex_lock(&btv->lock); - set_tvnorm(btv, i); - mutex_unlock(&btv->lock); + memset(&freq, 0, sizeof(freq)); + freq.frequency = *(unsigned long *)arg; + mutex_lock(&btv->lock); + freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + btv->freq = *(unsigned long *)arg; + bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq); + if (btv->has_matchbox && btv->radio_user) + tea5757_set_freq(btv,*(unsigned long *)arg); + mutex_unlock(&btv->lock); + return 0; + } - return 0; -} + case VIDIOCGTUNER: + { + struct video_tuner *v = arg; -static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (v->tuner) /* Only tuner 0 */ + return -EINVAL; + strcpy(v->name, "Television"); + v->rangelow = 0; + v->rangehigh = 0x7FFFFFFF; + v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v->mode = btv->tvnorm; + v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; + bttv_call_i2c_clients(btv,cmd,v); + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner *v = arg; - if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) - *id = V4L2_STD_625_50; - else - *id = V4L2_STD_525_60; - return 0; -} + if (v->tuner) /* Only tuner 0 */ + return -EINVAL; + if (v->mode >= BTTV_TVNORMS) + return -EINVAL; -static int bttv_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - unsigned int n; + mutex_lock(&btv->lock); + set_tvnorm(btv,v->mode); + bttv_call_i2c_clients(btv,cmd,v); + mutex_unlock(&btv->lock); + return 0; + } - n = i->index; + case VIDIOCGCHAN: + { + struct video_channel *v = arg; + unsigned int channel = v->channel; - if (n >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; + if (channel >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; + v->tuners=0; + v->flags = VIDEO_VC_AUDIO; + v->type = VIDEO_TYPE_CAMERA; + v->norm = btv->tvnorm; + if (channel == bttv_tvcards[btv->c.type].tuner) { + strcpy(v->name,"Television"); + v->flags|=VIDEO_VC_TUNER; + v->type=VIDEO_TYPE_TV; + v->tuners=1; + } else if (channel == btv->svhs) { + strcpy(v->name,"S-Video"); + } else { + sprintf(v->name,"Composite%d",channel); + } + return 0; + } + case VIDIOCSCHAN: + { + struct video_channel *v = arg; + unsigned int channel = v->channel; - memset(i, 0, sizeof(*i)); + if (channel >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; + if (v->norm >= BTTV_TVNORMS) + return -EINVAL; - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; + mutex_lock(&btv->lock); + if (channel == btv->input && + v->norm == btv->tvnorm) { + /* nothing to do */ + mutex_unlock(&btv->lock); + return 0; + } - if (i->index == bttv_tvcards[btv->c.type].tuner) { - sprintf(i->name, "Television"); - i->type = V4L2_INPUT_TYPE_TUNER; - i->tuner = 0; - } else if (i->index == btv->svhs) { - sprintf(i->name, "S-Video"); - } else { - sprintf(i->name, "Composite%d", i->index); + set_input(btv, v->channel, v->norm); + mutex_unlock(&btv->lock); + return 0; } - if (i->index == btv->input) { - __u32 dstatus = btread(BT848_DSTATUS); - if (0 == (dstatus & BT848_DSTATUS_PRES)) - i->status |= V4L2_IN_ST_NO_SIGNAL; - if (0 == (dstatus & BT848_DSTATUS_HLOC)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - } + case VIDIOCGAUDIO: + { + struct video_audio *v = arg; - for (n = 0; n < BTTV_TVNORMS; n++) - i->std |= bttv_tvnorms[n].v4l2_id; + memset(v,0,sizeof(*v)); + strcpy(v->name,"Television"); + v->flags |= VIDEO_AUDIO_MUTABLE; + v->mode = VIDEO_SOUND_MONO; - return 0; -} + mutex_lock(&btv->lock); + bttv_call_i2c_clients(btv,cmd,v); -static int bttv_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; + /* card specific hooks */ + if (btv->audio_hook) + btv->audio_hook(btv,v,0); - *i = btv->input; - return 0; -} + mutex_unlock(&btv->lock); + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio *v = arg; + unsigned int audio = v->audio; -static int bttv_s_input(struct file *file, void *priv, unsigned int i) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; + if (audio >= bttv_tvcards[btv->c.type].audio_inputs) + return -EINVAL; - int err; + mutex_lock(&btv->lock); + audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0); + bttv_call_i2c_clients(btv,cmd,v); - err = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != err) - return err; + /* card specific hooks */ + if (btv->audio_hook) + btv->audio_hook(btv,v,1); - if (i > bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; + mutex_unlock(&btv->lock); + return 0; + } - mutex_lock(&btv->lock); - set_input(btv, i, btv->tvnorm); - mutex_unlock(&btv->lock); - return 0; -} + /* *** v4l2 *** ************************************************ */ + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *e = arg; + unsigned int index = e->index; -static int bttv_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int err; + if (index >= BTTV_TVNORMS) + return -EINVAL; + v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id, + bttv_tvnorms[e->index].name); + e->index = index; + return 0; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; + *id = bttv_tvnorms[btv->tvnorm].v4l2_id; + return 0; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + unsigned int i; - err = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != err) - return err; + for (i = 0; i < BTTV_TVNORMS; i++) + if (*id & bttv_tvnorms[i].v4l2_id) + break; + if (i == BTTV_TVNORMS) + return -EINVAL; - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; + mutex_lock(&btv->lock); + set_tvnorm(btv,i); + i2c_vidiocschan(btv); + mutex_unlock(&btv->lock); + return 0; + } + case VIDIOC_QUERYSTD: + { + v4l2_std_id *id = arg; - if (0 != t->index) - return -EINVAL; + if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) + *id = V4L2_STD_625_50; + else + *id = V4L2_STD_525_60; + return 0; + } - mutex_lock(&btv->lock); - bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + unsigned int n; - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 1); + n = i->index; + if (n >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; + memset(i,0,sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + i->audioset = 1; + if (i->index == bttv_tvcards[btv->c.type].tuner) { + sprintf(i->name, "Television"); + i->type = V4L2_INPUT_TYPE_TUNER; + i->tuner = 0; + } else if (i->index == btv->svhs) { + sprintf(i->name, "S-Video"); + } else { + sprintf(i->name,"Composite%d",i->index); + } + if (i->index == btv->input) { + __u32 dstatus = btread(BT848_DSTATUS); + if (0 == (dstatus & BT848_DSTATUS_PRES)) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if (0 == (dstatus & BT848_DSTATUS_HLOC)) + i->status |= V4L2_IN_ST_NO_H_LOCK; + } + for (n = 0; n < BTTV_TVNORMS; n++) + i->std |= bttv_tvnorms[n].v4l2_id; + return 0; + } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = btv->input; + return 0; + } + case VIDIOC_S_INPUT: + { + unsigned int *i = arg; - mutex_unlock(&btv->lock); + if (*i > bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; + mutex_lock(&btv->lock); + set_input(btv, *i, btv->tvnorm); + mutex_unlock(&btv->lock); + return 0; + } - return 0; -} + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; -static int bttv_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int err; + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + memset(t,0,sizeof(*t)); + t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; + if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) + t->signal = 0xffff; + + if (btv->audio_hook) { + /* Hmmm ... */ + struct video_audio va; + memset(&va, 0, sizeof(struct video_audio)); + btv->audio_hook(btv,&va,0); + t->audmode = V4L2_TUNER_MODE_MONO; + t->rxsubchans = V4L2_TUNER_SUB_MONO; + if(va.mode & VIDEO_SOUND_STEREO) { + t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + } + if(va.mode & VIDEO_SOUND_LANG2) { + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_LANG1 + | V4L2_TUNER_SUB_LANG2; + } + } + /* FIXME: fill capability+audmode */ + mutex_unlock(&btv->lock); + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; - err = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != err) - return err; + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); + if (btv->audio_hook) { + struct video_audio va; + memset(&va, 0, sizeof(struct video_audio)); + if (t->audmode == V4L2_TUNER_MODE_MONO) + va.mode = VIDEO_SOUND_MONO; + else if (t->audmode == V4L2_TUNER_MODE_STEREO || + t->audmode == V4L2_TUNER_MODE_LANG1_LANG2) + va.mode = VIDEO_SOUND_STEREO; + else if (t->audmode == V4L2_TUNER_MODE_LANG1) + va.mode = VIDEO_SOUND_LANG1; + else if (t->audmode == V4L2_TUNER_MODE_LANG2) + va.mode = VIDEO_SOUND_LANG2; + btv->audio_hook(btv,&va,1); + } + mutex_unlock(&btv->lock); + return 0; + } - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = btv->freq; + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; - return 0; -} + memset(f,0,sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = btv->freq; + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int bttv_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int err; + if (unlikely(f->tuner != 0)) + return -EINVAL; + if (unlikely (f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + mutex_lock(&btv->lock); + btv->freq = f->frequency; + bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f); + if (btv->has_matchbox && btv->radio_user) + tea5757_set_freq(btv,btv->freq); + mutex_unlock(&btv->lock); + return 0; + } + case VIDIOC_LOG_STATUS: + { + printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr); + bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); + printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); + return 0; + } +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *reg = arg; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + if (cmd == VIDIOC_DBG_G_REGISTER) + reg->val = btread(reg->reg); + else + btwrite(reg->val, reg->reg); + return 0; + } +#endif - err = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != err) - return err; + default: + return -ENOIOCTLCMD; - if (unlikely(f->tuner != 0)) - return -EINVAL; - if (unlikely(f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - mutex_lock(&btv->lock); - btv->freq = f->frequency; - bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv, btv->freq); - mutex_unlock(&btv->lock); + } return 0; } -static int bttv_log_status(struct file *file, void *f) +/* Given cropping boundaries b and the scaled width and height of a + single field or frame, which must not exceed hardware limits, this + function adjusts the cropping parameters c. */ +static void +bttv_crop_adjust (struct bttv_crop * c, + const struct v4l2_rect * b, + __s32 width, + __s32 height, + enum v4l2_field field) { - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; + __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); + __s32 max_left; + __s32 max_top; - printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); - bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); - printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n", - btv->c.nr, btv->c.nr); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int bttv_g_register(struct file *file, void *f, - struct v4l2_register *reg) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - reg->val = btread(reg->reg); - - return 0; -} - -static int bttv_s_register(struct file *file, void *f, - struct v4l2_register *reg) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - btwrite(reg->val, reg->reg); - - return 0; -} -#endif - -/* Given cropping boundaries b and the scaled width and height of a - single field or frame, which must not exceed hardware limits, this - function adjusts the cropping parameters c. */ -static void -bttv_crop_adjust (struct bttv_crop * c, - const struct v4l2_rect * b, - __s32 width, - __s32 height, - enum v4l2_field field) -{ - __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field); - __s32 max_left; - __s32 max_top; - - if (width < c->min_scaled_width) { - /* Max. hor. scale factor 16:1. */ - c->rect.width = width * 16; - } else if (width > c->max_scaled_width) { - /* Min. hor. scale factor 1:1. */ - c->rect.width = width; + if (width < c->min_scaled_width) { + /* Max. hor. scale factor 16:1. */ + c->rect.width = width * 16; + } else if (width > c->max_scaled_width) { + /* Min. hor. scale factor 1:1. */ + c->rect.width = width; max_left = b->left + b->width - width; max_left = min(max_left, (__s32) MAX_HDELAY); @@ -2447,681 +2659,983 @@ pix_format_set_size (struct v4l2_pix_format * f, } } -static int bttv_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f) { - struct bttv_fh *fh = priv; - - pix_format_set_size(&f->fmt.pix, fh->fmt, - fh->width, fh->height); - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - - return 0; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format)); + pix_format_set_size (&f->fmt.pix, fh->fmt, + fh->width, fh->height); + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + return 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + memset(&f->fmt.win,0,sizeof(struct v4l2_window)); + f->fmt.win.w = fh->ov.w; + f->fmt.win.field = fh->ov.field; + return 0; + case V4L2_BUF_TYPE_VBI_CAPTURE: + bttv_vbi_get_fmt(fh, &f->fmt.vbi); + return 0; + default: + return -EINVAL; + } } -static int bttv_g_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) +static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv, + struct v4l2_format *f, int adjust_crop) { - struct bttv_fh *fh = priv; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + const struct bttv_format *fmt; + enum v4l2_field field; + __s32 width, height; + int rc; - f->fmt.win.w = fh->ov.w; - f->fmt.win.field = fh->ov.field; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; - return 0; -} + field = f->fmt.pix.field; + if (V4L2_FIELD_ANY == field) { + __s32 height2; -static int bttv_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - const struct bttv_format *fmt; - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - enum v4l2_field field; - __s32 width, height; - int rc; + height2 = btv->crop[!!fh->do_crop].rect.height >> 1; + field = (f->fmt.pix.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + if (V4L2_FIELD_SEQ_BT == field) + field = V4L2_FIELD_SEQ_TB; + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_SEQ_TB: + if (fmt->flags & FORMAT_FLAGS_PLANAR) + return -EINVAL; + break; + default: + return -EINVAL; + } - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; + width = f->fmt.pix.width; + height = f->fmt.pix.height; - field = f->fmt.pix.field; + rc = limit_scaled_size(fh, &width, &height, field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + adjust_crop); + if (0 != rc) + return rc; - if (V4L2_FIELD_ANY == field) { - __s32 height2; + /* update data for the application */ + f->fmt.pix.field = field; + pix_format_set_size(&f->fmt.pix, fmt, width, height); - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (f->fmt.pix.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; + return 0; } - - if (V4L2_FIELD_SEQ_BT == field) - field = V4L2_FIELD_SEQ_TB; - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - case V4L2_FIELD_INTERLACED: - break; - case V4L2_FIELD_SEQ_TB: - if (fmt->flags & FORMAT_FLAGS_PLANAR) - return -EINVAL; - break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + return verify_window(fh, &f->fmt.win, + /* adjust_size */ 1, + /* adjust_crop */ 0); + case V4L2_BUF_TYPE_VBI_CAPTURE: + return bttv_vbi_try_fmt(fh, &f->fmt.vbi); default: return -EINVAL; } - - width = f->fmt.pix.width; - height = f->fmt.pix.height; - - rc = limit_scaled_size(fh, &width, &height, field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - /* adjust_crop */ 0); - if (0 != rc) - return rc; - - /* update data for the application */ - f->fmt.pix.field = field; - pix_format_set_size(&f->fmt.pix, fmt, width, height); - - return 0; } -static int bttv_try_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - - return verify_window(fh, &f->fmt.win, - /* adjust_size */ 1, - /* adjust_crop */ 0); -} - -static int bttv_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv, + struct v4l2_format *f) { int retval; - const struct bttv_format *fmt; - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - __s32 width, height; - enum v4l2_field field; - - retval = bttv_switch_type(fh, f->type); - if (0 != retval) - return retval; - - retval = bttv_try_fmt_cap(file, priv, f); - if (0 != retval) - return retval; - width = f->fmt.pix.width; - height = f->fmt.pix.height; - field = f->fmt.pix.field; - - retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - /* adjust_crop */ 1); - if (0 != retval) - return retval; - - f->fmt.pix.field = field; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - - /* update our state informations */ - mutex_lock(&fh->cap.lock); - fh->fmt = fmt; - fh->cap.field = f->fmt.pix.field; - fh->cap.last = V4L2_FIELD_NONE; - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - btv->init.fmt = fmt; - btv->init.width = f->fmt.pix.width; - btv->init.height = f->fmt.pix.height; - mutex_unlock(&fh->cap.lock); + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + const struct bttv_format *fmt; - return 0; -} + retval = bttv_switch_type(fh,f->type); + if (0 != retval) + return retval; + retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1); + if (0 != retval) + return retval; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); -static int bttv_s_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; + /* update our state informations */ + mutex_lock(&fh->cap.lock); + fh->fmt = fmt; + fh->cap.field = f->fmt.pix.field; + fh->cap.last = V4L2_FIELD_NONE; + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + btv->init.fmt = fmt; + btv->init.width = f->fmt.pix.width; + btv->init.height = f->fmt.pix.height; + mutex_unlock(&fh->cap.lock); - if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return 0; + } + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + return setup_window(fh, btv, &f->fmt.win, 1); + case V4L2_BUF_TYPE_VBI_CAPTURE: + retval = bttv_switch_type(fh,f->type); + if (0 != retval) + return retval; + return bttv_vbi_set_fmt(fh, &f->fmt.vbi); + default: return -EINVAL; } - - return setup_window(fh, btv, &f->fmt.win, 1); } -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +static int bttv_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { - int retval; - unsigned int i; - struct bttv_fh *fh = priv; + struct bttv_fh *fh = file->private_data; + struct bttv *btv = fh->btv; + unsigned long flags; + int retval = 0; - mutex_lock(&fh->cap.lock); - retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, - V4L2_MEMORY_MMAP); - if (retval < 0) { - mutex_unlock(&fh->cap.lock); - return retval; - } + if (bttv_debug > 1) + v4l_print_ioctl(btv->c.name, cmd); + + if (btv->errors) + bttv_reinit_bt848(btv); + + switch (cmd) { + case VIDIOCSFREQ: + case VIDIOCSTUNER: + case VIDIOCSCHAN: + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + retval = v4l2_prio_check(&btv->prio,&fh->prio); + if (0 != retval) + return retval; + }; - gbuffers = retval; - memset(mbuf, 0, sizeof(*mbuf)); - mbuf->frames = gbuffers; - mbuf->size = gbuffers * gbufsize; + switch (cmd) { - for (i = 0; i < gbuffers; i++) - mbuf->offsets[i] = i * gbufsize; + /* *** v4l1 *** ************************************************ */ + case VIDIOCGCAP: + { + struct video_capability *cap = arg; - mutex_unlock(&fh->cap.lock); - return 0; -} -#endif + memset(cap,0,sizeof(*cap)); + strcpy(cap->name,btv->video_dev->name); + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + /* vbi */ + cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; + } else { + /* others */ + cap->type = VID_TYPE_CAPTURE| + VID_TYPE_TUNER| + VID_TYPE_CLIPPING| + VID_TYPE_SCALES; + if (no_overlay <= 0) + cap->type |= VID_TYPE_OVERLAY; + + cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; + cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; + cap->minwidth = 48; + cap->minheight = 32; + } + cap->channels = bttv_tvcards[btv->c.type].video_inputs; + cap->audios = bttv_tvcards[btv->c.type].audio_inputs; + return 0; + } -static int bttv_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; + case VIDIOCGPICT: + { + struct video_picture *pic = arg; + + memset(pic,0,sizeof(*pic)); + pic->brightness = btv->bright; + pic->contrast = btv->contrast; + pic->hue = btv->hue; + pic->colour = btv->saturation; + if (fh->fmt) { + pic->depth = fh->fmt->depth; + pic->palette = fh->fmt->palette; + } + return 0; + } + case VIDIOCSPICT: + { + struct video_picture *pic = arg; + const struct bttv_format *fmt; - if (0 == v4l2) - return -EINVAL; + fmt = format_by_palette(pic->palette); + if (NULL == fmt) + return -EINVAL; + mutex_lock(&fh->cap.lock); + if (fmt->flags & FORMAT_FLAGS_RAW) { + /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL * + RAW_LINES * 2. F1 is stored at offset 0, F2 + at buffer size / 2. */ + fh->width = RAW_BPL; + fh->height = gbufsize / RAW_BPL; + btv->init.width = RAW_BPL; + btv->init.height = gbufsize / RAW_BPL; + } + fh->ovfmt = fmt; + fh->fmt = fmt; + btv->init.ovfmt = fmt; + btv->init.fmt = fmt; + if (bigendian) { + /* dirty hack time: swap bytes for overlay if the + display adaptor is big endian (insmod option) */ + if (fmt->palette == VIDEO_PALETTE_RGB555 || + fmt->palette == VIDEO_PALETTE_RGB565 || + fmt->palette == VIDEO_PALETTE_RGB32) { + fh->ovfmt = fmt+1; + } + } + bt848_bright(btv,pic->brightness); + bt848_contrast(btv,pic->contrast); + bt848_hue(btv,pic->hue); + bt848_sat(btv,pic->colour); + mutex_unlock(&fh->cap.lock); + return 0; + } - strlcpy(cap->driver, "bttv", sizeof(cap->driver)); - strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - - if (bttv_tvcards[btv->c.type].tuner != UNSET && - bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} + case VIDIOCGWIN: + { + struct video_window *win = arg; -static int bttv_enum_fmt_vbi(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (0 != f->index) - return -EINVAL; + memset(win,0,sizeof(*win)); + win->x = fh->ov.w.left; + win->y = fh->ov.w.top; + win->width = fh->ov.w.width; + win->height = fh->ov.w.height; + return 0; + } + case VIDIOCSWIN: + { + struct video_window *win = arg; + struct v4l2_window w2; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description, "vbi data"); + if (no_overlay > 0) { + printk ("VIDIOCSWIN: no_overlay\n"); + return -EINVAL; + } - return 0; -} + w2.field = V4L2_FIELD_ANY; + w2.w.left = win->x; + w2.w.top = win->y; + w2.w.width = win->width; + w2.w.height = win->height; + w2.clipcount = win->clipcount; + w2.clips = (struct v4l2_clip __user *)win->clips; + retval = setup_window(fh, btv, &w2, 0); + if (0 == retval) { + /* on v4l1 this ioctl affects the read() size too */ + fh->width = fh->ov.w.width; + fh->height = fh->ov.w.height; + btv->init.width = fh->ov.w.width; + btv->init.height = fh->ov.w.height; + } + return retval; + } -static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) -{ - int index = -1, i; + case VIDIOCGFBUF: + { + struct video_buffer *fbuf = arg; + + fbuf->base = btv->fbuf.base; + fbuf->width = btv->fbuf.fmt.width; + fbuf->height = btv->fbuf.fmt.height; + fbuf->bytesperline = btv->fbuf.fmt.bytesperline; + if (fh->ovfmt) + fbuf->depth = fh->ovfmt->depth; + else { + if (fbuf->width) + fbuf->depth = ((fbuf->bytesperline<<3) + + (fbuf->width-1) ) + /fbuf->width; + else + fbuf->depth = 0; + } + return 0; + } + case VIDIOCSFBUF: + { + struct video_buffer *fbuf = arg; + const struct bttv_format *fmt; + unsigned long end; + + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + end = (unsigned long)fbuf->base + + fbuf->height * fbuf->bytesperline; + mutex_lock(&fh->cap.lock); + retval = -EINVAL; - for (i = 0; i < FORMATS; i++) { - if (formats[i].fourcc != -1) - index++; - if ((unsigned int)index == f->index) + switch (fbuf->depth) { + case 8: + fmt = format_by_palette(VIDEO_PALETTE_HI240); + break; + case 16: + fmt = format_by_palette(VIDEO_PALETTE_RGB565); + break; + case 24: + fmt = format_by_palette(VIDEO_PALETTE_RGB24); break; + case 32: + fmt = format_by_palette(VIDEO_PALETTE_RGB32); + break; + case 15: + fbuf->depth = 16; + fmt = format_by_palette(VIDEO_PALETTE_RGB555); + break; + default: + fmt = NULL; + break; + } + if (NULL == fmt) + goto fh_unlock_and_return; + + fh->ovfmt = fmt; + fh->fmt = fmt; + btv->init.ovfmt = fmt; + btv->init.fmt = fmt; + btv->fbuf.base = fbuf->base; + btv->fbuf.fmt.width = fbuf->width; + btv->fbuf.fmt.height = fbuf->height; + if (fbuf->bytesperline) + btv->fbuf.fmt.bytesperline = fbuf->bytesperline; + else + btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8; + mutex_unlock(&fh->cap.lock); + return 0; } - if (FORMATS == i) - return -EINVAL; - - f->pixelformat = formats[i].fourcc; - strlcpy(f->description, formats[i].name, sizeof(f->description)); - return i; -} - -static int bttv_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int rc = bttv_enum_fmt_cap_ovr(f); + case VIDIOCCAPTURE: + case VIDIOC_OVERLAY: + { + struct bttv_buffer *new; + int *on = arg; - if (rc < 0) - return rc; + if (*on) { + /* verify args */ + if (NULL == btv->fbuf.base) + return -EINVAL; + if (!fh->ov.setup_ok) { + dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); + return -EINVAL; + } + } - return 0; -} + if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) + return -EBUSY; -static int bttv_enum_fmt_overlay(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - int rc; + mutex_lock(&fh->cap.lock); + if (*on) { + fh->ov.tvnorm = btv->tvnorm; + new = videobuf_pci_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + } else { + new = NULL; + } - if (no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; + /* switch over */ + retval = bttv_switch_overlay(btv,fh,new); + mutex_unlock(&fh->cap.lock); + return retval; } - rc = bttv_enum_fmt_cap_ovr(f); - - if (rc < 0) - return rc; - - if (!(formats[rc].flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - - return 0; -} - -static int bttv_g_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - *fb = btv->fbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - if (fh->ovfmt) - fb->fmt.pixelformat = fh->ovfmt->fourcc; - return 0; -} - -static int bttv_overlay(struct file *file, void *f, unsigned int on) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - struct bttv_buffer *new; - int retval; - - if (on) { - /* verify args */ - if (NULL == btv->fbuf.base) - return -EINVAL; - if (!fh->ov.setup_ok) { - dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr); - return -EINVAL; - } - } + case VIDIOCGMBUF: + { + struct video_mbuf *mbuf = arg; + unsigned int i; - if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY)) - return -EBUSY; + retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize, + V4L2_MEMORY_MMAP); + if (retval < 0) + return retval; - mutex_lock(&fh->cap.lock); - if (on) { - fh->ov.tvnorm = btv->tvnorm; - new = videobuf_pci_alloc(sizeof(*new)); - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - } else { - new = NULL; + gbuffers = retval; + memset(mbuf,0,sizeof(*mbuf)); + mbuf->frames = gbuffers; + mbuf->size = gbuffers * gbufsize; + for (i = 0; i < gbuffers; i++) + mbuf->offsets[i] = i * gbufsize; + return 0; } + case VIDIOCMCAPTURE: + { + struct video_mmap *vm = arg; + struct bttv_buffer *buf; + enum v4l2_field field; + __s32 height2; + int res; - /* switch over */ - retval = bttv_switch_overlay(btv, fh, new); - mutex_unlock(&fh->cap.lock); - return retval; -} - -static int bttv_s_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct bttv_format *fmt; - int retval; + if (vm->frame >= VIDEO_MAX_FRAME) + return -EINVAL; - if (!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; + res = bttv_resource(fh); + if (!check_alloc_btres(btv, fh, res)) + return -EBUSY; - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; - if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; + mutex_lock(&fh->cap.lock); + retval = -EINVAL; + buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame]; + if (NULL == buf) + goto fh_unlock_and_return; + if (0 == buf->vb.baddr) + goto fh_unlock_and_return; + if (buf->vb.state == STATE_QUEUED || + buf->vb.state == STATE_ACTIVE) + goto fh_unlock_and_return; - retval = -EINVAL; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - __s32 width = fb->fmt.width; - __s32 height = fb->fmt.height; - - retval = limit_scaled_size(fh, &width, &height, - V4L2_FIELD_INTERLACED, - /* width_mask */ ~3, - /* width_bias */ 2, - /* adjust_size */ 0, - /* adjust_crop */ 0); + height2 = btv->crop[!!fh->do_crop].rect.height >> 1; + field = (vm->height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + retval = bttv_prepare_buffer(&fh->cap,btv,buf, + format_by_palette(vm->format), + vm->width,vm->height,field); if (0 != retval) - return retval; + goto fh_unlock_and_return; + btv->init.width = vm->width; + btv->init.height = vm->height; + spin_lock_irqsave(&btv->s_lock,flags); + buffer_queue(&fh->cap,&buf->vb); + spin_unlock_irqrestore(&btv->s_lock,flags); + mutex_unlock(&fh->cap.lock); + return 0; } + case VIDIOCSYNC: + { + int *frame = arg; + struct bttv_buffer *buf; - /* ok, accept it */ - mutex_lock(&fh->cap.lock); - btv->fbuf.base = fb->base; - btv->fbuf.fmt.width = fb->fmt.width; - btv->fbuf.fmt.height = fb->fmt.height; - if (0 != fb->fmt.bytesperline) - btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; - - retval = 0; - fh->ovfmt = fmt; - btv->init.ovfmt = fmt; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - fh->ov.w.left = 0; - fh->ov.w.top = 0; - fh->ov.w.width = fb->fmt.width; - fh->ov.w.height = fb->fmt.height; - btv->init.ov.w.width = fb->fmt.width; - btv->init.ov.w.height = fb->fmt.height; - kfree(fh->ov.clips); - fh->ov.clips = NULL; - fh->ov.nclips = 0; - - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; + if (*frame >= VIDEO_MAX_FRAME) + return -EINVAL; - new = videobuf_pci_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - retval = bttv_switch_overlay(btv, fh, new); + mutex_lock(&fh->cap.lock); + retval = -EINVAL; + buf = (struct bttv_buffer *)fh->cap.bufs[*frame]; + if (NULL == buf) + goto fh_unlock_and_return; + retval = videobuf_waiton(&buf->vb,0,1); + if (0 != retval) + goto fh_unlock_and_return; + switch (buf->vb.state) { + case STATE_ERROR: + retval = -EIO; + /* fall through */ + case STATE_DONE: + { + struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); + videobuf_dma_sync(&fh->cap,dma); + bttv_dma_free(&fh->cap,btv,buf); + break; } + default: + retval = -EINVAL; + break; + } + mutex_unlock(&fh->cap.lock); + return retval; } - mutex_unlock(&fh->cap.lock); - return retval; -} -static int bttv_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct bttv_fh *fh = priv; - return videobuf_reqbufs(bttv_queue(fh), p); -} + case VIDIOCGVBIFMT: + if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) { + retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); + if (0 != retval) + return retval; + } + + /* fall through */ -static int bttv_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - return videobuf_querybuf(bttv_queue(fh), b); -} + case VIDIOCSVBIFMT: + return v4l_compat_translate_ioctl(inode, file, cmd, + arg, bttv_do_ioctl); + + case BTTV_VERSION: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGCHAN: + case VIDIOCSCHAN: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + return bttv_common_ioctls(btv,cmd,arg); + + /* *** v4l2 *** ************************************************ */ + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; -static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int res = bttv_resource(fh); + if (0 == v4l2) + return -EINVAL; + memset(cap, 0, sizeof (*cap)); + strlcpy(cap->driver, "bttv", sizeof (cap->driver)); + strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card)); + snprintf(cap->bus_info, sizeof (cap->bus_info), + "PCI:%s", pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + + if (bttv_tvcards[btv->c.type].tuner != UNSET && + bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; + } - if (!check_alloc_btres(btv, fh, res)) - return -EBUSY; + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type; + unsigned int i; + int index; + + type = f->type; + if (V4L2_BUF_TYPE_VBI_CAPTURE == type) { + /* vbi */ + index = f->index; + if (0 != index) + return -EINVAL; + memset(f,0,sizeof(*f)); + f->index = index; + f->type = type; + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description,"vbi data"); + return 0; + } - return videobuf_qbuf(bttv_queue(fh), b); -} + /* video capture + overlay */ + index = -1; + for (i = 0; i < BTTV_FORMATS; i++) { + if (bttv_formats[i].fourcc != -1) + index++; + if ((unsigned int)index == f->index) + break; + } + if (BTTV_FORMATS == i) + return -EINVAL; -static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct bttv_fh *fh = priv; - return videobuf_dqbuf(bttv_queue(fh), b, - file->f_flags & O_NONBLOCK); -} + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + break; + default: + return -EINVAL; + } + memset(f,0,sizeof(*f)); + f->index = index; + f->type = type; + f->pixelformat = bttv_formats[i].fourcc; + strlcpy(f->description,bttv_formats[i].name,sizeof(f->description)); + return 0; + } -static int bttv_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int res = bttv_resource(fh); + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = arg; + return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0); + } + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + return bttv_g_fmt(fh,f); + } + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + return bttv_s_fmt(fh,btv,f); + } - if (!check_alloc_btres(btv, fh, res)) - return -EBUSY; - return videobuf_streamon(bttv_queue(fh)); -} + case VIDIOC_G_FBUF: + { + struct v4l2_framebuffer *fb = arg; + *fb = btv->fbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + if (fh->ovfmt) + fb->fmt.pixelformat = fh->ovfmt->fourcc; + return 0; + } + case VIDIOC_S_FBUF: + { + struct v4l2_framebuffer *fb = arg; + const struct bttv_format *fmt; -static int bttv_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - int retval; - int res = bttv_resource(fh); + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; + retval = -EINVAL; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + __s32 width = fb->fmt.width; + __s32 height = fb->fmt.height; + + retval = limit_scaled_size(fh, &width, &height, + V4L2_FIELD_INTERLACED, + /* width_mask */ ~3, + /* width_bias */ 2, + /* adjust_size */ 0, + /* adjust_crop */ 0); + if (0 != retval) + return retval; + } - retval = videobuf_streamoff(bttv_queue(fh)); - if (retval < 0) + /* ok, accept it */ + mutex_lock(&fh->cap.lock); + btv->fbuf.base = fb->base; + btv->fbuf.fmt.width = fb->fmt.width; + btv->fbuf.fmt.height = fb->fmt.height; + if (0 != fb->fmt.bytesperline) + btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; + else + btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; + + retval = 0; + fh->ovfmt = fmt; + btv->init.ovfmt = fmt; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + fh->ov.w.left = 0; + fh->ov.w.top = 0; + fh->ov.w.width = fb->fmt.width; + fh->ov.w.height = fb->fmt.height; + btv->init.ov.w.width = fb->fmt.width; + btv->init.ov.w.height = fb->fmt.height; + kfree(fh->ov.clips); + fh->ov.clips = NULL; + fh->ov.nclips = 0; + + if (check_btres(fh, RESOURCE_OVERLAY)) { + struct bttv_buffer *new; + + new = videobuf_pci_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new); + retval = bttv_switch_overlay(btv,fh,new); + } + } + mutex_unlock(&fh->cap.lock); return retval; - free_btres(btv, fh, res); - return 0; -} + } -static int bttv_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - const struct v4l2_queryctrl *ctrl; + case VIDIOC_REQBUFS: + return videobuf_reqbufs(bttv_queue(fh),arg); - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; + case VIDIOC_QUERYBUF: + return videobuf_querybuf(bttv_queue(fh),arg); - if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) - *c = no_ctl; - else { - ctrl = ctrl_by_id(c->id); + case VIDIOC_QBUF: + { + int res = bttv_resource(fh); - *c = (NULL != ctrl) ? *ctrl : no_ctl; + if (!check_alloc_btres(btv, fh, res)) + return -EBUSY; + return videobuf_qbuf(bttv_queue(fh),arg); } - return 0; -} - -static int bttv_g_parm(struct file *file, void *f, - struct v4l2_streamparm *parm) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - struct v4l2_standard s; - - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, - bttv_tvnorms[btv->tvnorm].name); - parm->parm.capture.timeperframe = s.frameperiod; - return 0; -} + case VIDIOC_DQBUF: + return videobuf_dqbuf(bttv_queue(fh),arg, + file->f_flags & O_NONBLOCK); -static int bttv_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; + case VIDIOC_STREAMON: + { + int res = bttv_resource(fh); - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; + if (!check_alloc_btres(btv,fh,res)) + return -EBUSY; + return videobuf_streamon(bttv_queue(fh)); + } + case VIDIOC_STREAMOFF: + { + int res = bttv_resource(fh); - mutex_lock(&btv->lock); - memset(t, 0, sizeof(*t)); - t->rxsubchans = V4L2_TUNER_SUB_MONO; - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); - strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; - t->type = V4L2_TUNER_ANALOG_TV; - if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) - t->signal = 0xffff; - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 0); + retval = videobuf_streamoff(bttv_queue(fh)); + if (retval < 0) + return retval; + free_btres(btv,fh,res); + return 0; + } - mutex_unlock(&btv->lock); - return 0; -} + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *c = arg; + int i; -static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + for (i = 0; i < BTTV_CTLS; i++) + if (bttv_ctls[i].id == c->id) + break; + if (i == BTTV_CTLS) { + *c = no_ctl; + return 0; + } + *c = bttv_ctls[i]; + if (btv->audio_hook && i >= 4 && i <= 8) { + struct video_audio va; + memset(&va,0,sizeof(va)); + btv->audio_hook(btv,&va,0); + switch (bttv_ctls[i].id) { + case V4L2_CID_AUDIO_VOLUME: + if (!(va.flags & VIDEO_AUDIO_VOLUME)) + *c = no_ctl; + break; + case V4L2_CID_AUDIO_BALANCE: + if (!(va.flags & VIDEO_AUDIO_BALANCE)) + *c = no_ctl; + break; + case V4L2_CID_AUDIO_BASS: + if (!(va.flags & VIDEO_AUDIO_BASS)) + *c = no_ctl; + break; + case V4L2_CID_AUDIO_TREBLE: + if (!(va.flags & VIDEO_AUDIO_TREBLE)) + *c = no_ctl; + break; + } + } + return 0; + } + case VIDIOC_G_CTRL: + return get_control(btv,arg); + case VIDIOC_S_CTRL: + return set_control(btv,arg); + case VIDIOC_G_PARM: + { + struct v4l2_streamparm *parm = arg; + struct v4l2_standard s; + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + memset(parm,0,sizeof(*parm)); + v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, + bttv_tvnorms[btv->tvnorm].name); + parm->parm.capture.timeperframe = s.frameperiod; + return 0; + } - *p = v4l2_prio_max(&btv->prio); + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; - return 0; -} + *p = v4l2_prio_max(&btv->prio); + return 0; + } + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *prio = arg; -static int bttv_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; + return v4l2_prio_change(&btv->prio, &fh->prio, *prio); + } - return v4l2_prio_change(&btv->prio, &fh->prio, prio); -} + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *cap = arg; + enum v4l2_buf_type type; -static int bttv_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; + type = cap->type; - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - *cap = bttv_tvnorms[btv->tvnorm].cropcap; + *cap = bttv_tvnorms[btv->tvnorm].cropcap; + cap->type = type; - return 0; -} + return 0; + } + case VIDIOC_G_CROP: + { + struct v4l2_crop * crop = arg; -static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + /* No fh->do_crop = 1; because btv->crop[1] may be + inconsistent with fh->width or fh->height and apps + do not expect a change here. */ - /* No fh->do_crop = 1; because btv->crop[1] may be - inconsistent with fh->width or fh->height and apps - do not expect a change here. */ + crop->c = btv->crop[!!fh->do_crop].rect; - crop->c = btv->crop[!!fh->do_crop].rect; + return 0; + } + case VIDIOC_S_CROP: + { + struct v4l2_crop *crop = arg; + const struct v4l2_rect *b; + struct bttv_crop c; + __s32 b_left; + __s32 b_top; + __s32 b_right; + __s32 b_bottom; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - return 0; -} + retval = v4l2_prio_check(&btv->prio,&fh->prio); + if (0 != retval) + return retval; -static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - const struct v4l2_rect *b; - int retval; - struct bttv_crop c; - __s32 b_left; - __s32 b_top; - __s32 b_right; - __s32 b_bottom; + /* Make sure tvnorm, vbi_end and the current cropping + parameters remain consistent until we're done. Note + read() may change vbi_end in check_alloc_btres(). */ + mutex_lock(&btv->lock); - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + retval = -EBUSY; - retval = v4l2_prio_check(&btv->prio, &fh->prio); - if (0 != retval) - return retval; + if (locked_btres(fh->btv, VIDEO_RESOURCES)) + goto btv_unlock_and_return; - /* Make sure tvnorm, vbi_end and the current cropping - parameters remain consistent until we're done. Note - read() may change vbi_end in check_alloc_btres(). */ - mutex_lock(&btv->lock); + b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; - retval = -EBUSY; + b_left = b->left; + b_right = b_left + b->width; + b_bottom = b->top + b->height; - if (locked_btres(fh->btv, VIDEO_RESOURCES)) { - mutex_unlock(&btv->lock); - return retval; - } + b_top = max(b->top, btv->vbi_end); + if (b_top + 32 >= b_bottom) + goto btv_unlock_and_return; - b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; + /* Min. scaled size 48 x 32. */ + c.rect.left = clamp(crop->c.left, b_left, b_right - 48); + c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); - b_left = b->left; - b_right = b_left + b->width; - b_bottom = b->top + b->height; + c.rect.width = clamp(crop->c.width, + 48, b_right - c.rect.left); - b_top = max(b->top, btv->vbi_end); - if (b_top + 32 >= b_bottom) { - mutex_unlock(&btv->lock); - return retval; - } + c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); + /* Top and height must be a multiple of two. */ + c.rect.top = (c.rect.top + 1) & ~1; - /* Min. scaled size 48 x 32. */ - c.rect.left = clamp(crop->c.left, b_left, b_right - 48); - c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); + c.rect.height = clamp(crop->c.height, + 32, b_bottom - c.rect.top); + c.rect.height = (c.rect.height + 1) & ~1; - c.rect.width = clamp(crop->c.width, - 48, b_right - c.rect.left); + bttv_crop_calc_limits(&c); - c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); - /* Top and height must be a multiple of two. */ - c.rect.top = (c.rect.top + 1) & ~1; + btv->crop[1] = c; - c.rect.height = clamp(crop->c.height, - 32, b_bottom - c.rect.top); - c.rect.height = (c.rect.height + 1) & ~1; + mutex_unlock(&btv->lock); - bttv_crop_calc_limits(&c); + fh->do_crop = 1; - btv->crop[1] = c; + mutex_lock(&fh->cap.lock); - mutex_unlock(&btv->lock); + if (fh->width < c.min_scaled_width) { + fh->width = c.min_scaled_width; + btv->init.width = c.min_scaled_width; + } else if (fh->width > c.max_scaled_width) { + fh->width = c.max_scaled_width; + btv->init.width = c.max_scaled_width; + } - fh->do_crop = 1; + if (fh->height < c.min_scaled_height) { + fh->height = c.min_scaled_height; + btv->init.height = c.min_scaled_height; + } else if (fh->height > c.max_scaled_height) { + fh->height = c.max_scaled_height; + btv->init.height = c.max_scaled_height; + } - mutex_lock(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); - if (fh->width < c.min_scaled_width) { - fh->width = c.min_scaled_width; - btv->init.width = c.min_scaled_width; - } else if (fh->width > c.max_scaled_width) { - fh->width = c.max_scaled_width; - btv->init.width = c.max_scaled_width; + return 0; } - if (fh->height < c.min_scaled_height) { - fh->height = c.min_scaled_height; - btv->init.height = c.min_scaled_height; - } else if (fh->height > c.max_scaled_height) { - fh->height = c.max_scaled_height; - btv->init.height = c.max_scaled_height; + case VIDIOC_ENUMSTD: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_ENUMINPUT: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_LOG_STATUS: + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + return bttv_common_ioctls(btv,cmd,arg); + + default: + return -ENOIOCTLCMD; } + return 0; + fh_unlock_and_return: mutex_unlock(&fh->cap.lock); + return retval; - return 0; + btv_unlock_and_return: + mutex_unlock(&btv->lock); + return retval; } -static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +static int bttv_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - strcpy(a->name, "audio"); - return 0; -} + struct bttv_fh *fh = file->private_data; -static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - return 0; + switch (cmd) { + case BTTV_VBISIZE: + { + const struct bttv_tvnorm *tvnorm; + + tvnorm = fh->vbi_fmt.tvnorm; + + if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] || + fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] || + fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) { + /* BTTV_VBISIZE cannot express these parameters, + however open() resets the paramters to defaults + and apps shouldn't call BTTV_VBISIZE after + VIDIOC_S_FMT. */ + return -EINVAL; + } + + bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); + return (fh->vbi_fmt.fmt.count[0] * 2 + * fh->vbi_fmt.fmt.samples_per_line); + } + + default: + return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); + } } static ssize_t bttv_read(struct file *file, char __user *data, @@ -3205,8 +3719,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) + if (buf->vb.state == STATE_DONE || + buf->vb.state == STATE_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -3263,7 +3777,7 @@ static int bttv_open(struct inode *inode, struct file *file) V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer), fh); - set_tvnorm(btv,btv->tvnorm); + i2c_vidiocschan(btv); btv->users++; @@ -3343,7 +3857,7 @@ static const struct file_operations bttv_fops = .owner = THIS_MODULE, .open = bttv_open, .release = bttv_release, - .ioctl = video_ioctl2, + .ioctl = bttv_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, .read = bttv_read, @@ -3353,61 +3867,19 @@ static const struct file_operations bttv_fops = static struct video_device bttv_video_template = { + .name = "UNSET", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER| + VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .fops = &bttv_fops, + .minor = -1, +}; + +static struct video_device bttv_vbi_template = +{ + .name = "bt848/878 vbi", + .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, .fops = &bttv_fops, .minor = -1, - .vidioc_querycap = bttv_querycap, - .vidioc_enum_fmt_cap = bttv_enum_fmt_cap, - .vidioc_g_fmt_cap = bttv_g_fmt_cap, - .vidioc_try_fmt_cap = bttv_try_fmt_cap, - .vidioc_s_fmt_cap = bttv_s_fmt_cap, - .vidioc_enum_fmt_overlay = bttv_enum_fmt_overlay, - .vidioc_g_fmt_overlay = bttv_g_fmt_overlay, - .vidioc_try_fmt_overlay = bttv_try_fmt_overlay, - .vidioc_s_fmt_overlay = bttv_s_fmt_overlay, - .vidioc_enum_fmt_vbi = bttv_enum_fmt_vbi, - .vidioc_g_fmt_vbi = bttv_g_fmt_vbi, - .vidioc_try_fmt_vbi = bttv_try_fmt_vbi, - .vidioc_s_fmt_vbi = bttv_s_fmt_vbi, - .vidioc_g_audio = bttv_g_audio, - .vidioc_s_audio = bttv_s_audio, - .vidioc_cropcap = bttv_cropcap, - .vidioc_reqbufs = bttv_reqbufs, - .vidioc_querybuf = bttv_querybuf, - .vidioc_qbuf = bttv_qbuf, - .vidioc_dqbuf = bttv_dqbuf, - .vidioc_s_std = bttv_s_std, - .vidioc_enum_input = bttv_enum_input, - .vidioc_g_input = bttv_g_input, - .vidioc_s_input = bttv_s_input, - .vidioc_queryctrl = bttv_queryctrl, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, - .vidioc_streamon = bttv_streamon, - .vidioc_streamoff = bttv_streamoff, - .vidioc_g_tuner = bttv_g_tuner, - .vidioc_s_tuner = bttv_s_tuner, -#ifdef CONFIG_VIDEO_V4L1_COMPAT - .vidiocgmbuf = vidiocgmbuf, -#endif - .vidioc_g_crop = bttv_g_crop, - .vidioc_g_crop = bttv_g_crop, - .vidioc_s_crop = bttv_s_crop, - .vidioc_g_fbuf = bttv_g_fbuf, - .vidioc_s_fbuf = bttv_s_fbuf, - .vidioc_overlay = bttv_overlay, - .vidioc_g_priority = bttv_g_priority, - .vidioc_s_priority = bttv_s_priority, - .vidioc_g_parm = bttv_g_parm, - .vidioc_g_frequency = bttv_g_frequency, - .vidioc_s_frequency = bttv_s_frequency, - .vidioc_log_status = bttv_log_status, - .vidioc_querystd = bttv_querystd, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = bttv_g_register, - .vidioc_s_register = bttv_s_register, -#endif - .tvnorms = BTTV_NORMS, - .current_norm = V4L2_STD_PAL, }; /* ----------------------------------------------------------------------- */ @@ -3446,7 +3918,7 @@ static int radio_open(struct inode *inode, struct file *file) static int radio_release(struct inode *inode, struct file *file) { - struct bttv *btv = file->private_data; + struct bttv *btv = file->private_data; struct rds_command cmd; btv->radio_user--; @@ -3456,116 +3928,59 @@ static int radio_release(struct inode *inode, struct file *file) return 0; } -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - strcpy(cap->driver, "bttv"); - strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); - - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 0); - - mutex_unlock(&btv->lock); - - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - memset(a, 0, sizeof(*a)); - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - if (0 != t->index) - return -EINVAL; - - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); - return 0; -} - -static int radio_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) +static int radio_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { - return 0; -} + struct bttv *btv = file->private_data; -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - return 0; -} + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability *cap = arg; -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - return 0; -} + memset(cap,0,sizeof(*cap)); + strcpy(cap->name,btv->radio_dev->name); + cap->type = VID_TYPE_TUNER; + cap->channels = 1; + cap->audios = 1; + return 0; + } -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; + case VIDIOCGTUNER: + { + struct video_tuner *v = arg; - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; + if(v->tuner) + return -EINVAL; + memset(v,0,sizeof(*v)); + strcpy(v->name, "Radio"); + bttv_call_i2c_clients(btv,cmd,v); + return 0; + } + case VIDIOCSTUNER: + /* nothing to do */ + return 0; - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctl; + case BTTV_VERSION: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + case VIDIOC_LOG_STATUS: + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + return bttv_common_ioctls(btv,cmd,arg); + default: + return -ENOIOCTLCMD; + } return 0; } -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) +static int radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - *i = 0; - return 0; + return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); } static ssize_t radio_read(struct file *file, char __user *data, @@ -3601,29 +4016,17 @@ static const struct file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = video_ioctl2, + .ioctl = radio_ioctl, .llseek = no_llseek, .poll = radio_poll, }; static struct video_device radio_template = { + .name = "bt848/878 radio", + .type = VID_TYPE_TUNER, .fops = &radio_fops, .minor = -1, - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, - .vidioc_g_frequency = bttv_g_frequency, - .vidioc_s_frequency = bttv_s_frequency, }; /* ----------------------------------------------------------------------- */ @@ -3905,20 +4308,20 @@ static void bttv_irq_timeout(unsigned long data) bttv_set_dma(btv, 0); /* wake up */ - bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); - bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); + bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR); + bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR); /* cancel all outstanding capture / vbi requests */ while (!list_empty(&btv->capture)) { item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = VIDEOBUF_ERROR; + item->vb.state = STATE_ERROR; wake_up(&item->vb.done); } while (!list_empty(&btv->vcapture)) { item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = VIDEOBUF_ERROR; + item->vb.state = STATE_ERROR; wake_up(&item->vb.done); } @@ -3941,7 +4344,7 @@ bttv_irq_wakeup_top(struct bttv *btv) do_gettimeofday(&wakeup->vb.ts); wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = VIDEOBUF_DONE; + wakeup->vb.state = STATE_DONE; wake_up(&wakeup->vb.done); spin_unlock(&btv->s_lock); } @@ -3990,7 +4393,7 @@ bttv_irq_switch_video(struct bttv *btv) } /* wake up finished buffers */ - bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); + bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE); spin_unlock(&btv->s_lock); } @@ -4023,7 +4426,7 @@ bttv_irq_switch_vbi(struct bttv *btv) bttv_buffer_activate_vbi(btv, new); bttv_set_dma(btv, 0); - bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); + bttv_irq_wakeup_vbi(btv, old, STATE_DONE); spin_unlock(&btv->s_lock); } @@ -4145,9 +4548,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) /* initialitation */ static struct video_device *vdev_init(struct bttv *btv, - const struct video_device *template, - const char *type_name, - const int type) + struct video_device *template, + char *type) { struct video_device *vfd; @@ -4158,10 +4560,9 @@ static struct video_device *vdev_init(struct bttv *btv, vfd->minor = -1; vfd->dev = &btv->c.pci->dev; vfd->release = video_device_release; - vfd->type = type; snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", - type_name, bttv_tvcards[btv->c.type].name); + type, bttv_tvcards[btv->c.type].name); return vfd; } @@ -4193,11 +4594,6 @@ static void bttv_unregister_video(struct bttv *btv) /* register video4linux devices */ static int __devinit bttv_register_video(struct bttv *btv) { - int video_type = VID_TYPE_CAPTURE | - VID_TYPE_TUNER | - VID_TYPE_CLIPPING| - VID_TYPE_SCALES; - if (no_overlay <= 0) { bttv_video_template.type |= VID_TYPE_OVERLAY; } else { @@ -4205,9 +4601,7 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, - "video", video_type); - + btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); if (NULL == btv->video_dev) goto err; if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) @@ -4222,9 +4616,7 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_video_template, - "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT); - + btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi"); if (NULL == btv->vbi_dev) goto err; if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) @@ -4235,8 +4627,7 @@ static int __devinit bttv_register_video(struct bttv *btv) if (!btv->has_radio) return 0; /* radio */ - btv->radio_dev = vdev_init(btv, &radio_template, - "radio", VID_TYPE_TUNER); + btv->radio_dev = vdev_init(btv, &radio_template, "radio"); if (NULL == btv->radio_dev) goto err; if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) @@ -4377,7 +4768,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->init.btv = btv; btv->init.ov.w.width = 320; btv->init.ov.w.height = 240; - btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24); btv->init.width = 320; btv->init.height = 240; btv->input = 0; @@ -4622,17 +5013,14 @@ static int __init bttv_init_module(void) printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); return ret; } - ret = pci_register_driver(&bttv_pci_driver); - if (ret < 0) - bus_unregister(&bttv_sub_bus_type); - - return ret; + return pci_register_driver(&bttv_pci_driver); } static void __exit bttv_cleanup_module(void) { pci_unregister_driver(&bttv_pci_driver); bus_unregister(&bttv_sub_bus_type); + return; } module_init(bttv_init_module); diff --git a/trunk/drivers/media/video/bt8xx/bttv-input.c b/trunk/drivers/media/video/bt8xx/bttv-input.c index fc9ecb21eec6..e7c521b8444a 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-input.c +++ b/trunk/drivers/media/video/bt8xx/bttv-input.c @@ -69,11 +69,6 @@ static void ir_handle_key(struct bttv *btv) (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { ir_input_keydown(ir->dev,&ir->ir,data,data); } else { - /* HACK: Probably, ir->mask_keydown is missing - for this board */ - if (btv->c.type == BTTV_BOARD_WINFAST2000) - ir_input_keydown(ir->dev, &ir->ir, data, data); - ir_input_nokey(ir->dev,&ir->ir); } diff --git a/trunk/drivers/media/video/bt8xx/bttv-risc.c b/trunk/drivers/media/video/bt8xx/bttv-risc.c index e5979f77504c..58986f1a5f1a 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-risc.c +++ b/trunk/drivers/media/video/bt8xx/bttv-risc.c @@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + buf->vb.state = STATE_NEEDS_INIT; } int @@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv, if (vbi) { unsigned int crop, vdelay; - vbi->vb.state = VIDEOBUF_ACTIVE; + vbi->vb.state = STATE_ACTIVE; list_del(&vbi->vb.queue); /* VDELAY is start of video, end of VBI capturing. */ @@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv, /* video capture */ if (NULL != set->top && NULL != set->bottom) { if (set->top == set->bottom) { - set->top->vb.state = VIDEOBUF_ACTIVE; + set->top->vb.state = STATE_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); } else { - set->top->vb.state = VIDEOBUF_ACTIVE; - set->bottom->vb.state = VIDEOBUF_ACTIVE; + set->top->vb.state = STATE_ACTIVE; + set->bottom->vb.state = STATE_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); if (set->bottom->vb.queue.next) @@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->top) { - set->top->vb.state = VIDEOBUF_ACTIVE; + set->top->vb.state = STATE_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); bttv_apply_geo(btv, &set->top->geo,1); @@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->bottom) { - set->bottom->vb.state = VIDEOBUF_ACTIVE; + set->bottom->vb.state = STATE_ACTIVE; if (set->bottom->vb.queue.next) list_del(&set->bottom->vb.queue); bttv_apply_geo(btv, &set->bottom->geo,1); diff --git a/trunk/drivers/media/video/bt8xx/bttv-vbi.c b/trunk/drivers/media/video/bt8xx/bttv-vbi.c index 1f0cc79e2a33..346ce019bdcb 100644 --- a/trunk/drivers/media/video/bt8xx/bttv-vbi.c +++ b/trunk/drivers/media/video/bt8xx/bttv-vbi.c @@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, redo_dma_risc = 1; } - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; @@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, /* For bttv_buffer_activate_vbi(). */ buf->geo.vdelay = min_vdelay; - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; buf->vb.field = field; dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", vb, &buf->top, &buf->bottom, @@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); dprintk("queue %p\n",vb); - buf->vb.state = VIDEOBUF_QUEUED; + buf->vb.state = STATE_QUEUED; list_add_tail(&buf->vb.queue,&btv->vcapture); if (NULL == btv->cvbi) { fh->btv->loop_irq |= 4; @@ -236,8 +236,10 @@ struct videobuf_queue_ops bttv_vbi_qops = { /* ----------------------------------------------------------------------- */ -static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, - __s32 crop_start) +static int +try_fmt (struct v4l2_vbi_format * f, + const struct bttv_tvnorm * tvnorm, + __s32 crop_start) { __s32 min_start, max_start, max_end, f2_offset; unsigned int i; @@ -303,9 +305,10 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, return 0; } -int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int +bttv_vbi_try_fmt (struct bttv_fh * fh, + struct v4l2_vbi_format * f) { - struct bttv_fh *fh = f; struct bttv *btv = fh->btv; const struct bttv_tvnorm *tvnorm; __s32 crop_start; @@ -317,13 +320,13 @@ int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) mutex_unlock(&btv->lock); - return try_fmt(&frt->fmt.vbi, tvnorm, crop_start); + return try_fmt(f, tvnorm, crop_start); } - -int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +int +bttv_vbi_set_fmt (struct bttv_fh * fh, + struct v4l2_vbi_format * f) { - struct bttv_fh *fh = f; struct bttv *btv = fh->btv; const struct bttv_tvnorm *tvnorm; __s32 start1, end; @@ -337,12 +340,11 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) tvnorm = &bttv_tvnorms[btv->tvnorm]; - rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start); + rc = try_fmt(f, tvnorm, btv->crop_start); if (0 != rc) goto fail; - start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] + - tvnorm->vbistart[0]; + start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0]; /* First possible line of video capturing. Should be max(f->start[0] + f->count[0], start1 + f->count[1]) * 2 @@ -350,11 +352,11 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) pretend the VBI and video capture window may overlap, so end = start + 1, the lowest possible value, times two because vbi_fmt.end counts field lines times two. */ - end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; + end = max(f->start[0], start1) * 2 + 2; mutex_lock(&fh->vbi.lock); - fh->vbi_fmt.fmt = frt->fmt.vbi; + fh->vbi_fmt.fmt = *f; fh->vbi_fmt.tvnorm = tvnorm; fh->vbi_fmt.end = end; @@ -368,13 +370,13 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) return rc; } - -int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) +void +bttv_vbi_get_fmt (struct bttv_fh * fh, + struct v4l2_vbi_format * f) { - struct bttv_fh *fh = f; const struct bttv_tvnorm *tvnorm; - frt->fmt.vbi = fh->vbi_fmt.fmt; + *f = fh->vbi_fmt.fmt; tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; @@ -389,28 +391,28 @@ int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) max_end = (tvnorm->cropcap.bounds.top + tvnorm->cropcap.bounds.height) >> 1; - frt->fmt.vbi.sampling_rate = tvnorm->Fsc; + f->sampling_rate = tvnorm->Fsc; for (i = 0; i < 2; ++i) { __s32 new_start; - new_start = frt->fmt.vbi.start[i] + new_start = f->start[i] + tvnorm->vbistart[i] - fh->vbi_fmt.tvnorm->vbistart[i]; - frt->fmt.vbi.start[i] = min(new_start, max_end - 1); - frt->fmt.vbi.count[i] = - min((__s32) frt->fmt.vbi.count[i], - max_end - frt->fmt.vbi.start[i]); + f->start[i] = min(new_start, max_end - 1); + f->count[i] = min((__s32) f->count[i], + max_end - f->start[i]); max_end += tvnorm->vbistart[1] - tvnorm->vbistart[0]; } } - return 0; } -void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm) +void +bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f, + int norm) { const struct bttv_tvnorm *tvnorm; unsigned int real_samples_per_line; diff --git a/trunk/drivers/media/video/bt8xx/bttv.h b/trunk/drivers/media/video/bt8xx/bttv.h index bf4c339a520c..19e75d50a107 100644 --- a/trunk/drivers/media/video/bt8xx/bttv.h +++ b/trunk/drivers/media/video/bt8xx/bttv.h @@ -241,10 +241,7 @@ struct tvcard unsigned int radio_addr; unsigned int has_radio; - - void (*volume_gpio)(struct bttv *btv, __u16 volume); - void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); - + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; diff --git a/trunk/drivers/media/video/bt8xx/bttvp.h b/trunk/drivers/media/video/bt8xx/bttvp.h index 1305d315cfc5..d4ac4c4b49b4 100644 --- a/trunk/drivers/media/video/bt8xx/bttvp.h +++ b/trunk/drivers/media/video/bt8xx/bttvp.h @@ -84,11 +84,6 @@ #define clamp(x, low, high) min (max (low, x), high) -#define BTTV_NORMS (\ - V4L2_STD_PAL | V4L2_STD_PAL_N | \ - V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ - V4L2_STD_NTSC | V4L2_STD_PAL_M | \ - V4L2_STD_PAL_60) /* ---------------------------------------------------------- */ struct bttv_tvnorm { @@ -117,6 +112,7 @@ extern const struct bttv_tvnorm bttv_tvnorms[]; struct bttv_format { char *name; + int palette; /* video4linux 1 */ int fourcc; /* video4linux 2 */ int btformat; /* BT848_COLOR_FMT_* */ int btswap; /* BT848_COLOR_CTL_* */ @@ -257,9 +253,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, /* ---------------------------------------------------------- */ /* bttv-vbi.c */ -int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); -int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); -int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); +void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); +int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); extern struct videobuf_queue_ops bttv_vbi_qops; @@ -341,9 +337,7 @@ struct bttv { /* old gpio interface */ wait_queue_head_t gpioq; int shutdown; - - void (*volume_gpio)(struct bttv *btv, __u16 volume); - void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); /* new gpio interface */ spinlock_t gpio_lock; @@ -464,6 +458,10 @@ struct bttv { extern unsigned int bttv_num; extern struct bttv bttvs[BTTV_MAX]; +/* private ioctls */ +#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) + #endif #define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) diff --git a/trunk/drivers/media/video/bw-qcam.c b/trunk/drivers/media/video/bw-qcam.c index 032265383df2..58423525591f 100644 --- a/trunk/drivers/media/video/bw-qcam.c +++ b/trunk/drivers/media/video/bw-qcam.c @@ -82,16 +82,11 @@ OTHER DEALINGS IN THE SOFTWARE. static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ static unsigned int yieldlines=4; /* Yield after this many during capture */ static int video_nr = -1; -static unsigned int force_init; /* Whether to probe aggressively */ module_param(maxpoll, int, 0); module_param(yieldlines, int, 0); module_param(video_nr, int, 0); -/* Set force_init=1 to avoid detection by polling status register and - * immediately attempt to initialize qcam */ -module_param(force_init, int, 0); - static inline int read_lpstatus(struct qcam_device *q) { return parport_read_status(q->pport); @@ -336,9 +331,6 @@ static int qc_detect(struct qcam_device *q) int count = 0; int i; - if (force_init) - return 1; - lastreg = reg = read_lpstatus(q) & 0xf0; for (i = 0; i < 500; i++) @@ -362,12 +354,12 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ +/* if (count > 30 && count < 200) */ if (count > 20 && count < 400) { return 1; /* found */ } else { printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); - printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); return 0; /* not found */ } } diff --git a/trunk/drivers/media/video/cs5345.c b/trunk/drivers/media/video/cs5345.c deleted file mode 100644 index fae469ce16f5..000000000000 --- a/trunk/drivers/media/video/cs5345.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC - * Copyright (C) 2007 Hans Verkuil - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static int debug; - -module_param(debug, bool, 0644); - -MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); - - -/* ----------------------------------------------------------------------- */ - -static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static inline int cs5345_read(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg) -{ - struct v4l2_routing *route = arg; - struct v4l2_control *ctrl = arg; - - switch (cmd) { - case VIDIOC_INT_G_AUDIO_ROUTING: - route->input = cs5345_read(client, 0x09) & 7; - route->input |= cs5345_read(client, 0x05) & 0x70; - route->output = 0; - break; - - case VIDIOC_INT_S_AUDIO_ROUTING: - if ((route->input & 0xf) > 6) { - v4l_err(client, "Invalid input %d.\n", route->input); - return -EINVAL; - } - cs5345_write(client, 0x09, route->input & 0xf); - cs5345_write(client, 0x05, route->input & 0xf0); - break; - - case VIDIOC_G_CTRL: - if (ctrl->id == V4L2_CID_AUDIO_MUTE) { - ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0; - break; - } - if (ctrl->id != V4L2_CID_AUDIO_VOLUME) - return -EINVAL; - ctrl->value = cs5345_read(client, 0x07) & 0x3f; - if (ctrl->value >= 32) - ctrl->value = ctrl->value - 64; - break; - - case VIDIOC_S_CTRL: - break; - if (ctrl->id == V4L2_CID_AUDIO_MUTE) { - cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0); - break; - } - if (ctrl->id != V4L2_CID_AUDIO_VOLUME) - return -EINVAL; - if (ctrl->value > 24 || ctrl->value < -24) - return -EINVAL; - cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f); - cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f); - break; - -#ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_register *reg = arg; - - if (!v4l2_chip_match_i2c_client(client, - reg->match_type, reg->match_chip)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) - reg->val = cs5345_read(client, reg->reg & 0x1f); - else - cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f); - break; - } -#endif - - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, - arg, V4L2_IDENT_CS5345, 0); - - case VIDIOC_LOG_STATUS: - { - u8 v = cs5345_read(client, 0x09) & 7; - u8 m = cs5345_read(client, 0x04); - int vol = cs5345_read(client, 0x08) & 0x3f; - - v4l_info(client, "Input: %d%s\n", v, - (m & 0x80) ? " (muted)" : ""); - if (vol >= 32) - vol = vol - 64; - v4l_info(client, "Volume: %d dB\n", vol); - break; - } - - default: - return -EINVAL; - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int cs5345_probe(struct i2c_client *client) -{ - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - cs5345_write(client, 0x02, 0x00); - cs5345_write(client, 0x04, 0x01); - cs5345_write(client, 0x09, 0x01); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "cs5345", - .driverid = I2C_DRIVERID_CS5345, - .command = cs5345_command, - .probe = cs5345_probe, -}; - diff --git a/trunk/drivers/media/video/cs53l32a.c b/trunk/drivers/media/video/cs53l32a.c index f41bfde045fe..a73e285af730 100644 --- a/trunk/drivers/media/video/cs53l32a.c +++ b/trunk/drivers/media/video/cs53l32a.c @@ -29,13 +29,12 @@ #include #include #include -#include MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); MODULE_LICENSE("GPL"); -static int debug; +static int debug = 0; module_param(debug, bool, 0644); @@ -58,7 +57,8 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) +static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, + void *arg) { struct v4l2_routing *route = arg; struct v4l2_control *ctrl = arg; @@ -105,8 +105,7 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, - arg, V4L2_IDENT_CS53l32A, 0); + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0); case VIDIOC_LOG_STATUS: { @@ -135,18 +134,27 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int cs53l32a_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; int i; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); for (i = 1; i <= 7; i++) { u8 v = cs53l32a_read(client, i); @@ -171,13 +179,55 @@ static int cs53l32a_probe(struct i2c_client *client) v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v); } + + i2c_attach_client(client); + return 0; } -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "cs53l32a", - .driverid = I2C_DRIVERID_CS53L32A, +static int cs53l32a_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, cs53l32a_attach); + return 0; +} + +static int cs53l32a_detach(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(client); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "cs53l32a", + }, + .id = I2C_DRIVERID_CS53L32A, + .attach_adapter = cs53l32a_probe, + .detach_client = cs53l32a_detach, .command = cs53l32a_command, - .probe = cs53l32a_probe, }; + +static int __init cs53l32a_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit cs53l32a_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(cs53l32a_init_module); +module_exit(cs53l32a_cleanup_module); diff --git a/trunk/drivers/media/video/cx2341x.c b/trunk/drivers/media/video/cx2341x.c index c592899a2317..62304255dcae 100644 --- a/trunk/drivers/media/video/cx2341x.c +++ b/trunk/drivers/media/video/cx2341x.c @@ -34,7 +34,7 @@ MODULE_DESCRIPTION("cx23415/6 driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); @@ -75,7 +75,6 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, 0 }; -EXPORT_SYMBOL(cx2341x_mpeg_ctrls); /* Map the control ID to the correct field in the cx2341x_mpeg_params @@ -282,14 +281,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return -EBUSY; params->stream_type = ctrl->value; params->video_encoding = - (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || - params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : - V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || + params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? + V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { /* MPEG-1 implies CBR */ - params->video_bitrate_mode = - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + } break; case V4L2_CID_MPEG_STREAM_VBI_FMT: params->stream_vbi_fmt = ctrl->value; @@ -336,8 +334,7 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return 0; } -static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, - s32 min, s32 max, s32 step, s32 def) +static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def) { const char *name; @@ -420,8 +417,7 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, return 0; } -int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, - struct v4l2_queryctrl *qctrl) +int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl) { int err; @@ -444,8 +440,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && - params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; @@ -460,16 +455,13 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && - params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && - params->video_bitrate_mode == - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; @@ -484,90 +476,80 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, /* CX23415/6 specific */ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_spatial_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, - 1, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF); - if (params->video_spatial_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF); + if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - 1, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF); - if (params->video_spatial_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF); + if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_temporal_filter_mode == - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: @@ -578,7 +560,6 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, } } -EXPORT_SYMBOL(cx2341x_ctrl_query); const char **cx2341x_ctrl_get_menu(u32 id) { @@ -648,7 +629,6 @@ const char **cx2341x_ctrl_get_menu(u32 id) return v4l2_ctrl_get_menu(id); } } -EXPORT_SYMBOL(cx2341x_ctrl_get_menu); static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) { @@ -657,8 +637,9 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) ((1 + params->audio_l2_bitrate) << 4) | (params->audio_mode << 8) | (params->audio_mode_extension << 10) | - (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) - ? 3 : params->audio_emphasis) << 12) | + (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ? + 3 : + params->audio_emphasis) << 12) | (params->audio_crc << 14); } @@ -698,19 +679,19 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, if (err) break; } - if (err == 0 && - params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && - params->video_bitrate_peak < params->video_bitrate) { + if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + params->video_bitrate_peak < params->video_bitrate) { err = -ERANGE; ctrls->error_idx = ctrls->count; } - if (err) + if (err) { ctrls->error_idx = i; - else + } + else { cx2341x_calc_audio_properties(params); + } return err; } -EXPORT_SYMBOL(cx2341x_ext_ctrls); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) { @@ -751,18 +732,13 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) .video_mute_yuv = 0x008080, /* YCbCr value for black */ /* encoding filters */ - .video_spatial_filter_mode = - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, .video_spatial_filter = 0, - .video_luma_spatial_filter_type = - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_chroma_spatial_filter_type = - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_temporal_filter_mode = - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, .video_temporal_filter = 8, - .video_median_filter_type = - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, .video_luma_median_filter_top = 255, .video_luma_median_filter_bottom = 0, .video_chroma_median_filter_top = 255, @@ -772,10 +748,8 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) *p = default_params; cx2341x_calc_audio_properties(p); } -EXPORT_SYMBOL(cx2341x_fill_defaults); -static int cx2341x_api(void *priv, cx2341x_mbox_func func, - u32 cmd, int args, ...) +static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...) { u32 data[CX2341X_MBOX_MAX_DATA]; va_list vargs; @@ -783,17 +757,15 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, va_start(vargs, args); - for (i = 0; i < args; i++) + for (i = 0; i < args; i++) { data[i] = va_arg(vargs, int); + } va_end(vargs); return func(priv, cmd, args, 0, data); } -#define NEQ(field) (old->field != new->field) - int cx2341x_update(void *priv, cx2341x_mbox_func func, - const struct cx2341x_mpeg_params *old, - const struct cx2341x_mpeg_params *new) + const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new) { static int mpeg_stream_type[] = { 0, /* MPEG-2 PS */ @@ -805,18 +777,17 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, }; int err = 0; - int force = (old == NULL); u16 temporal = new->video_temporal_filter; cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); - if (force || NEQ(is_50hz)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, - new->is_50hz); + if (old == NULL || old->is_50hz != new->is_50hz) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz); if (err) return err; } - if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { + if (old == NULL || old->width != new->width || old->height != new->height || + old->video_encoding != new->video_encoding) { u16 w = new->width; u16 h = new->height; @@ -824,74 +795,69 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, w /= 2; h /= 2; } - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, - h, w); + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); if (err) return err; } if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) { - /* Adjust temporal filter if necessary. The problem with the - temporal filter is that it works well with full resolution - capturing, but not when the capture window is scaled (the - filter introduces a ghosting effect). So if the capture - window is scaled, then force the filter to 0. + /* Adjust temporal filter if necessary. The problem with the temporal + filter is that it works well with full resolution capturing, but + not when the capture window is scaled (the filter introduces + a ghosting effect). So if the capture window is scaled, then + force the filter to 0. For full resolution the filter really improves the video - quality, especially if the original video quality is - suboptimal. */ + quality, especially if the original video quality is suboptimal. */ temporal = 0; } - if (force || NEQ(stream_type)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, - mpeg_stream_type[new->stream_type]); + if (old == NULL || old->stream_type != new->stream_type) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]); if (err) return err; } - if (force || NEQ(video_aspect)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, - 1 + new->video_aspect); + if (old == NULL || old->video_aspect != new->video_aspect) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect); if (err) return err; } - if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { + if (old == NULL || old->video_b_frames != new->video_b_frames || + old->video_gop_size != new->video_gop_size) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, new->video_gop_size, new->video_b_frames + 1); if (err) return err; } - if (force || NEQ(video_gop_closure)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, - new->video_gop_closure); + if (old == NULL || old->video_gop_closure != new->video_gop_closure) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure); if (err) return err; } - if (force || NEQ(audio_properties)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, - 1, new->audio_properties); + if (old == NULL || old->audio_properties != new->audio_properties) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); if (err) return err; } - if (force || NEQ(audio_mute)) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, - new->audio_mute); + if (old == NULL || old->audio_mute != new->audio_mute) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); if (err) return err; } - if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || - NEQ(video_bitrate_peak)) { + if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || + old->video_bitrate != new->video_bitrate || + old->video_bitrate_peak != new->video_bitrate_peak) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, new->video_bitrate_mode, new->video_bitrate, new->video_bitrate_peak / 400, 0, 0); if (err) return err; } - if (force || NEQ(video_spatial_filter_mode) || - NEQ(video_temporal_filter_mode) || - NEQ(video_median_filter_type)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, - 2, new->video_spatial_filter_mode | - (new->video_temporal_filter_mode << 1), + if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode || + old->video_temporal_filter_mode != new->video_temporal_filter_mode || + old->video_median_filter_type != new->video_median_filter_type) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, + new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1), new->video_median_filter_type); if (err) return err; } - if (force || NEQ(video_luma_median_filter_bottom) || - NEQ(video_luma_median_filter_top) || - NEQ(video_chroma_median_filter_bottom) || - NEQ(video_chroma_median_filter_top)) { + if (old == NULL || + old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom || + old->video_luma_median_filter_top != new->video_luma_median_filter_top || + old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom || + old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, new->video_luma_median_filter_bottom, new->video_luma_median_filter_top, @@ -899,39 +865,36 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, new->video_chroma_median_filter_top); if (err) return err; } - if (force || NEQ(video_luma_spatial_filter_type) || - NEQ(video_chroma_spatial_filter_type)) { - err = cx2341x_api(priv, func, - CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, - 2, new->video_luma_spatial_filter_type, - new->video_chroma_spatial_filter_type); + if (old == NULL || + old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type || + old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, + new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type); if (err) return err; } - if (force || NEQ(video_spatial_filter) || - old->video_temporal_filter != temporal) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, - 2, new->video_spatial_filter, temporal); + if (old == NULL || + old->video_spatial_filter != new->video_spatial_filter || + old->video_temporal_filter != temporal) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, + new->video_spatial_filter, temporal); if (err) return err; } - if (force || NEQ(video_temporal_decimation)) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, - 1, new->video_temporal_decimation); + if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1, + new->video_temporal_decimation); if (err) return err; } - if (force || NEQ(video_mute) || - (new->video_mute && NEQ(video_mute_yuv))) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, - new->video_mute | (new->video_mute_yuv << 8)); + if (old == NULL || old->video_mute != new->video_mute || + (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8)); if (err) return err; } - if (force || NEQ(stream_insert_nav_packets)) { - err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, - 7, new->stream_insert_nav_packets); + if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) { + err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets); if (err) return err; } return 0; } -EXPORT_SYMBOL(cx2341x_update); static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id) { @@ -980,17 +943,18 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), p->video_bitrate); - if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { printk(", Peak %d", p->video_bitrate_peak); + } printk("\n"); - printk(KERN_INFO - "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", + printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", prefix, p->video_gop_size, p->video_b_frames, p->video_gop_closure ? "" : "No "); - if (p->video_temporal_decimation) + if (p->video_temporal_decimation) { printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", prefix, p->video_temporal_decimation); + } /* Audio */ printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", @@ -1000,9 +964,10 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), p->audio_mute ? " (muted)" : ""); - if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) - printk(", %s", cx2341x_menu_item(p, - V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); + if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { + printk(", %s", + cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); + } printk(", %s, %s\n", cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); @@ -1010,33 +975,33 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) /* Encoding filters */ printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", prefix, - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), + cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), p->video_spatial_filter); - - if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) + if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) { temporal = 0; - + } printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", prefix, - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), + cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), temporal); - printk(KERN_INFO - "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", + printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", prefix, - cx2341x_menu_item(p, - V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), + cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), p->video_luma_median_filter_bottom, p->video_luma_median_filter_top, p->video_chroma_median_filter_bottom, p->video_chroma_median_filter_top); } + +EXPORT_SYMBOL(cx2341x_fill_defaults); +EXPORT_SYMBOL(cx2341x_ctrl_query); +EXPORT_SYMBOL(cx2341x_ctrl_get_menu); +EXPORT_SYMBOL(cx2341x_ext_ctrls); +EXPORT_SYMBOL(cx2341x_update); EXPORT_SYMBOL(cx2341x_log_status); +EXPORT_SYMBOL(cx2341x_mpeg_ctrls); /* * Local variables: diff --git a/trunk/drivers/media/video/cx23885/Kconfig b/trunk/drivers/media/video/cx23885/Kconfig index 1fd326fe4113..081ee6e1536f 100644 --- a/trunk/drivers/media/video/cx23885/Kconfig +++ b/trunk/drivers/media/video/cx23885/Kconfig @@ -12,10 +12,6 @@ config VIDEO_CX23885 select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE - select TUNER_XC2028 if !DVB_FE_CUSTOMIZE - select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE - select DVB_TDA18271 if !DVB_FE_CUSTOMIZE - select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. diff --git a/trunk/drivers/media/video/cx23885/Makefile b/trunk/drivers/media/video/cx23885/Makefile index 32c90be50602..665067022d2a 100644 --- a/trunk/drivers/media/video/cx23885/Makefile +++ b/trunk/drivers/media/video/cx23885/Makefile @@ -1,4 +1,4 @@ -cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o +cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o obj-$(CONFIG_VIDEO_CX23885) += cx23885.o diff --git a/trunk/drivers/media/video/cx23885/cx23885-cards.c b/trunk/drivers/media/video/cx23885/cx23885-cards.c index 2d414dad5c31..b9012acabb2f 100644 --- a/trunk/drivers/media/video/cx23885/cx23885-cards.c +++ b/trunk/drivers/media/video/cx23885/cx23885-cards.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "cx23885.h" @@ -33,8 +32,6 @@ struct cx23885_board cx23885_boards[] = { [CX23885_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", - /* Ensure safe default for unknown boards */ - .clk_freq = 0, .input = {{ .type = CX23885_VMUX_COMPOSITE1, .vmux = 0, @@ -72,29 +69,23 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800] = { .name = "Hauppauge WinTV-HVR1800", - .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, - .tuner_type = TUNER_PHILIPS_TDA8290, - .tuner_addr = 0x42, /* 0x84 >> 1 */ .input = {{ .type = CX23885_VMUX_TELEVISION, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN5_CH2 | - CX25840_VIN2_CH1, - .gpio0 = 0, + .vmux = 0, + .gpio0 = 0xff00, + },{ + .type = CX23885_VMUX_DEBUG, + .vmux = 0, + .gpio0 = 0xff01, },{ .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | - CX25840_VIN6_CH1, - .gpio0 = 0, + .vmux = 1, + .gpio0 = 0xff02, },{ .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | - CX25840_VIN8_CH1 | - CX25840_SVIDEO_ON, - .gpio0 = 0, + .vmux = 2, + .gpio0 = 0xff02, }}, }, [CX23885_BOARD_HAUPPAUGE_HVR1250] = { @@ -122,14 +113,6 @@ struct cx23885_board cx23885_boards[] = { .name = "DViCO FusionHDTV5 Express", .portb = CX23885_MPEG_DVB, }, - [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = { - .name = "Hauppauge WinTV-HVR1500Q", - .portc = CX23885_MPEG_DVB, - }, - [CX23885_BOARD_HAUPPAUGE_HVR1500] = { - .name = "Hauppauge WinTV-HVR1500", - .portc = CX23885_MPEG_DVB, - }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -153,10 +136,6 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x0070, .subdevice = 0x7801, .card = CX23885_BOARD_HAUPPAUGE_HVR1800, - },{ - .subvendor = 0x0070, - .subdevice = 0x7809, - .card = CX23885_BOARD_HAUPPAUGE_HVR1800, },{ .subvendor = 0x0070, .subdevice = 0x7911, @@ -165,22 +144,6 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xd500, .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, - },{ - .subvendor = 0x0070, - .subdevice = 0x7790, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, - },{ - .subvendor = 0x0070, - .subdevice = 0x7797, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, - },{ - .subvendor = 0x0070, - .subdevice = 0x7710, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500, - },{ - .subvendor = 0x0070, - .subdevice = 0x7717, - .card = CX23885_BOARD_HAUPPAUGE_HVR1500, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -221,19 +184,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) switch (tv.model) { case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ - case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */ - case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ - case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */ - case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */ - case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ - case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ - case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ - case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ - case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ - case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */ - case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */ - case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */ - case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */ + case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ + case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ break; default: printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); @@ -244,34 +197,6 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } -/* Tuner callback function for cx23885 boards. Currently only needed - * for HVR1500Q, which has an xc5000 tuner. - */ -int cx23885_tuner_callback(void *priv, int command, int arg) -{ - struct cx23885_i2c *bus = priv; - struct cx23885_dev *dev = bus->dev; - - switch(dev->board) { - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - if(command == 0) { /* Tuner Reset Command from xc5000 */ - /* Drive the tuner into reset and out */ - cx_clear(GP0_IO, 0x00000004); - mdelay(200); - cx_set(GP0_IO, 0x00000004); - return 0; - } - else { - printk(KERN_ERR - "%s(): Unknow command.\n", __FUNCTION__); - return -EINVAL; - } - break; - } - - return 0; /* Should never be here */ -} - void cx23885_gpio_setup(struct cx23885_dev *dev) { switch(dev->board) { @@ -279,23 +204,6 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-0 cx24227 demodulator reset */ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ break; - case CX23885_BOARD_HAUPPAUGE_HVR1500: - /* GPIO-0 cx24227 demodulator */ - /* GPIO-2 xc3028 tuner */ - - /* Put the parts into reset */ - cx_set(GP0_IO, 0x00050000); - cx_clear(GP0_IO, 0x00000005); - msleep(5); - - /* Bring the parts out of reset */ - cx_set(GP0_IO, 0x00050005); - break; - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - /* GPIO-0 cx24227 demodulator reset */ - /* GPIO-2 xc5000 tuner reset */ - cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */ - break; case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ /* GPIO-1 656_D0 */ @@ -304,14 +212,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-11-14 cx23417 addr0-3 */ /* GPIO-15-18 cx23417 READY, CS, RD, WR */ /* GPIO-19 IR_RX */ - - /* Force the TDA8295A into reset and back */ - cx_set(GP0_IO, 0x00040004); - mdelay(20); - cx_clear(GP0_IO, 0x00000004); - mdelay(20); - cx_set(GP0_IO, 0x00040004); - mdelay(20); + // FIXME: Analog requires the tuner is brought out of reset break; } } @@ -320,8 +221,6 @@ int cx23885_ir_init(struct cx23885_dev *dev) { switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1500: - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: /* FIXME: Implement me */ break; @@ -345,8 +244,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1500: - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: if (dev->i2c_bus[0].i2c_rc == 0) @@ -361,8 +258,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1500: - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: default: @@ -375,6 +270,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) /* ------------------------------------------------------------------ */ +EXPORT_SYMBOL(cx23885_boards); + /* * Local variables: * c-basic-offset: 8 diff --git a/trunk/drivers/media/video/cx23885/cx23885-core.c b/trunk/drivers/media/video/cx23885/cx23885-core.c index 8e40c7bcc06d..3cdd136477e5 100644 --- a/trunk/drivers/media/video/cx23885/cx23885-core.c +++ b/trunk/drivers/media/video/cx23885/cx23885-core.c @@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth "); MODULE_LICENSE("GPL"); -static unsigned int debug; +static unsigned int debug = 0; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages"); @@ -44,15 +44,13 @@ static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card,"card type"); -#define dprintk(level, fmt, arg...)\ - do { if (debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) static unsigned int cx23885_devcount; static DEFINE_MUTEX(devlist); -LIST_HEAD(cx23885_devlist); +static LIST_HEAD(cx23885_devlist); #define NO_SYNC_LINE (-1U) @@ -75,14 +73,14 @@ LIST_HEAD(cx23885_devlist); * 0x00010ea0 0x00010xxx Free */ -static struct sram_channel cx23885_sram_channels[] = { +struct sram_channel cx23885_sram_channels[] = { [SRAM_CH01] = { - .name = "VID A", + .name = "test ch1", .cmds_start = 0x10000, - .ctrl_start = 0x105b0, - .cdt = 0x107b0, - .fifo_start = 0x40, - .fifo_size = 0x2800, + .ctrl_start = 0x10500, + .cdt = 0x10900, + .fifo_start = 0x3000, + .fifo_size = 0x1000, .ptr1_reg = DMA1_PTR1, .ptr2_reg = DMA1_PTR2, .cnt1_reg = DMA1_CNT1, @@ -104,8 +102,8 @@ static struct sram_channel cx23885_sram_channels[] = { [SRAM_CH03] = { .name = "TS1 B", .cmds_start = 0x100A0, - .ctrl_start = 0x10630, - .cdt = 0x10870, + .ctrl_start = 0x10780, + .cdt = 0x10400, .fifo_start = 0x5000, .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, @@ -141,7 +139,7 @@ static struct sram_channel cx23885_sram_channels[] = { .name = "TS2 C", .cmds_start = 0x10140, .ctrl_start = 0x10680, - .cdt = 0x108d0, + .cdt = 0x10480, .fifo_start = 0x6000, .fifo_size = 0x1000, .ptr1_reg = DMA5_PTR1, @@ -207,14 +205,14 @@ static struct sram_channel cx23885_sram_channels[] = { * 0x00010ea0 0x00010xxx Free */ -static struct sram_channel cx23887_sram_channels[] = { +struct sram_channel cx23887_sram_channels[] = { [SRAM_CH01] = { - .name = "VID A", - .cmds_start = 0x10000, - .ctrl_start = 0x105b0, - .cdt = 0x107b0, - .fifo_start = 0x40, - .fifo_size = 0x2800, + .name = "test ch1", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, .ptr1_reg = DMA1_PTR1, .ptr2_reg = DMA1_PTR2, .cnt1_reg = DMA1_CNT1, @@ -233,12 +231,12 @@ static struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA2_CNT2, }, [SRAM_CH03] = { - .name = "TS1 B", - .cmds_start = 0x100A0, - .ctrl_start = 0x10780, - .cdt = 0x10400, - .fifo_start = 0x5000, - .fifo_size = 0x1000, + .name = "ch3", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, .ptr1_reg = DMA3_PTR1, .ptr2_reg = DMA3_PTR2, .cnt1_reg = DMA3_CNT1, @@ -359,7 +357,7 @@ static int cx23885_risc_decode(u32 risc) } void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; @@ -380,7 +378,7 @@ void cx23885_wakeup(struct cx23885_tsport *port, do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); - buf->vb.state = VIDEOBUF_DONE; + buf->vb.state = STATE_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } @@ -393,10 +391,12 @@ void cx23885_wakeup(struct cx23885_tsport *port, printk("%s: %d buffers handled (should be 1)\n", __FUNCTION__, bc); } +void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch); int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) + struct sram_channel *ch, + unsigned int bpl, u32 risc) { unsigned int i, lines; u32 cdt; @@ -468,7 +468,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) + struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -529,8 +529,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, dev->name, cx_read(ch->cnt2_reg)); } -static void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) +void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) { struct cx23885_dev *dev = port->dev; unsigned int i, j, n; @@ -548,7 +548,7 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port, } } -static void cx23885_shutdown(struct cx23885_dev *dev) +void cx23885_shutdown(struct cx23885_dev *dev) { /* disable RISC controller */ cx_write(DEV_CNTRL2, 0); @@ -578,7 +578,7 @@ static void cx23885_shutdown(struct cx23885_dev *dev) } -static void cx23885_reset(struct cx23885_dev *dev) +void cx23885_reset(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); @@ -594,18 +594,15 @@ static void cx23885_reset(struct cx23885_dev *dev) mdelay(100); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], - 720*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03], - 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06], - 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); cx23885_gpio_setup(dev); } @@ -640,7 +637,7 @@ static int get_resources(struct cx23885_dev *dev) static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); + u32 reg, u32 mask, u32 value); static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { @@ -707,44 +704,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p return 0; } -static void cx23885_dev_checkrevision(struct cx23885_dev *dev) -{ - switch (cx_read(RDR_CFG2) & 0xff) { - case 0x00: - /* cx23885 */ - dev->hwrevision = 0xa0; - break; - case 0x01: - /* CX23885-12Z */ - dev->hwrevision = 0xa1; - break; - case 0x02: - /* CX23885-13Z */ - dev->hwrevision = 0xb0; - break; - case 0x03: - /* CX23888-22Z */ - dev->hwrevision = 0xc0; - break; - case 0x0e: - /* CX23887-15Z */ - dev->hwrevision = 0xc0; - case 0x0f: - /* CX23887-14Z */ - dev->hwrevision = 0xb1; - break; - default: - printk(KERN_ERR "%s() New hardware revision found 0x%x\n", - __FUNCTION__, dev->hwrevision); - } - if (dev->hwrevision) - printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", - __FUNCTION__, dev->hwrevision); - else - printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n", - __FUNCTION__, dev->hwrevision); -} - static int cx23885_dev_setup(struct cx23885_dev *dev) { int i; @@ -764,14 +723,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; dev->sram_channels = cx23887_sram_channels; - /* Apply a sensible clock frequency for the PCIe bridge */ - dev->clk_freq = 25000000; } else if(dev->pci->device == 0x8852) { dev->bridge = CX23885_BRIDGE_885; dev->sram_channels = cx23885_sram_channels; - /* Apply a sensible clock frequency for the PCIe bridge */ - dev->clk_freq = 28000000; } else BUG(); @@ -791,10 +746,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } - /* If the user specific a clk freq override, apply it */ - if (cx23885_boards[dev->board].clk_freq > 0) - dev->clk_freq = cx23885_boards[dev->board].clk_freq; - dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); dev->pci_irqmask = 0x001f00; @@ -859,17 +810,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_pci_quirks(dev); - /* Assume some sensible defaults */ - dev->tuner_type = cx23885_boards[dev->board].tuner_type; - dev->tuner_addr = cx23885_boards[dev->board].tuner_addr; - dev->radio_type = cx23885_boards[dev->board].radio_type; - dev->radio_addr = cx23885_boards[dev->board].radio_addr; - - dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n", - __FUNCTION__, dev->tuner_type, dev->tuner_addr); - dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n", - __FUNCTION__, dev->radio_type, dev->radio_addr); - /* init hardware */ cx23885_reset(dev); @@ -880,33 +820,24 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_setup(dev); cx23885_ir_init(dev); - if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { - if (cx23885_video_register(dev) < 0) { - printk(KERN_ERR "%s() Failed to register analog " - "video adapters on VID_A\n", __FUNCTION__); - } - } - - if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { if (cx23885_dvb_register(&dev->ts1) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", __FUNCTION__); } } - if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { if (cx23885_dvb_register(&dev->ts2) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n", __FUNCTION__); } } - cx23885_dev_checkrevision(dev); - return 0; } -static void cx23885_dev_unregister(struct cx23885_dev *dev) +void cx23885_dev_unregister(struct cx23885_dev *dev) { release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); @@ -914,9 +845,6 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) if (!atomic_dec_and_test(&dev->refcount)) return; - if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) - cx23885_video_unregister(dev); - if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) cx23885_dvb_unregister(&dev->ts1); @@ -1024,11 +952,9 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, return 0; } -static int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int bpl, - unsigned int lines) +int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, unsigned int bpl, + unsigned int lines) { u32 instructions; u32 *rp; @@ -1056,7 +982,7 @@ static int cx23885_risc_databuffer(struct pci_dev *pci, } int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) + u32 reg, u32 mask, u32 value) { u32 *rp; int rc; @@ -1085,58 +1011,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - - dprintk(1, "%s() Register Dump\n", __FUNCTION__); - dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __FUNCTION__, - cx_read(DEV_CNTRL2)); - dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __FUNCTION__, - cx_read(PCI_INT_MSK)); - dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __FUNCTION__, - cx_read(AUDIO_INT_INT_MSK)); - dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __FUNCTION__, - cx_read(AUD_INT_DMA_CTL)); - dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __FUNCTION__, - cx_read(AUDIO_EXT_INT_MSK)); - dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __FUNCTION__, - cx_read(AUD_EXT_DMA_CTL)); - dprintk(1, "%s() PAD_CTRL 0x%08X\n", __FUNCTION__, - cx_read(PAD_CTRL)); - dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __FUNCTION__, - cx_read(ALT_PIN_OUT_SEL)); - dprintk(1, "%s() GPIO2 0x%08X\n", __FUNCTION__, - cx_read(GPIO2)); - dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __FUNCTION__, - port->reg_gpcnt, cx_read(port->reg_gpcnt)); - dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); - dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); - dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_src_sel, cx_read(port->reg_src_sel)); - dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_lngth, cx_read(port->reg_lngth)); - dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); - dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); - dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); - dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_sop_status, cx_read(port->reg_sop_status)); - dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); - dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_vld_misc, cx_read(port->reg_vld_misc)); - dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); - dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __FUNCTION__, - port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); + buf->vb.state = STATE_NEEDS_INIT; } static int cx23885_start_dma(struct cx23885_tsport *port, @@ -1201,9 +1076,6 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ - if (debug > 4) - cx23885_tsport_reg_dump(port); - return 0; } @@ -1219,7 +1091,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) return 0; } -int cx23885_restart_queue(struct cx23885_tsport *port, +static int cx23885_restart_queue(struct cx23885_tsport *port, struct cx23885_dmaqueue *q) { struct cx23885_dev *dev = port->dev; @@ -1242,7 +1114,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); cx23885_start_dma(port, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(5, "[%p/%d] restart_queue - first active\n", @@ -1253,7 +1125,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1290,7 +1162,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { buf->vb.width = port->ts_packet_size; buf->vb.height = port->ts_packet_count; buf->vb.size = size; @@ -1302,7 +1174,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, videobuf_to_dma(&buf->vb)->sglist, buf->vb.width, buf->vb.height); } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; return 0; fail: @@ -1325,7 +1197,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue, &cx88q->active); cx23885_start_dma(port, cx88q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); dprintk(1, "[%p/%d] %s - first active\n", @@ -1335,7 +1207,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1359,7 +1231,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; + buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); @@ -1371,6 +1243,16 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, spin_unlock_irqrestore(&port->slock, flags); } +void cx23885_cancel_buffers(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + struct cx23885_dmaqueue *q = &port->mpegq; + + dprintk(1, "%s()\n", __FUNCTION__); + del_timer_sync(&q->timeout); + cx23885_stop_dma(port); + do_cancel_buffers(port, "cancel", 0); +} static void cx23885_timeout(unsigned long data) { @@ -1443,15 +1325,12 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_tsport *ts1 = &dev->ts1; struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; - u32 vida_status, vida_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; - int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; + int ts1_count = 0, ts2_count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); - vida_status = cx_read(VID_A_INT_STAT); - vida_mask = cx_read(VID_A_INT_MSK); ts1_status = cx_read(VID_B_INT_STAT); ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); @@ -1460,17 +1339,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; - vida_count = cx_read(VID_A_GPCNT); ts1_count = cx_read(ts1->reg_gpcnt); ts2_count = cx_read(ts2->reg_gpcnt); - dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", - pci_status, pci_mask); - dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", - vida_status, vida_mask, vida_count); - dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", - ts1_status, ts1_mask, ts1_count); - dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", - ts2_status, ts2_mask, ts2_count); + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count ); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count ); if ( (pci_status & PCI_MSK_RISC_RD) || (pci_status & PCI_MSK_RISC_WR) || @@ -1507,18 +1380,11 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - if (ts1_status) { - if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) - handled += cx23885_irq_ts(ts1, ts1_status); - } - - if (ts2_status) { - if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) - handled += cx23885_irq_ts(ts2, ts2_status); - } + if (ts1_status) + handled += cx23885_irq_ts(ts1, ts1_status); - if (vida_status) - handled += cx23885_video_irq(dev, vida_status); + if (ts2_status) + handled += cx23885_irq_ts(ts2, ts2_status); if (handled) cx_write(PCI_INT_STAT, pci_status); diff --git a/trunk/drivers/media/video/cx23885/cx23885-dvb.c b/trunk/drivers/media/video/cx23885/cx23885-dvb.c index ed465c007cea..eda8c05d0931 100644 --- a/trunk/drivers/media/video/cx23885/cx23885-dvb.c +++ b/trunk/drivers/media/video/cx23885/cx23885-dvb.c @@ -32,26 +32,13 @@ #include "s5h1409.h" #include "mt2131.h" -#include "tda8290.h" -#include "tda18271.h" #include "lgdt330x.h" -#include "xc5000.h" #include "dvb-pll.h" -#include "tuner-xc2028.h" -#include "tuner-xc2028-types.h" -static unsigned int debug; +static unsigned int debug = 0; -#define dprintk(level, fmt, arg...)\ - do { if (debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -/* ------------------------------------------------------------------ */ - -static unsigned int alt_tuner; -module_param(alt_tuner, int, 0644); -MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration"); +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) /* ------------------------------------------------------------------ */ @@ -98,39 +85,18 @@ static struct s5h1409_config hauppauge_generic_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, + .if_freq = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct s5h1409_config hauppauge_ezqam_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, - .qam_if = 4000, - .inversion = S5H1409_INVERSION_ON, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .status_mode = S5H1409_DEMODLOCKING }; static struct s5h1409_config hauppauge_hvr1800lp_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct s5h1409_config hauppauge_hvr1500_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_OFF, + .if_freq = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .status_mode = S5H1409_DEMODLOCKING }; static struct mt2131_config hauppauge_generic_tunerconfig = { @@ -143,66 +109,6 @@ static struct lgdt330x_config fusionhdtv_5_express = { .serial_mpeg = 0x40, }; -static struct s5h1409_config hauppauge_hvr1500q_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { - .i2c_address = 0x61, - .if_khz = 5380, - .tuner_callback = cx23885_tuner_callback -}; - -static struct tda829x_config tda829x_no_probe = { - .probe_tuner = TDA829X_DONT_PROBE, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 5380, .std_bits = 0x1b }, - .qam_6 = { .if_freq = 4000, .std_bits = 0x18 }, -}; - -static struct tda18271_config hauppauge_tda18271_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_ANALOG, -}; - -static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg) -{ - struct cx23885_tsport *port = ptr; - struct cx23885_dev *dev = port->dev; - - switch (command) { - case XC2028_TUNER_RESET: - /* Send the tuner in then out of reset */ - /* GPIO-2 xc3028 tuner */ - dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg); - - cx_set(GP0_IO, 0x00040000); - cx_clear(GP0_IO, 0x00000004); - msleep(5); - - cx_set(GP0_IO, 0x00040004); - msleep(5); - break; - case XC2028_RESET_CLK: - dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg); - break; - default: - dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__, - command, arg); - return -EINVAL; - } - - return 0; -} - static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -214,6 +120,7 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1800: i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, @@ -224,36 +131,6 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; - case CX23885_BOARD_HAUPPAUGE_HVR1800: - i2c_bus = &dev->i2c_bus[0]; - switch (alt_tuner) { - case 1: - port->dvb.frontend = - dvb_attach(s5h1409_attach, - &hauppauge_ezqam_config, - &i2c_bus->i2c_adap); - if (port->dvb.frontend != NULL) { - dvb_attach(tda829x_attach, port->dvb.frontend, - &dev->i2c_bus[1].i2c_adap, 0x42, - &tda829x_no_probe); - dvb_attach(tda18271_attach, port->dvb.frontend, - 0x60, &dev->i2c_bus[1].i2c_adap, - &hauppauge_tda18271_config); - } - break; - case 0: - default: - port->dvb.frontend = - dvb_attach(s5h1409_attach, - &hauppauge_generic_config, - &i2c_bus->i2c_adap); - if (port->dvb.frontend != NULL) - dvb_attach(mt2131_attach, port->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_generic_tunerconfig, 0); - break; - } - break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, @@ -275,43 +152,6 @@ static int dvb_register(struct cx23885_tsport *port) &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF); } break; - case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - i2c_bus = &dev->i2c_bus[1]; - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1500q_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - hauppauge_hvr1500q_tunerconfig.priv = i2c_bus; - dvb_attach(xc5000_attach, port->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_hvr1500q_tunerconfig); - } - break; - case CX23885_BOARD_HAUPPAUGE_HVR1500: - i2c_bus = &dev->i2c_bus[1]; - port->dvb.frontend = dvb_attach(s5h1409_attach, - &hauppauge_hvr1500_config, - &dev->i2c_bus[0].i2c_adap); - if (port->dvb.frontend != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &i2c_bus->i2c_adap, - .i2c_addr = 0x61, - .video_dev = port, - .callback = cx23885_hvr1500_xc3028_callback, - }; - static struct xc2028_ctrl ctl = { - .fname = "xc3028-v27.fw", - .max_len = 64, - .scode_table = OREN538, - }; - - fe = dvb_attach(xc2028_attach, - port->dvb.frontend, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctl); - } - break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); @@ -325,9 +165,6 @@ static int dvb_register(struct cx23885_tsport *port) /* Put the analog decoder in standby to keep it quiet */ cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL); - if (port->dvb.frontend->ops.analog_ops.standby) - port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend); - /* register everything */ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); diff --git a/trunk/drivers/media/video/cx23885/cx23885-i2c.c b/trunk/drivers/media/video/cx23885/cx23885-i2c.c index 92fe0bd37c84..71da528932df 100644 --- a/trunk/drivers/media/video/cx23885/cx23885-i2c.c +++ b/trunk/drivers/media/video/cx23885/cx23885-i2c.c @@ -29,7 +29,7 @@ #include -static unsigned int i2c_debug; +static unsigned int i2c_debug = 0; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); @@ -37,10 +37,8 @@ static unsigned int i2c_scan = 0; module_param(i2c_scan, int, 0444); MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); -#define dprintk(level, fmt, arg...)\ - do { if (i2c_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) +#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) #define I2C_WAIT_DELAY 32 #define I2C_WAIT_RETRY 64 @@ -79,19 +77,14 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap) } static int i2c_sendbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined_rlen) + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; u32 wdata, addr, ctrl; int retval, cnt; - if (joined_rlen) - dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__, - msg->len, joined_rlen); - else - dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); - + dprintk(1, "%s()\n", __FUNCTION__); /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { cx_write(bus->reg_addr, msg->addr << 25); @@ -113,8 +106,6 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (msg->len > 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; - else if (joined_rlen) - ctrl |= I2C_NOSTOP; cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); @@ -136,10 +127,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, wdata = msg->buf[cnt]; ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - if (cnt < msg->len - 1) + if (cnt < msg->len-1 || !last) ctrl |= I2C_NOSTOP | I2C_EXTEND; - else if (joined_rlen) - ctrl |= I2C_NOSTOP; cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); @@ -161,22 +150,19 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; err: - if (i2c_debug) - printk(" ERR: %d\n", retval); + printk(" ERR: %d\n", retval); return retval; } static int i2c_readbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int joined) + const struct i2c_msg *msg, int last) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; u32 ctrl, cnt; int retval; - - if (i2c_debug && !joined) - dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); + dprintk(1, "%s()\n", __FUNCTION__); /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { @@ -192,18 +178,11 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, return 0; } - if (i2c_debug) { - if (joined) - printk(" R"); - else - printk(" addr << 1) + 1); - } - for(cnt = 0; cnt < msg->len; cnt++) { ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; - if (cnt < msg->len - 1) + if (cnt < msg->len-1 || !last) ctrl |= I2C_NOSTOP | I2C_EXTEND; cx_write(bus->reg_addr, msg->addr << 25); @@ -216,7 +195,9 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, goto eio; msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; if (i2c_debug) { - printk(" %02x", msg->buf[cnt]); + if (!(ctrl & I2C_NOSTOP)) + printk(" addr << 1) +1); + printk(" =%02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) printk(" >\n"); } @@ -226,8 +207,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; err: - if (i2c_debug) - printk(" ERR: %d\n", retval); + printk(" ERR: %d\n", retval); return retval; } @@ -245,22 +225,15 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, __FUNCTION__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { /* read */ - retval = i2c_readbytes(i2c_adap, &msgs[i], 0); - } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && - msgs[i].addr == msgs[i + 1].addr) { - /* write then read from same address */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], - msgs[i + 1].len); + retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); if (retval < 0) goto err; - i++; - retval = i2c_readbytes(i2c_adap, &msgs[i], 1); } else { /* write */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); + retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num); + if (retval < 0) + goto err; } - if (retval < 0) - goto err; } return num; @@ -270,9 +243,7 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, static int attach_inform(struct i2c_client *client) { - struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter); - struct cx23885_dev *dev = bus->dev; - struct tuner_setup tun_setup; + struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); @@ -280,31 +251,6 @@ static int attach_inform(struct i2c_client *client) if (!client->driver->command) return 0; - if (dev->tuner_type != UNSET) { - - dprintk(1, "%s (tuner) i2c attach [addr=0x%x,client=%s]\n", - client->driver->driver.name, client->addr, - client->name); - - if ((dev->tuner_addr == ADDR_UNSET) || - (dev->tuner_addr == client->addr)) { - - dprintk(1, "%s (tuner || addr UNSET)\n", - client->driver->driver.name); - - dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->driver.name, - client->addr, client->name); - - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - client->driver->command(client, TUNER_SET_TYPE_ADDR, - &tun_setup); - } - } - return 0; } @@ -343,7 +289,6 @@ static struct i2c_adapter cx23885_i2c_adap_template = { .owner = THIS_MODULE, .id = I2C_HW_B_CX23885, .algo = &cx23885_i2c_algo_template, - .class = I2C_CLASS_TV_ANALOG, .client_register = attach_inform, .client_unregister = detach_inform, }; @@ -360,7 +305,7 @@ static char *i2c_devs[128] = { [ 0x84 >> 1 ] = "tda8295", [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275", - [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000", + [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275", }; static void do_i2c_scan(char *name, struct i2c_client *c) @@ -399,7 +344,6 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; - i2c_set_adapdata(&bus->i2c_adap, bus); i2c_add_adapter(&bus->i2c_adap); bus->i2c_client.adapter = &bus->i2c_adap; @@ -422,6 +366,8 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus) /* ----------------------------------------------------------------------- */ +EXPORT_SYMBOL(cx23885_call_i2c_clients); + /* * Local variables: * c-basic-offset: 8 diff --git a/trunk/drivers/media/video/cx23885/cx23885-reg.h b/trunk/drivers/media/video/cx23885/cx23885-reg.h index bdd11bc513ad..162169f9091b 100644 --- a/trunk/drivers/media/video/cx23885/cx23885-reg.h +++ b/trunk/drivers/media/video/cx23885/cx23885-reg.h @@ -233,17 +233,6 @@ Channel manager Data Structure entry = 20 DWORD #define VID_A_INT_SSTAT 0x0004002C #define VID_B_INT_MSK 0x00040030 -#define VID_B_MSK_BAD_PKT (1 << 20) -#define VID_B_MSK_VBI_OPC_ERR (1 << 17) -#define VID_B_MSK_OPC_ERR (1 << 16) -#define VID_B_MSK_VBI_SYNC (1 << 13) -#define VID_B_MSK_SYNC (1 << 12) -#define VID_B_MSK_VBI_OF (1 << 9) -#define VID_B_MSK_OF (1 << 8) -#define VID_B_MSK_VBI_RISCI2 (1 << 5) -#define VID_B_MSK_RISCI2 (1 << 4) -#define VID_B_MSK_VBI_RISCI1 (1 << 1) -#define VID_B_MSK_RISCI1 1 #define VID_B_INT_STAT 0x00040034 #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C @@ -287,7 +276,6 @@ Channel manager Data Structure entry = 20 DWORD #define RDR_CFG0 0x00050000 #define RDR_CFG1 0x00050004 -#define RDR_CFG2 0x00050008 #define RDR_TLCTL0 0x00050318 /* APB DMAC Current Buffer Pointer */ @@ -347,7 +335,6 @@ Channel manager Data Structure entry = 20 DWORD /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ #define MC417_OEN 0x00110024 #define MC417_CTL 0x00110028 -#define ALT_PIN_OUT_SEL 0x0011002C #define CLK_DELAY 0x00110048 #define PAD_CTRL 0x0011004C diff --git a/trunk/drivers/media/video/cx23885/cx23885-vbi.c b/trunk/drivers/media/video/cx23885/cx23885-vbi.c deleted file mode 100644 index e36e3fcae2fb..000000000000 --- a/trunk/drivers/media/video/cx23885/cx23885-vbi.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2007 Steven Toth - * - * 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 -#include -#include -#include -#include - -#include "cx23885.h" - -static unsigned int vbibufs = 4; -module_param(vbibufs, int, 0644); -MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); - -static unsigned int vbi_debug; -module_param(vbi_debug, int, 0644); -MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); - -#define dprintk(level, fmt, arg...)\ - do { if (vbi_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -/* ------------------------------------------------------------------ */ - -int cx23885_vbi_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (dev->tvnorm & V4L2_STD_525_60) { - /* ntsc */ - f->fmt.vbi.sampling_rate = 28636363; - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.start[1] = 273; - - } else if (dev->tvnorm & V4L2_STD_625_50) { - /* pal */ - f->fmt.vbi.sampling_rate = 35468950; - f->fmt.vbi.start[0] = 7 - 1; - f->fmt.vbi.start[1] = 319 - 1; - } - return 0; -} - -static int cx23885_start_vbi_dma(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) -{ - /* setup fifo + format */ - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], - buf->vb.width, buf->risc.dma); - - /* reset counter */ - q->count = 1; - - /* enable irqs */ - cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); - cx_set(VID_A_INT_MSK, 0x000022); - - /* start dma */ - cx_set(DEV_CNTRL2, (1<<5)); - cx_set(VID_A_DMA_CTL, 0x00000022); - - return 0; -} - -int cx23885_stop_vbi_dma(struct cx23885_dev *dev) -{ - /* stop dma */ - cx_clear(VID_A_DMA_CTL, 0x00000022); - - /* disable irqs */ - cx_clear(PCI_INT_MSK, 0x000001); - cx_clear(VID_A_INT_MSK, 0x00000022); - return 0; -} - -int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) -{ - struct cx23885_buffer *buf; - struct list_head *item; - - if (list_empty(&q->active)) - return 0; - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_vbi_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; -} - -void cx23885_vbi_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vbiq; - struct cx23885_buffer *buf; - unsigned long flags; - - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); - - cx_clear(VID_A_DMA_CTL, 0x22); - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, - buf, buf->vb.i, (unsigned long)buf->risc.dma); - } - cx23885_restart_vbi_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - -/* ------------------------------------------------------------------ */ -#define VBI_LINE_LENGTH 2048 -#define VBI_LINE_COUNT 17 - -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; - return 0; -} - -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - unsigned int size; - int rc; - - size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = VBI_LINE_LENGTH; - buf->vb.height = VBI_LINE_COUNT; - buf->vb.size = size; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->vb.width * buf->vb.height, - buf->vb.width, 0, - buf->vb.height); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx23885_free_buffer(q, buf); - return rc; -} - -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_dmaqueue *q = &dev->vbiq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_vbi_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] vbi_queue - first active\n", - buf, buf->vb.i); - - } else { - prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - } -} - -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -struct videobuf_queue_ops cx23885_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; - -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/trunk/drivers/media/video/cx23885/cx23885-video.c b/trunk/drivers/media/video/cx23885/cx23885-video.c deleted file mode 100644 index d3c4d2c5cbe0..000000000000 --- a/trunk/drivers/media/video/cx23885/cx23885-video.c +++ /dev/null @@ -1,1557 +0,0 @@ -/* - * Driver for the Conexant CX23885 PCIe bridge - * - * Copyright (c) 2007 Steven Toth - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cx23885.h" -#include - -#ifdef CONFIG_VIDEO_V4L1_COMPAT -/* Include V4L1 specific functions. Should be removed soon */ -#include -#endif - -MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); -MODULE_AUTHOR("Steven Toth "); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------------ */ - -static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; - -module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); - -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -static unsigned int video_debug; -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); - -static unsigned int irq_debug; -module_param(irq_debug, int, 0644); -MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); - -static unsigned int vid_limit = 16; -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); - -#define dprintk(level, fmt, arg...)\ - do { if (video_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ - } while (0) - -/* ------------------------------------------------------------------- */ -/* static data */ - -#define FORMAT_FLAGS_PACKED 0x01 - -static struct cx23885_fmt formats[] = { - { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, -}; - -static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats); i++) - if (formats[i].fourcc == fourcc) - return formats+i; - - printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc); - return NULL; -} - -/* ------------------------------------------------------------------- */ - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct cx23885_ctrl cx23885_ctls[] = { - /* --- video --- */ - { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = LUMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = LUMA_CTRL, - .mask = 0xff00, - .shift = 8, - }, { - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = CHROMA_CTRL, - .mask = 0xff0000, - .shift = 16, - }, { - /* strictly, this only describes only U saturation. - * V saturation is handled specially through code. - */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = CHROMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = PATH1_CTL1, - .mask = (0x1f << 24), - .shift = 24, - }, { - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = PATH1_VOL_CTL, - .mask = 0xff, - .shift = 0, - } -}; -static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); - -const u32 cx23885_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_MUTE, - 0 -}; -EXPORT_SYMBOL(cx23885_user_ctrls); - -static const u32 *ctrl_classes[] = { - cx23885_user_ctrls, - NULL -}; - -void cx23885_video_wakeup(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, u32 count) -{ - struct cx23885_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - do_gettimeofday(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } - if (list_empty(&q->active)) { - del_timer(&q->timeout); - } else { - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - } - if (bc != 1) - printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", - __FUNCTION__, bc); -} - -int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) -{ - dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", - __FUNCTION__, - (unsigned int)norm, - v4l2_norm_to_name(norm)); - - dev->tvnorm = norm; - - /* Tell the analog tuner/demods */ - cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm); - - /* Tell the internal A/V decoder */ - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm); - - return 0; -} - -struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, - struct pci_dev *pci, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - dprintk(1, "%s()\n", __FUNCTION__); - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->minor = -1; - vfd->dev = &pci->dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, cx23885_boards[dev->board].name); - return vfd; -} - -int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || - qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX23885_CTLS; i++) - if (cx23885_ctls[i].v.id == qctrl->id) - break; - if (i == CX23885_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx23885_ctls[i].v; - return 0; -} -EXPORT_SYMBOL(cx23885_ctrl_query); - -/* ------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bit) -{ - dprintk(1, "%s()\n", __FUNCTION__); - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_check(struct cx23885_fh *fh, unsigned int bit) -{ - return (fh->resources & bit); -} - -static int res_locked(struct cx23885_dev *dev, unsigned int bit) -{ - return (dev->resources & bit); -} - -static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __FUNCTION__); - - mutex_lock(&dev->lock); - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); -} - -int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) -{ - struct v4l2_routing route; - memset(&route, 0, sizeof(route)); - - dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", - __FUNCTION__, - input, INPUT(input)->vmux, - INPUT(input)->gpio0, INPUT(input)->gpio1, - INPUT(input)->gpio2, INPUT(input)->gpio3); - dev->input = input; - - route.input = INPUT(input)->vmux; - - /* Tell the internal A/V decoder */ - cx23885_call_i2c_clients(&dev->i2c_bus[2], - VIDIOC_INT_S_VIDEO_ROUTING, &route); - - return 0; -} -EXPORT_SYMBOL(cx23885_video_mux); - -/* ------------------------------------------------------------------ */ -int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, - unsigned int height, enum v4l2_field field) -{ - dprintk(1, "%s()\n", __FUNCTION__); - return 0; -} - -static int cx23885_start_video_dma(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q, - struct cx23885_buffer *buf) -{ - dprintk(1, "%s()\n", __FUNCTION__); - - /* setup fifo + format */ - cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], - buf->bpl, buf->risc.dma); - cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); - - /* reset counter */ - cx_write(VID_A_GPCNT_CTL, 3); - q->count = 1; - - /* enable irq */ - cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); - cx_set(VID_A_INT_MSK, 0x000011); - - /* start dma */ - cx_set(DEV_CNTRL2, (1<<5)); - cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ - - return 0; -} - - -static int cx23885_restart_video_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) -{ - struct cx23885_buffer *buf, *prev; - struct list_head *item; - dprintk(1, "%s()\n", __FUNCTION__); - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_video_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, - vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - struct cx23885_fh *fh = q->priv_data; - - *size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 == *count) - *count = 32; - while (*size * *count > vid_limit * 1024 * 1024) - (*count)--; - return 0; -} - -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - int rc, init_buffer = 0; - u32 line0_offset, line1_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) - return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - init_buffer = 1; - } - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - } - - if (init_buffer) { - buf->bpl = buf->vb.width * buf->fmt->depth >> 3; - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) { - /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating NTSC risc\n", - __FUNCTION__); - line0_offset = buf->bpl; - line1_offset = 0; - } else { - /* All other formats are top field first */ - dprintk(1, "%s() Creating PAL/SECAM risc\n", - __FUNCTION__); - line0_offset = 0; - line1_offset = buf->bpl; - } - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - line1_offset, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); - } - } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, - fh->width, fh->height, fh->fmt->depth, fh->fmt->name, - (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - - fail: - cx23885_free_buffer(q, buf); - return rc; -} - -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_dmaqueue *q = &dev->vidq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - - } else { - prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -static struct videobuf_queue_ops cx23885_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static struct videobuf_queue *get_queue(struct cx23885_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return &fh->vbiq; - default: - BUG(); - return NULL; - } -} - -static int get_resource(struct cx23885_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return RESOURCE_VBI; - default: - BUG(); - return 0; - } -} - -static int video_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct cx23885_dev *h, *dev = NULL; - struct cx23885_fh *fh; - struct list_head *list; - enum v4l2_buf_type type = 0; - int radio = 0; - - list_for_each(list, &cx23885_devlist) { - h = list_entry(list, struct cx23885_dev, devlist); - if (h->video_dev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev && - h->vbi_dev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && - h->radio_dev->minor == minor) { - radio = 1; - dev = h; - } - } - if (NULL == dev) - return -ENODEV; - - dprintk(1, "open minor=%d radio=%d type=%s\n", - minor, radio, v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); - - videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops, - dev->pci, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh); - - dprintk(1, "post videobuf_queue_init()\n"); - - - return 0; -} - -static ssize_t video_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx23885_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - default: - BUG(); - return 0; - } -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_buffer *buf; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); - } - - if (res_check(fh, RESOURCE_VIDEO)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - return POLLERR; - buf = list_entry(fh->vidq.stream.next, - struct cx23885_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx23885_buffer *)fh->vidq.read_buf; - if (NULL == buf) - return POLLERR; - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - return 0; -} - -static int video_release(struct inode *inode, struct file *file) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - /* FIXME */ - res_free(dev, fh, RESOURCE_OVERLAY); - } - - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(&fh->vidq); - res_free(dev, fh, RESOURCE_VIDEO); - } - if (fh->vidq.read_buf) { - buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } - - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbiq.streaming) - videobuf_streamoff(&fh->vbiq); - if (fh->vbiq.reading) - videobuf_read_stop(&fh->vbiq); - res_free(dev, fh, RESOURCE_VBI); - } - - videobuf_mmap_free(&fh->vidq); - file->private_data = NULL; - kfree(fh); - - /* We are not putting the tuner to sleep here on exit, because - * we want to use the mpeg encoder in another session to capture - * tuner video. Closing this will result in no video to the encoder. - */ - - return 0; -} - -static int video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); -} - -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__); - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl); - return 0; -} -EXPORT_SYMBOL(cx23885_get_control); - -int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" - " (disabled - no action)\n", __FUNCTION__); - return 0; -} -EXPORT_SYMBOL(cx23885_set_control); - -static void init_controls(struct cx23885_dev *dev) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX23885_CTLS; i++) { - ctrl.id = cx23885_ctls[i].v.id; - ctrl.value = cx23885_ctls[i].v.default_value; - - cx23885_set_control(dev, &ctrl); - } -} - -/* ------------------------------------------------------------------ */ -/* VIDEO IOCTLS */ - -static int vidioc_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - struct cx23885_fmt *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = norm_maxw(dev->tvnorm); - maxh = norm_maxh(dev->tvnorm); - - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -static int vidioc_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - int err; - - dprintk(2, "%s()\n", __FUNCTION__); - err = vidioc_try_fmt_cap(file, priv, f); - - if (0 != err) - return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vidq.field = f->fmt.pix.field; - dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__, - fh->width, fh->height, fh->vidq.field); - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f); - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - strcpy(cap->driver, "cx23885"); - strlcpy(cap->card, cx23885_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->version = CX23885_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; - if (UNSET != dev->tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; -} - -static int vidioc_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(formats))) - return -EINVAL; - - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; - - return 0; -} - -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, - struct video_mbuf *mbuf) -{ - struct cx23885_fh *fh = priv; - struct videobuf_queue *q; - struct v4l2_requestbuffers req; - unsigned int i; - int err; - - q = get_queue(fh); - memset(&req, 0, sizeof(req)); - req.type = q->type; - req.count = 8; - req.memory = V4L2_MEMORY_MMAP; - err = videobuf_reqbufs(q, &req); - if (err < 0) - return err; - - mbuf->frames = req.count; - mbuf->size = 0; - for (i = 0; i < mbuf->frames; i++) { - mbuf->offsets[i] = q->bufs[i]->boff; - mbuf->size += q->bufs[i]->bsize; - } - return 0; -} -#endif - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx23885_fh *fh = priv; - return (videobuf_reqbufs(get_queue(fh), p)); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return (videobuf_querybuf(get_queue(fh), p)); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return (videobuf_qbuf(get_queue(fh), p)); -} - -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return (videobuf_dqbuf(get_queue(fh), p, - file->f_flags & O_NONBLOCK)); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - dprintk(1, "%s()\n", __FUNCTION__); - - if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) - return -EINVAL; - if (unlikely(i != fh->type)) - return -EINVAL; - - if (unlikely(!res_get(dev, fh, get_resource(fh)))) - return -EBUSY; - return videobuf_streamon(get_queue(fh)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - int err, res; - dprintk(1, "%s()\n", __FUNCTION__); - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - res = get_resource(fh); - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - dprintk(1, "%s()\n", __FUNCTION__); - - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, *tvnorms); - mutex_unlock(&dev->lock); - - return 0; -} - -int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) -{ - static const char *iname[] = { - [CX23885_VMUX_COMPOSITE1] = "Composite1", - [CX23885_VMUX_COMPOSITE2] = "Composite2", - [CX23885_VMUX_COMPOSITE3] = "Composite3", - [CX23885_VMUX_COMPOSITE4] = "Composite4", - [CX23885_VMUX_SVIDEO] = "S-Video", - [CX23885_VMUX_TELEVISION] = "Television", - [CX23885_VMUX_CABLE] = "Cable TV", - [CX23885_VMUX_DVB] = "DVB", - [CX23885_VMUX_DEBUG] = "for debug only", - }; - unsigned int n; - dprintk(1, "%s()\n", __FUNCTION__); - - n = i->index; - if (n >= 4) - return -EINVAL; - - if (0 == INPUT(n)->type) - return -EINVAL; - - memset(i, 0, sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); - if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || - (CX23885_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX23885_NORMS; - return 0; -} -EXPORT_SYMBOL(cx23885_enum_input); - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - dprintk(1, "%s()\n", __FUNCTION__); - return cx23885_enum_input(dev, i); -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - *i = dev->input; - dprintk(1, "%s() returns %d\n", __FUNCTION__, *i); - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - dprintk(1, "%s(%d)\n", __FUNCTION__, i); - - if (i >= 4) { - dprintk(1, "%s() -EINVAL\n", __FUNCTION__); - return -EINVAL; - } - - mutex_lock(&dev->lock); - cx23885_video_mux(dev, i); - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx23885_ctrl_query(qctrl); -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - t->signal = 0xffff ; /* LOCKED */ - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->freq; - - cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f); - - return 0; -} - -int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) -{ - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (unlikely(f->tuner != 0)) - return -EINVAL; - - mutex_lock(&dev->lock); - dev->freq = f->frequency; - - cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f); - - /* When changing channels it is required to reset TVAUDIO */ - msleep(10); - - mutex_unlock(&dev->lock); - - return 0; -} -EXPORT_SYMBOL(cx23885_set_freq); - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - return - cx23885_set_freq(dev, f); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register(struct file *file, void *fh, - struct v4l2_register *reg) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; - - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg); - - return 0; -} - -static int vidioc_s_register(struct file *file, void *fh, - struct v4l2_register *reg) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; - - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - - cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg); - - return 0; -} -#endif - -/* ----------------------------------------------------------- */ - -static void cx23885_vid_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vidq; - struct cx23885_buffer *buf; - unsigned long flags; - - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); - - cx_clear(VID_A_DMA_CTL, 0x11); - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - cx23885_restart_video_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - -int cx23885_video_irq(struct cx23885_dev *dev, u32 status) -{ - u32 mask, count; - int handled = 0; - - mask = cx_read(VID_A_INT_MSK); - if (0 == (status & mask)) - return handled; - cx_write(VID_A_INT_STAT, status); - - dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status); - /* risc op code error */ - if (status & (1 << 16)) { - printk(KERN_WARNING "%s/0: video risc op code error\n", - dev->name); - cx_clear(VID_A_DMA_CTL, 0x11); - cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); - } - - /* risc1 y */ - if (status & 0x01) { - spin_lock(&dev->slock); - count = cx_read(VID_A_GPCNT); - cx23885_video_wakeup(dev, &dev->vidq, count); - spin_unlock(&dev->slock); - handled++; - } - /* risc2 y */ - if (status & 0x10) { - dprintk(2, "stopper video\n"); - spin_lock(&dev->slock); - cx23885_restart_video_queue(dev, &dev->vidq); - spin_unlock(&dev->slock); - handled++; - } - - return handled; -} - -/* ----------------------------------------------------------- */ -/* exported stuff */ - -static const struct file_operations video_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -static struct video_device cx23885_vbi_template; -static struct video_device cx23885_video_template = { - .name = "cx23885-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, - .vidioc_g_fmt_vbi = cx23885_vbi_fmt, - .vidioc_try_fmt_vbi = cx23885_vbi_fmt, - .vidioc_s_fmt_vbi = cx23885_vbi_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, -#ifdef CONFIG_VIDEO_V4L1_COMPAT - .vidiocgmbuf = vidiocgmbuf, -#endif - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif - .tvnorms = CX23885_NORMS, - .current_norm = V4L2_STD_NTSC_M, -}; - -static const struct file_operations radio_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - - -void cx23885_video_unregister(struct cx23885_dev *dev) -{ - dprintk(1, "%s()\n", __FUNCTION__); - cx_clear(PCI_INT_MSK, 1); - - if (dev->video_dev) { - if (-1 != dev->video_dev->minor) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - - btcx_riscmem_free(dev->pci, &dev->vidq.stopper); - } -} - -int cx23885_video_register(struct cx23885_dev *dev) -{ - int err; - - dprintk(1, "%s()\n", __FUNCTION__); - spin_lock_init(&dev->slock); - - /* Initialize VBI template */ - memcpy(&cx23885_vbi_template, &cx23885_video_template, - sizeof(cx23885_vbi_template)); - strcpy(cx23885_vbi_template.name, "cx23885-vbi"); - cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; - - dev->tvnorm = cx23885_video_template.current_norm; - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - dev->vidq.timeout.function = cx23885_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, - VID_A_DMA_CTL, 0x11, 0x00); - - /* Don't enable VBI yet */ - cx_set(PCI_INT_MSK, 1); - - - /* register v4l devices */ - dev->video_dev = cx23885_vdev_init(dev, dev->pci, - &cx23885_video_template, "video"); - err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, - video_nr[dev->nr]); - if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - goto fail_unreg; - } - printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", - dev->name, dev->video_dev->minor & 0x1f); - /* initial device configuration */ - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, dev->tvnorm); - init_controls(dev); - cx23885_video_mux(dev, 0); - mutex_unlock(&dev->lock); - - return 0; - -fail_unreg: - cx23885_video_unregister(dev); - return err; -} - diff --git a/trunk/drivers/media/video/cx23885/cx23885.h b/trunk/drivers/media/video/cx23885/cx23885.h index 7cb2179f2622..dec4dc2fcbb4 100644 --- a/trunk/drivers/media/video/cx23885/cx23885.h +++ b/trunk/drivers/media/video/cx23885/cx23885.h @@ -44,10 +44,6 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 -#define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ @@ -57,62 +53,6 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 -#define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 -#define CX23885_BOARD_HAUPPAUGE_HVR1500 6 - -/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ -#define CX23885_NORMS (\ - V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ - V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ - V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ - V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) - -struct cx23885_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ - int depth; - int flags; - u32 cxformat; -}; - -struct cx23885_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - -struct cx23885_tvnorm { - char *name; - v4l2_std_id id; - u32 cxiformat; - u32 cxoformat; -}; - -struct cx23885_fh { - struct cx23885_dev *dev; - enum v4l2_buf_type type; - int radio; - u32 resources; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - - /* video capture */ - struct cx23885_fmt *fmt; - unsigned int width, height; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* MPEG Encoder specifics ONLY */ - struct videobuf_queue mpegq; - atomic_t v4l_reading; -}; enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, @@ -152,28 +92,12 @@ struct cx23885_input { typedef enum { CX23885_MPEG_UNDEFINED = 0, - CX23885_MPEG_DVB, - CX23885_ANALOG_VIDEO, + CX23885_MPEG_DVB } port_t; struct cx23885_board { char *name; - port_t porta, portb, portc; - unsigned int tuner_type; - unsigned int radio_type; - unsigned char tuner_addr; - unsigned char radio_addr; - - /* Vendors can and do run the PCIe bridge at different - * clock rates, driven physically by crystals on the PCBs. - * The core has to accomodate this. This allows the user - * to add new boards with new frequencys. The value is - * expressed in Hz. - * - * The core framework will default this value based on - * current designs, but it can vary. - */ - u32 clk_freq; + port_t portb, portc; struct cx23885_input input[MAX_CX23885_INPUT]; }; @@ -265,11 +189,6 @@ struct cx23885_dev { u32 __iomem *lmmio; u8 __iomem *bmmio; int pci_irqmask; - int hwrevision; - - /* This valud is board specific and is used to configure the - * AV core so we see nice clean and stable video and audio. */ - u32 clk_freq; /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ struct cx23885_i2c i2c_bus[3]; @@ -291,31 +210,8 @@ struct cx23885_dev { CX23885_BRIDGE_885 = 885, CX23885_BRIDGE_887 = 887, } bridge; - - /* Analog video */ - u32 resources; - unsigned int input; - u32 tvaudio; - v4l2_std_id tvnorm; - unsigned int tuner_type; - unsigned char tuner_addr; - unsigned int radio_type; - unsigned char radio_addr; - unsigned int has_radio; - - /* V4l */ - u32 freq; - struct video_device *video_dev; - struct video_device *vbi_dev; - struct video_device *radio_dev; - - struct cx23885_dmaqueue vidq; - struct cx23885_dmaqueue vbiq; - spinlock_t slock; }; -extern struct list_head cx23885_devlist; - #define SRAM_CH01 0 /* Video A */ #define SRAM_CH02 1 /* VBI A */ #define SRAM_CH03 2 /* Video B */ @@ -358,42 +254,19 @@ struct sram_channel { #define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) #define cx_clear(reg,bit) cx_andor((reg),(bit),0) -/* ----------------------------------------------------------- */ -/* cx23885-core.c */ - extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, struct sram_channel *ch, unsigned int bpl, u32 risc); -extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); - -extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - -extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, - unsigned int top_offset, unsigned int bottom_offset, - unsigned int bpl, unsigned int padding, unsigned int lines); - -void cx23885_cancel_buffers(struct cx23885_tsport *port); - -extern int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q); - -extern void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count); - - /* ----------------------------------------------------------- */ -/* cx23885-cards.c */ +/* cx23885-cards.c */ + extern struct cx23885_board cx23885_boards[]; extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; -extern int cx23885_tuner_callback(void *priv, int command, int arg); extern void cx23885_card_list(struct cx23885_dev *dev); extern int cx23885_ir_init(struct cx23885_dev *dev); extern void cx23885_gpio_setup(struct cx23885_dev *dev); @@ -407,50 +280,19 @@ extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, struct cx23885_buffer *buf, enum v4l2_field field); + extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ -/* cx23885-video.c */ -/* Video */ -extern int cx23885_video_register(struct cx23885_dev *dev); -extern void cx23885_video_unregister(struct cx23885_dev *dev); -extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); - -/* ----------------------------------------------------------- */ -/* cx23885-vbi.c */ -extern int cx23885_vbi_fmt(struct file *file, void *priv, - struct v4l2_format *f); -extern void cx23885_vbi_timeout(unsigned long data); -extern struct videobuf_queue_ops cx23885_vbi_qops; - /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); -/* ----------------------------------------------------------- */ -/* tv norms */ - -static inline unsigned int norm_maxw(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; -} - -static inline unsigned int norm_maxh(v4l2_std_id norm) -{ - return (norm & V4L2_STD_625_50) ? 576 : 480; -} - -static inline unsigned int norm_swidth(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; -} - - /* * Local variables: * c-basic-offset: 8 diff --git a/trunk/drivers/media/video/cx25840/cx25840-audio.c b/trunk/drivers/media/video/cx25840/cx25840-audio.c index d6421e1e8f6a..3d46a776df36 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-audio.c +++ b/trunk/drivers/media/video/cx25840/cx25840-audio.c @@ -32,156 +32,118 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) /* common for all inputs and rates */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ - if (!state->is_cx23885) - cx25840_write(client, 0x127, 0x50); + cx25840_write(client, 0x127, 0x50); if (state->aud_input != CX25840_AUDIO_SERIAL) { switch (freq) { case 32000: - if (state->is_cx23885) { - /* We don't have register values - * so avoid destroying registers. */ - break; - } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x1006040f); + cx25840_write4(client, 0x108, 0x0f040610); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x01bb39ee); + cx25840_write4(client, 0x110, 0xee39bb01); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x0801f77f */ - cx25840_write4(client, 0x900, 0x0801f77f); - cx25840_write4(client, 0x904, 0x0801f77f); - cx25840_write4(client, 0x90c, 0x0801f77f); + cx25840_write4(client, 0x900, 0x7ff70108); + cx25840_write4(client, 0x904, 0x7ff70108); + cx25840_write4(client, 0x90c, 0x7ff70108); break; case 44100: - if (state->is_cx23885) { - /* We don't have register values - * so avoid destroying registers. */ - break; - } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x1009040f); + cx25840_write4(client, 0x108, 0x0f040910); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x00ec6bd6); + cx25840_write4(client, 0x110, 0xd66bec00); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x08016d59 */ - cx25840_write4(client, 0x900, 0x08016d59); - cx25840_write4(client, 0x904, 0x08016d59); - cx25840_write4(client, 0x90c, 0x08016d59); + cx25840_write4(client, 0x900, 0x596d0108); + cx25840_write4(client, 0x904, 0x596d0108); + cx25840_write4(client, 0x90c, 0x596d0108); break; case 48000: - if (state->is_cx23885) { - /* We don't have register values - * so avoid destroying registers. */ - break; - } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x100a040f); + cx25840_write4(client, 0x108, 0x0f040a10); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x0098d6e5); + cx25840_write4(client, 0x110, 0xe5d69800); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x08014faa */ - cx25840_write4(client, 0x900, 0x08014faa); - cx25840_write4(client, 0x904, 0x08014faa); - cx25840_write4(client, 0x90c, 0x08014faa); + cx25840_write4(client, 0x900, 0xaa4f0108); + cx25840_write4(client, 0x904, 0xaa4f0108); + cx25840_write4(client, 0x90c, 0xaa4f0108); break; } } else { switch (freq) { case 32000: - if (state->is_cx23885) { - /* We don't have register values - * so avoid destroying registers. */ - break; - } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x1e08040f); + cx25840_write4(client, 0x108, 0x0f04081e); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x012a0869); + cx25840_write4(client, 0x110, 0x69082a01); if (state->is_cx25836) break; /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0x08010000); + cx25840_write4(client, 0x8f8, 0x00000108); /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x08020000); - cx25840_write4(client, 0x904, 0x08020000); - cx25840_write4(client, 0x90c, 0x08020000); + cx25840_write4(client, 0x900, 0x00000208); + cx25840_write4(client, 0x904, 0x00000208); + cx25840_write4(client, 0x90c, 0x00000208); /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ cx25840_write(client, 0x127, 0x54); break; case 44100: - if (state->is_cx23885) { - /* We don't have register values - * so avoid destroying registers. */ - break; - } - /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x1809040f); + cx25840_write4(client, 0x108, 0x0f040918); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x00ec6bd6); + cx25840_write4(client, 0x110, 0xd66bec00); if (state->is_cx25836) break; /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0x080160cd); + cx25840_write4(client, 0x8f8, 0xcd600108); /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x08017385); - cx25840_write4(client, 0x904, 0x08017385); - cx25840_write4(client, 0x90c, 0x08017385); + cx25840_write4(client, 0x900, 0x85730108); + cx25840_write4(client, 0x904, 0x85730108); + cx25840_write4(client, 0x90c, 0x85730108); break; case 48000: - if (!state->is_cx23885) { - /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x180a040f); + /* VID_PLL and AUX_PLL */ + cx25840_write4(client, 0x108, 0x0f040a18); - /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x0098d6e5); - } + /* AUX_PLL_FRAC */ + cx25840_write4(client, 0x110, 0xe5d69800); if (state->is_cx25836) break; - if (!state->is_cx23885) { - /* src1_ctl */ - cx25840_write4(client, 0x8f8, 0x08018000); - - /* src3/4/6_ctl */ - cx25840_write4(client, 0x900, 0x08015555); - cx25840_write4(client, 0x904, 0x08015555); - cx25840_write4(client, 0x90c, 0x08015555); - } else { - - cx25840_write4(client, 0x8f8, 0x0801867c); + /* src1_ctl = 0x08010000 */ + cx25840_write4(client, 0x8f8, 0x00800108); - cx25840_write4(client, 0x900, 0x08014faa); - cx25840_write4(client, 0x904, 0x08014faa); - cx25840_write4(client, 0x90c, 0x08014faa); - } + /* src3/4/6_ctl = 0x08020000 */ + cx25840_write4(client, 0x900, 0x55550108); + cx25840_write4(client, 0x904, 0x55550108); + cx25840_write4(client, 0x90c, 0x55550108); break; } } @@ -206,14 +168,14 @@ void cx25840_audio_set_path(struct i2c_client *client) if (state->aud_input == CX25840_AUDIO_SERIAL) { /* Set Path1 to Serial Audio Input */ - cx25840_write4(client, 0x8d0, 0x01011012); + cx25840_write4(client, 0x8d0, 0x12100101); /* The microcontroller should not be started for the * non-tuner inputs: autodetection is specific for * TV audio. */ } else { /* Set Path1 to Analog Demod Main Channel */ - cx25840_write4(client, 0x8d0, 0x1f063870); + cx25840_write4(client, 0x8d0, 0x7038061f); } set_audclk_freq(client, state->audclk_freq); @@ -226,11 +188,6 @@ void cx25840_audio_set_path(struct i2c_client *client) /* deassert soft reset */ cx25840_and_or(client, 0x810, ~0x1, 0x00); - - if (state->is_cx23885) { - /* Ensure the controller is running when we exit */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); - } } static int get_volume(struct i2c_client *client) diff --git a/trunk/drivers/media/video/cx25840/cx25840-core.c b/trunk/drivers/media/video/cx25840/cx25840-core.c index 756a1eeb274e..15f191e170d2 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-core.c +++ b/trunk/drivers/media/video/cx25840/cx25840-core.c @@ -13,8 +13,6 @@ * NTSC sliced VBI support by Christopher Neufeld * with additional fixes by Hans Verkuil . * - * CX23885 support by Steven Toth . - * * 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 @@ -39,7 +37,6 @@ #include #include #include -#include #include #include "cx25840-core.h" @@ -75,10 +72,10 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) u8 buffer[6]; buffer[0] = addr >> 8; buffer[1] = addr & 0xff; - buffer[2] = value & 0xff; - buffer[3] = (value >> 8) & 0xff; - buffer[4] = (value >> 16) & 0xff; - buffer[5] = value >> 24; + buffer[2] = value >> 24; + buffer[3] = (value >> 16) & 0xff; + buffer[4] = (value >> 8) & 0xff; + buffer[5] = value & 0xff; return i2c_master_send(client, buffer, 6); } @@ -125,6 +122,8 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, enum cx25840_audio_input aud_input); +static void log_audio_status(struct i2c_client *client); +static void log_video_status(struct i2c_client *client); /* ----------------------------------------------------------------------- */ @@ -257,96 +256,6 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_and_or(client, 0x803, ~0x10, 0x10); } -static void cx23885_initialize(struct i2c_client *client) -{ - DEFINE_WAIT(wait); - struct cx25840_state *state = i2c_get_clientdata(client); - struct workqueue_struct *q; - - /* Internal Reset */ - cx25840_and_or(client, 0x102, ~0x01, 0x01); - cx25840_and_or(client, 0x102, ~0x01, 0x00); - - /* Stop microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x00); - - /* DIF in reset? */ - cx25840_write(client, 0x398, 0); - - /* Trust the default xtal, no division */ - /* This changes for the cx23888 products */ - cx25840_write(client, 0x2, 0x76); - - /* Bring down the regulator for AUX clk */ - cx25840_write(client, 0x1, 0x40); - - /* Sys PLL frac */ - cx25840_write4(client, 0x11c, 0x01d1744c); - - /* Sys PLL int */ - cx25840_write4(client, 0x118, 0x00000416); - - /* Disable DIF bypass */ - cx25840_write4(client, 0x33c, 0x00000001); - - /* DIF Src phase inc */ - cx25840_write4(client, 0x340, 0x0df7df83); - - /* Vid PLL frac */ - cx25840_write4(client, 0x10c, 0x01b6db7b); - - /* Vid PLL int */ - cx25840_write4(client, 0x108, 0x00000512); - - /* Luma */ - cx25840_write4(client, 0x414, 0x00107d12); - - /* Chroma */ - cx25840_write4(client, 0x420, 0x3d008282); - - /* Aux PLL frac */ - cx25840_write4(client, 0x114, 0x017dbf48); - - /* Aux PLL int */ - cx25840_write4(client, 0x110, 0x000a030e); - - /* ADC2 input select */ - cx25840_write(client, 0x102, 0x10); - - /* VIN1 & VIN5 */ - cx25840_write(client, 0x103, 0x11); - - /* Enable format auto detect */ - cx25840_write(client, 0x400, 0); - /* Fast subchroma lock */ - /* White crush, Chroma AGC & Chroma Killer enabled */ - cx25840_write(client, 0x401, 0xe8); - - /* Select AFE clock pad output source */ - cx25840_write(client, 0x144, 0x05); - - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ - INIT_WORK(&state->fw_work, cx25840_work_handler); - init_waitqueue_head(&state->fw_wait); - q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); - - cx25840_vbi_setup(client); - - /* (re)set input */ - set_input(client, state->vid_input, state->aud_input); - - /* start microcontroller */ - cx25840_and_or(client, 0x803, ~0x10, 0x10); -} - /* ----------------------------------------------------------------------- */ static void input_change(struct i2c_client *client) @@ -410,22 +319,9 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input <= CX25840_COMPOSITE8); u8 reg; - v4l_dbg(1, cx25840_debug, client, - "decoder set video input %d, audio input %d\n", - vid_input, aud_input); - - if (vid_input >= CX25840_VIN1_CH1) { - v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", - vid_input); - reg = vid_input & 0xff; - if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON) - is_composite = 0; - else - is_composite = 1; + v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n", + vid_input, aud_input); - v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", - reg, is_composite); - } else if (is_composite) { reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); } else { @@ -435,8 +331,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp if ((vid_input & ~0xff0) || luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { - v4l_err(client, "0x%04x is not a valid video input!\n", - vid_input); + v4l_err(client, "0x%04x is not a valid video input!\n", vid_input); return -EINVAL; } reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); @@ -449,49 +344,31 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp } } - /* The caller has previously prepared the correct routing - * configuration in reg (for the cx23885) so we have no - * need to attempt to flip bits for earlier av decoders. - */ - if (!state->is_cx23885) { - switch (aud_input) { - case CX25840_AUDIO_SERIAL: - /* do nothing, use serial audio input */ - break; - case CX25840_AUDIO4: reg &= ~0x30; break; - case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; - case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; - case CX25840_AUDIO7: reg &= ~0xc0; break; - case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + switch (aud_input) { + case CX25840_AUDIO_SERIAL: + /* do nothing, use serial audio input */ + break; + case CX25840_AUDIO4: reg &= ~0x30; break; + case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX25840_AUDIO7: reg &= ~0xc0; break; + case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; - default: - v4l_err(client, "0x%04x is not a valid audio input!\n", - aud_input); - return -EINVAL; - } + default: + v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input); + return -EINVAL; } cx25840_write(client, 0x103, reg); - /* Set INPUT_MODE to Composite (0) or S-Video (1) */ cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); - - if (!state->is_cx23885) { - /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); - /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ - if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) - cx25840_and_or(client, 0x102, ~0x4, 4); - else - cx25840_and_or(client, 0x102, ~0x4, 0); - } else { - if (is_composite) - /* ADC2 input select channel 2 */ - cx25840_and_or(client, 0x102, ~0x2, 0); - else - /* ADC2 input select channel 3 */ - cx25840_and_or(client, 0x102, ~0x2, 2); - } + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx25840_and_or(client, 0x102, ~0x4, 4); + else + cx25840_and_or(client, 0x102, ~0x4, 0); state->vid_input = vid_input; state->aud_input = aud_input; @@ -499,25 +376,6 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_audio_set_path(client); input_change(client); } - - if (state->is_cx23885) { - /* Audio channel 1 src : Parallel 1 */ - cx25840_write(client, 0x124, 0x03); - - /* Select AFE clock pad output source */ - cx25840_write(client, 0x144, 0x05); - - /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ - cx25840_write(client, 0x914, 0xa0); - - /* I2S_OUT_CTL: - * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 - * I2S_OUT_MASTER_MODE = Master - */ - cx25840_write(client, 0x918, 0xa0); - cx25840_write(client, 0x919, 0x01); - } - return 0; } @@ -783,200 +641,6 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) /* ----------------------------------------------------------------------- */ -static void log_video_status(struct i2c_client *client) -{ - static const char *const fmt_strs[] = { - "0x0", - "NTSC-M", "NTSC-J", "NTSC-4.43", - "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", - "0x9", "0xA", "0xB", - "SECAM", - "0xD", "0xE", "0xF" - }; - - struct cx25840_state *state = i2c_get_clientdata(client); - u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; - u8 gen_stat1 = cx25840_read(client, 0x40d); - u8 gen_stat2 = cx25840_read(client, 0x40e); - int vid_input = state->vid_input; - - v4l_info(client, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); - v4l_info(client, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); - - v4l_info(client, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); - - if (vid_input >= CX25840_COMPOSITE1 && - vid_input <= CX25840_COMPOSITE8) { - v4l_info(client, "Specified video input: Composite %d\n", - vid_input - CX25840_COMPOSITE1 + 1); - } else { - v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); - } - - v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); -} - -/* ----------------------------------------------------------------------- */ - -static void log_audio_status(struct i2c_client *client) -{ - struct cx25840_state *state = i2c_get_clientdata(client); - u8 download_ctl = cx25840_read(client, 0x803); - u8 mod_det_stat0 = cx25840_read(client, 0x804); - u8 mod_det_stat1 = cx25840_read(client, 0x805); - u8 audio_config = cx25840_read(client, 0x808); - u8 pref_mode = cx25840_read(client, 0x809); - u8 afc0 = cx25840_read(client, 0x80b); - u8 mute_ctl = cx25840_read(client, 0x8d3); - int aud_input = state->aud_input; - char *p; - - switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio mode: %s\n", p); - - switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "high-deviation FM"; break; - case 0x11: p = "very high-deviation FM"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio standard: %s\n", p); - v4l_info(client, "Audio muted: %s\n", - (state->unmute_volume >= 0) ? "yes" : "no"); - v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? - ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); - - switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio standard: %s\n", p); - - if ((audio_config >> 4) < 0xF) { - switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AB)"; break; - case 0x06: p = "DUAL2 (AC) (FM)"; break; - case 0x07: p = "DUAL3 (BC) (FM)"; break; - case 0x08: p = "DUAL4 (AC) (AM)"; break; - case 0x09: p = "DUAL5 (BC) (AM)"; break; - case 0x0a: p = "SAP"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio mode: %s\n", p); - } else { - switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio system: %s\n", p); - } - - if (aud_input) { - v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); - } else { - v4l_info(client, "Specified audio input: External\n"); - } - - switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; - } - v4l_info(client, "Preferred audio mode: %s\n", p); - - if ((audio_config & 0xf) == 0xf) { - switch ((afc0 >> 3) & 0x3) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - case 2: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 65 MHz format: %s\n", p); - - switch (afc0 & 0x7) { - case 0: p = "chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 45 MHz format: %s\n", p); - } -} - -/* ----------------------------------------------------------------------- */ - static int cx25840_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -996,8 +660,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, state->is_initialized = 1; if (state->is_cx25836) cx25836_initialize(client); - else if (state->is_cx23885) - cx23885_initialize(client); else cx25840_initialize(client); } @@ -1015,7 +677,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) reg->val = cx25840_read(client, reg->reg & 0x0fff); else @@ -1032,26 +693,14 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_STREAMON: v4l_dbg(1, cx25840_debug, client, "enable output\n"); - if (state->is_cx23885) { - u8 v = (cx25840_read(client, 0x421) | 0x0b); - cx25840_write(client, 0x421, v); - } else { - cx25840_write(client, 0x115, - state->is_cx25836 ? 0x0c : 0x8c); - cx25840_write(client, 0x116, - state->is_cx25836 ? 0x04 : 0x07); - } + cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c); + cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07); break; case VIDIOC_STREAMOFF: v4l_dbg(1, cx25840_debug, client, "disable output\n"); - if (state->is_cx23885) { - u8 v = cx25840_read(client, 0x421) & ~(0x0b); - cx25840_write(client, 0x421, v); - } else { - cx25840_write(client, 0x115, 0x00); - cx25840_write(client, 0x116, 0x00); - } + cx25840_write(client, 0x115, 0x00); + cx25840_write(client, 0x116, 0x00); break; case VIDIOC_LOG_STATUS: @@ -1214,8 +863,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_INT_RESET: if (state->is_cx25836) cx25836_initialize(client); - else if (state->is_cx23885) - cx23885_initialize(client); else cx25840_initialize(client); break; @@ -1232,21 +879,35 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -static int cx25840_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver_cx25840; + +static int cx25840_detect_client(struct i2c_adapter *adapter, int address, + int kind) { + struct i2c_client *client; struct cx25840_state *state; u32 id; u16 device_id; - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + /* Check if the adapter supports the needed features + * Not until kernel version 2.6.11 did the bit-algo + * correctly report that it would do an I2C-level xfer */ + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver_cx25840; + snprintf(client->name, sizeof(client->name) - 1, "cx25840"); v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); - v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); /* The high byte of the device ID should be * 0x83 for the cx2583x and 0x84 for the cx2584x */ @@ -1255,18 +916,16 @@ static int cx25840_probe(struct i2c_client *client) } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); - } else if (device_id == 0x0000) { - id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; - } else if (device_id == 0x1313) { - id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - return -ENODEV; + kfree(client); + return 0; } state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); if (state == NULL) { + kfree(client); return -ENOMEM; } @@ -1280,7 +939,6 @@ static int cx25840_probe(struct i2c_client *client) i2c_set_clientdata(client, state); state->c = client; state->is_cx25836 = ((device_id & 0xff00) == 0x8300); - state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; @@ -1291,19 +949,250 @@ static int cx25840_probe(struct i2c_client *client) state->id = id; state->rev = device_id; + i2c_attach_client(client); + + return 0; +} + +static int cx25840_attach_adapter(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, &cx25840_detect_client); return 0; } -static int cx25840_remove(struct i2c_client *client) +static int cx25840_detach_client(struct i2c_client *client) { - kfree(i2c_get_clientdata(client)); + struct cx25840_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + + kfree(state); + kfree(client); + return 0; } -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "cx25840", - .driverid = I2C_DRIVERID_CX25840, +/* ----------------------------------------------------------------------- */ + +static struct i2c_driver i2c_driver_cx25840 = { + .driver = { + .name = "cx25840", + }, + .id = I2C_DRIVERID_CX25840, + .attach_adapter = cx25840_attach_adapter, + .detach_client = cx25840_detach_client, .command = cx25840_command, - .probe = cx25840_probe, - .remove = cx25840_remove, }; + + +static int __init m__init(void) +{ + return i2c_add_driver(&i2c_driver_cx25840); +} + +static void __exit m__exit(void) +{ + i2c_del_driver(&i2c_driver_cx25840); +} + +module_init(m__init); +module_exit(m__exit); + +/* ----------------------------------------------------------------------- */ + +static void log_video_status(struct i2c_client *client) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx25840_state *state = i2c_get_clientdata(client); + u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; + u8 gen_stat1 = cx25840_read(client, 0x40d); + u8 gen_stat2 = cx25840_read(client, 0x40e); + int vid_input = state->vid_input; + + v4l_info(client, "Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + v4l_info(client, "Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + v4l_info(client, "Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8) { + v4l_info(client, "Specified video input: Composite %d\n", + vid_input - CX25840_COMPOSITE1 + 1); + } else { + v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct i2c_client *client) +{ + struct cx25840_state *state = i2c_get_clientdata(client); + u8 download_ctl = cx25840_read(client, 0x803); + u8 mod_det_stat0 = cx25840_read(client, 0x804); + u8 mod_det_stat1 = cx25840_read(client, 0x805); + u8 audio_config = cx25840_read(client, 0x808); + u8 pref_mode = cx25840_read(client, 0x809); + u8 afc0 = cx25840_read(client, 0x80b); + u8 mute_ctl = cx25840_read(client, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "not defined"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0x0e: p = "IF FM Radio"; break; + case 0x0f: p = "BTSC"; break; + case 0x10: p = "high-deviation FM"; break; + case 0x11: p = "very high-deviation FM"; break; + case 0xfd: p = "unknown audio standard"; break; + case 0xfe: p = "forced audio standard"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio standard: %s\n", p); + v4l_info(client, "Audio muted: %s\n", + (state->unmute_volume >= 0) ? "yes" : "no"); + v4l_info(client, "Audio microcontroller: %s\n", + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "undefined"; break; + case 0x01: p = "BTSC"; break; + case 0x02: p = "EIAJ"; break; + case 0x03: p = "A2-M"; break; + case 0x04: p = "A2-BG"; break; + case 0x05: p = "A2-DK1"; break; + case 0x06: p = "A2-DK2"; break; + case 0x07: p = "A2-DK3"; break; + case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x09: p = "AM-L"; break; + case 0x0a: p = "NICAM-BG"; break; + case 0x0b: p = "NICAM-DK"; break; + case 0x0c: p = "NICAM-I"; break; + case 0x0d: p = "NICAM-L"; break; + case 0x0e: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio system: %s\n", p); + } + + if (aud_input) { + v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); + } else { + v4l_info(client, "Specified audio input: External\n"); + } + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + v4l_info(client, "Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 3) & 0x3) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + case 2: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x7) { + case 0: p = "chroma"; break; + case 1: p = "BTSC"; break; + case 2: p = "EIAJ"; break; + case 3: p = "A2-M"; break; + case 4: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 45 MHz format: %s\n", p); + } +} diff --git a/trunk/drivers/media/video/cx25840/cx25840-core.h b/trunk/drivers/media/video/cx25840/cx25840-core.h index 95093edc9186..ea669b1f084d 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-core.h +++ b/trunk/drivers/media/video/cx25840/cx25840-core.h @@ -47,7 +47,6 @@ struct cx25840_state { u32 id; u32 rev; int is_cx25836; - int is_cx23885; int is_initialized; wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ struct work_struct fw_work; /* work entry for fw load */ diff --git a/trunk/drivers/media/video/cx25840/cx25840-firmware.c b/trunk/drivers/media/video/cx25840/cx25840-firmware.c index 1ddf724a2c74..e852024a5ea3 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-firmware.c +++ b/trunk/drivers/media/video/cx25840/cx25840-firmware.c @@ -24,7 +24,6 @@ #include "cx25840-core.h" #define FWFILE "v4l-cx25840.fw" -#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw" /* * Mike Isely - The FWSEND parameter controls the @@ -93,14 +92,10 @@ static int fw_write(struct i2c_client *client, u8 * data, int size) int cx25840_loadfw(struct i2c_client *client) { - struct cx25840_state *state = i2c_get_clientdata(client); const struct firmware *fw = NULL; u8 buffer[4], *ptr; int size, send, retval; - if (state->is_cx23885) - firmware = FWFILE_CX23885; - if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { v4l_err(client, "unable to open firmware %s\n", firmware); return -EINVAL; diff --git a/trunk/drivers/media/video/cx25840/cx25840-vbi.c b/trunk/drivers/media/video/cx25840/cx25840-vbi.c index 6828f59b9d83..ced13febed89 100644 --- a/trunk/drivers/media/video/cx25840/cx25840-vbi.c +++ b/trunk/drivers/media/video/cx25840/cx25840-vbi.c @@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client) fsc/1000000,fsc%1000000); v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " - "vblank %i, vactive %i, vblank656 %i, src_dec %i, " + "vblank %i , vactive %i, vblank656 %i, src_dec %i," "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," " sc 0x%06x\n", hblank, hactive, vblank, vactive, vblank656, diff --git a/trunk/drivers/media/video/cx88/Kconfig b/trunk/drivers/media/video/cx88/Kconfig index 49d3813a9b48..ceb31d4a2512 100644 --- a/trunk/drivers/media/video/cx88/Kconfig +++ b/trunk/drivers/media/video/cx88/Kconfig @@ -8,7 +8,6 @@ config VIDEO_CX88 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR - select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO ---help--- This is a video4linux driver for Conexant 2388x based TV cards. diff --git a/trunk/drivers/media/video/cx88/cx88-alsa.c b/trunk/drivers/media/video/cx88/cx88-alsa.c index 8735227f7e47..40ffd7a5579a 100644 --- a/trunk/drivers/media/video/cx88/cx88-alsa.c +++ b/trunk/drivers/media/video/cx88/cx88-alsa.c @@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; chip->buf = buf; chip->dma_risc = dma; diff --git a/trunk/drivers/media/video/cx88/cx88-blackbird.c b/trunk/drivers/media/video/cx88/cx88-blackbird.c index a99e9d5950aa..f802b5653569 100644 --- a/trunk/drivers/media/video/cx88/cx88-blackbird.c +++ b/trunk/drivers/media/video/cx88/cx88-blackbird.c @@ -307,7 +307,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value) /* ------------------------------------------------------------------ */ -static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { struct cx8802_dev *dev = priv; unsigned long timeout; @@ -536,12 +536,11 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) dprintk(1,"Initialize codec\n"); retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ if (retval < 0) { - - dev->mpeg_active = 0; - /* ping was not successful, reset and upload firmware */ cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */ + msleep(1); cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */ + msleep(1); retval = blackbird_load_firmware(dev); if (retval < 0) return retval; @@ -563,6 +562,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) } dprintk(0, "Firmware version is 0x%08x\n", version); } + msleep(1); cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */ cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */ @@ -570,68 +570,40 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ blackbird_codec_settings(dev); + msleep(1); + /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef); + blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0); + blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */ blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, BLACKBIRD_FIELD1_SAA7115, BLACKBIRD_FIELD2_SAA7115 ); + /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */ blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - return 0; -} - -static int blackbird_start_codec(struct file *file, void *priv) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx88_core *core = dev->core; - /* start capturing to the host interface */ - u32 reg; - - int i; - int lastchange = -1; - int lastval = 0; - - for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) { - reg = cx_read(AUD_STATUS); - - dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg); - if ((reg & 0x0F) != lastval) { - lastval = reg & 0x0F; - lastchange = i; - } - msleep(100); - } - - /* unmute audio source */ - cx_clear(AUD_VOL_CTL, (1 << 6)); - - blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0); - /* initialize the video input */ blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); - /* start capturing to the host interface */ - blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE - ); + msleep(1); - dev->mpeg_active = 1; - return 0; -} + blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE); + msleep(1); + blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE); + msleep(1); -static int blackbird_stop_codec(struct cx8802_dev *dev) -{ - blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - BLACKBIRD_END_NOW, + /* start capturing to the host interface */ + /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */ + blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE ); + msleep(10); - dev->mpeg_active = 0; + blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0); return 0; } @@ -861,10 +833,6 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - - if (dev->mpeg_active) - blackbird_stop_codec(dev); - p = dev->params; err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); if (!err) { @@ -896,9 +864,10 @@ static int vidioc_s_frequency (struct file *file, void *priv, struct cx8802_dev *dev = fh->dev; struct cx88_core *core = dev->core; - if (dev->mpeg_active) - blackbird_stop_codec(dev); - + blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + BLACKBIRD_END_NOW, + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_BITS_NONE); cx88_set_freq (core,f); blackbird_initialize_codec(dev); cx88_set_scale(dev->core, dev->width, dev->height, @@ -1104,11 +1073,15 @@ static int mpeg_open(struct inode *inode, struct file *file) static int mpeg_release(struct inode *inode, struct file *file) { struct cx8802_fh *fh = file->private_data; - struct cx8802_dev *dev = fh->dev; + struct cx8802_dev *dev = NULL; struct cx8802_driver *drv = NULL; - if (dev->mpeg_active) - blackbird_stop_codec(dev); + /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */ + blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + BLACKBIRD_END_NOW, + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_BITS_NONE + ); cx8802_cancel_buffers(fh->dev); /* stop mpeg capture */ @@ -1134,10 +1107,6 @@ static ssize_t mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct cx8802_fh *fh = file->private_data; - struct cx8802_dev *dev = fh->dev; - - if (!dev->mpeg_active) - blackbird_start_codec(file, fh); return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); @@ -1313,7 +1282,6 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) core->name); host_setup(dev->core); - blackbird_initialize_codec(dev); blackbird_register_video(dev); /* initial device configuration: needed ? */ diff --git a/trunk/drivers/media/video/cx88/cx88-cards.c b/trunk/drivers/media/video/cx88/cx88-cards.c index e6b7f518c56e..a4eb6a87a761 100644 --- a/trunk/drivers/media/video/cx88/cx88-cards.c +++ b/trunk/drivers/media/video/cx88/cx88-cards.c @@ -26,7 +26,6 @@ #include #include "cx88.h" -#include "tea5767.h" static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; @@ -246,10 +245,6 @@ static const struct cx88_board cx88_boards[] = { }}, .radio = { .type = CX88_RADIO, - .vmux = 3, - .gpio0 = 0x000040bf, - .gpio1 = 0x000080c0, - .gpio2 = 0x0000ff20, }, }, [CX88_BOARD_WINFAST_DV2000] = { @@ -302,22 +297,22 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, - .audioroute = 1, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, - .audioroute = 1, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -378,7 +373,7 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? - .audioroute = 1, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, @@ -549,7 +544,7 @@ static const struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .audioroute = 1, + .extadc = 1, }}, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -672,22 +667,22 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, - .audioroute = 1, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, - .audioroute = 1, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -826,23 +821,23 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, - .audioroute = 1, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .vmux = 2, .gpio0 = 0x0000cdf3, - .audioroute = 1, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -1110,12 +1105,12 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, - .audioroute = 1, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, @@ -1340,17 +1335,17 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xe780, - .audioroute = 1, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xe780, - .audioroute = 2, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xe780, - .audioroute = 2, + .extadc = 1, }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, @@ -1375,32 +1370,6 @@ static const struct cx88_board cx88_boards[] = { .gpio0 = 0x07fa, }}, }, - [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { - .name = "Pinnacle PCTV HD 800i", - .tuner_type = TUNER_XC5000, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x04fb, - .gpio1 = 0x10ff, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x04fb, - .gpio1 = 0x10ef, - .audioroute = 1, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x04fb, - .gpio1 = 0x10ef, - .audioroute = 1, - }}, - .mpeg = CX88_MPEG_DVB, - }, }; /* ------------------------------------------------------------------ */ @@ -1710,10 +1679,6 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x1421, .subdevice = 0x0390, .card = CX88_BOARD_ADSTECH_PTV_390, - },{ - .subvendor = 0x11bd, - .subdevice = 0x0051, - .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, }, }; @@ -1880,36 +1845,6 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) } } -/* ----------------------------------------------------------------------- */ -/* Tuner callback function. Currently only needed for the Pinnacle * - * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * - * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ - -int cx88_tuner_callback(void *priv, int command, int arg) -{ - struct i2c_algo_bit_data *i2c_algo = priv; - struct cx88_core *core = i2c_algo->data; - - switch(core->boardnr) { - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - if(command == 0) { /* This is the reset command from xc5000 */ - /* Reset XC5000 tuner via SYS_RSTO_pin */ - cx_write(MO_SRST_IO, 0); - msleep(10); - cx_write(MO_SRST_IO, 1); - return 0; - } - else { - printk(KERN_ERR - "xc5000: unknown tuner callback command.\n"); - return -EINVAL; - } - break; - } - return 0; /* Should never be here */ -} -EXPORT_SYMBOL(cx88_tuner_callback); - /* ----------------------------------------------------------------------- */ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) @@ -2044,23 +1979,6 @@ static void cx88_card_setup(struct cx88_core *core) core->name, i); } break; - case CX88_BOARD_MSI_TVANYWHERE_MASTER: - { - struct v4l2_priv_tun_config tea5767_cfg; - struct tea5767_ctrl ctl; - - memset(&ctl, 0, sizeof(ctl)); - - ctl.high_cut = 1; - ctl.st_noise = 1; - ctl.deemph_75 = 1; - ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; - - tea5767_cfg.tuner = TUNER_TEA5767; - tea5767_cfg.priv = &ctl; - - cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); - } } } diff --git a/trunk/drivers/media/video/cx88/cx88-core.c b/trunk/drivers/media/video/cx88/cx88-core.c index 01e2ac98970b..62e8dd24c5f5 100644 --- a/trunk/drivers/media/video/cx88/cx88-core.c +++ b/trunk/drivers/media/video/cx88/cx88-core.c @@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + buf->vb.state = STATE_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core, do_gettimeofday(&buf->vb.ts); dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, count, buf->count); - buf->vb.state = VIDEOBUF_DONE; + buf->vb.state = STATE_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } diff --git a/trunk/drivers/media/video/cx88/cx88-dvb.c b/trunk/drivers/media/video/cx88/cx88-dvb.c index f7b41eb1bb5a..fce19caf9d04 100644 --- a/trunk/drivers/media/video/cx88/cx88-dvb.c +++ b/trunk/drivers/media/video/cx88/cx88-dvb.c @@ -40,8 +40,6 @@ #include "cx22702.h" #include "or51132.h" #include "lgdt330x.h" -#include "s5h1409.h" -#include "xc5000.h" #include "nxt200x.h" #include "cx24123.h" #include "isl6421.h" @@ -373,22 +371,6 @@ static struct cx24123_config kworld_dvbs_100_config = { .lnb_polarity = 1, }; -static struct s5h1409_config pinnacle_pctv_hd_800i_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_PARALLEL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, -}; - -static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { - .i2c_address = 0x64, - .if_khz = 5380, - .tuner_callback = cx88_tuner_callback, -}; - static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ @@ -643,21 +625,6 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - dev->dvb.frontend = dvb_attach(s5h1409_attach, - &pinnacle_pctv_hd_800i_config, - &dev->core->i2c_adap); - if (dev->dvb.frontend != NULL) { - /* tuner_config.video_dev must point to - * i2c_adap.algo_data - */ - pinnacle_pctv_hd_800i_tuner_config.priv = - dev->core->i2c_adap.algo_data; - dvb_attach(xc5000_attach, dev->dvb.frontend, - &dev->core->i2c_adap, - &pinnacle_pctv_hd_800i_tuner_config); - } - break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); diff --git a/trunk/drivers/media/video/cx88/cx88-i2c.c b/trunk/drivers/media/video/cx88/cx88-i2c.c index 566b26af523e..c8b1c50625f4 100644 --- a/trunk/drivers/media/video/cx88/cx88-i2c.c +++ b/trunk/drivers/media/video/cx88/cx88-i2c.c @@ -109,32 +109,26 @@ static int attach_inform(struct i2c_client *client) if (core->board.radio_type != UNSET) { if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - tun_setup.tuner_callback = cx88_tuner_callback; + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); } } if (core->board.tuner_type != UNSET) { if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - tun_setup.tuner_callback = cx88_tuner_callback; + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->board.tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &core->board.tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg); - } + if (core->board.tda9887_conf) + client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf); return 0; } @@ -182,7 +176,6 @@ static char *i2c_devs[128] = { [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", [ 0xc2 >> 1 ] = "tuner (analog/dvb)", - [ 0xc8 >> 1 ] = "xc5000", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/trunk/drivers/media/video/cx88/cx88-input.c b/trunk/drivers/media/video/cx88/cx88-input.c index bb0911b4d2f6..e52de3968c63 100644 --- a/trunk/drivers/media/video/cx88/cx88-input.c +++ b/trunk/drivers/media/video/cx88/cx88-input.c @@ -305,11 +305,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keycode = 0xfa; ir->polling = 50; /* ms */ break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - ir_codes = ir_codes_pinnacle_pctv_hd; - ir_type = IR_TYPE_RC5; - ir->sampling = 1; - break; } if (NULL == ir_codes) { @@ -448,7 +443,6 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_PINNACLE_PCTV_HD_800i: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) diff --git a/trunk/drivers/media/video/cx88/cx88-mpeg.c b/trunk/drivers/media/video/cx88/cx88-mpeg.c index 0aedbeaf94cd..448c67380945 100644 --- a/trunk/drivers/media/video/cx88/cx88-mpeg.c +++ b/trunk/drivers/media/video/cx88/cx88-mpeg.c @@ -102,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); cx_write(MO_PINMUX_IO, 0x00); - cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01); + cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: @@ -117,15 +117,6 @@ static int cx8802_start_dma(struct cx8802_dev *dev, break; case CX88_BOARD_HAUPPAUGE_HVR1300: break; - case CX88_BOARD_PINNACLE_PCTV_HD_800i: - /* Enable MPEG parallel IO and video signal pins */ - cx_write(MO_PINMUX_IO, 0x88); - cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4)); - dev->ts_gen_cntrl = 5; - cx_write(TS_SOP_STAT, 0); - cx_write(TS_VALERR_CNTRL, 0); - udelay(100); - break; default: cx_write(TS_SOP_STAT, 0x00); break; @@ -204,7 +195,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); cx8802_start_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] restart_queue - first active\n", @@ -215,7 +206,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(1,"[%p/%d] restart_queue - move to active\n", @@ -251,7 +242,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { buf->vb.width = dev->ts_packet_size; buf->vb.height = dev->ts_packet_count; buf->vb.size = size; @@ -263,7 +254,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, dma->sglist, buf->vb.width, buf->vb.height, 0); } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; return 0; fail: @@ -285,7 +276,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue,&cx88q->active); cx8802_start_dma(dev, cx88q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] %s - first active\n", @@ -295,7 +286,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&cx88q->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", @@ -315,7 +306,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; + buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); @@ -446,7 +437,10 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static int cx8802_init_common(struct cx8802_dev *dev) +/* ----------------------------------------------------------- */ +/* exported stuff */ + +int cx8802_init_common(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; int err; @@ -494,7 +488,7 @@ static int cx8802_init_common(struct cx8802_dev *dev) return 0; } -static void cx8802_fini_common(struct cx8802_dev *dev) +void cx8802_fini_common(struct cx8802_dev *dev) { dprintk( 2, "cx8802_fini_common\n" ); cx8802_stop_dma(dev); @@ -510,7 +504,7 @@ static void cx8802_fini_common(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) +int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -536,7 +530,7 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) return 0; } -static int cx8802_resume_common(struct pci_dev *pci_dev) +int cx8802_resume_common(struct pci_dev *pci_dev) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -880,6 +874,9 @@ EXPORT_SYMBOL(cx8802_buf_prepare); EXPORT_SYMBOL(cx8802_buf_queue); EXPORT_SYMBOL(cx8802_cancel_buffers); +EXPORT_SYMBOL(cx8802_init_common); +EXPORT_SYMBOL(cx8802_fini_common); + EXPORT_SYMBOL(cx8802_register_driver); EXPORT_SYMBOL(cx8802_unregister_driver); EXPORT_SYMBOL(cx8802_get_driver); diff --git a/trunk/drivers/media/video/cx88/cx88-vbi.c b/trunk/drivers/media/video/cx88/cx88-vbi.c index d96ecfcf393a..babb08556406 100644 --- a/trunk/drivers/media/video/cx88/cx88-vbi.c +++ b/trunk/drivers/media/video/cx88/cx88-vbi.c @@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; + buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); @@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; @@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, buf->vb.width, 0, buf->vb.height); } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; return 0; fail: @@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); cx8800_start_vbi_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] vbi_queue - first active\n", @@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", diff --git a/trunk/drivers/media/video/cx88/cx88-video.c b/trunk/drivers/media/video/cx88/cx88-video.c index 7f1931aed207..c84dafbdb991 100644 --- a/trunk/drivers/media/video/cx88/cx88-video.c +++ b/trunk/drivers/media/video/cx88/cx88-video.c @@ -392,41 +392,13 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) break; } - /* if there are audioroutes defined, we have an external - ADC to deal with audio */ - - if (INPUT(input).audioroute) { - - /* cx2388's C-ADC is connected to the tuner only. - When used with S-Video, that ADC is busy dealing with - chroma, so an external must be used for baseband audio */ - - if (INPUT(input).type != CX88_VMUX_TELEVISION && - INPUT(input).type != CX88_RADIO) { - /* "ADC mode" */ - cx_write(AUD_I2SCNTL, 0x1); + if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { + /* sets sound input from external adc */ + if (INPUT(input).extadc) cx_set(AUD_CTL, EN_I2SIN_ENABLE); - } else { - /* Normal mode */ - cx_write(AUD_I2SCNTL, 0x0); + else cx_clear(AUD_CTL, EN_I2SIN_ENABLE); - } - - /* The wm8775 module has the "2" route hardwired into - the initialization. Some boards may use different - routes for different inputs. HVR-1300 surely does */ - if (core->board.audio_chip && - core->board.audio_chip == AUDIO_CHIP_WM8775) { - struct v4l2_routing route; - - route.input = INPUT(input).audioroute; - cx88_call_i2c_clients(core, - VIDIOC_INT_S_AUDIO_ROUTING, &route); - - } - } - return 0; } EXPORT_SYMBOL(cx88_video_mux); @@ -514,7 +486,7 @@ static int restart_video_queue(struct cx8800_dev *dev, if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] restart_queue - first active\n", @@ -524,7 +496,7 @@ static int restart_video_queue(struct cx8800_dev *dev, prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] restart_queue - move to active\n", @@ -581,7 +553,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, init_buffer = 1; } - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { init_buffer = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; @@ -629,7 +601,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, fh->width, fh->height, fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; return 0; fail: @@ -653,14 +625,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (!list_empty(&q->queued)) { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = VIDEOBUF_QUEUED; + buf->vb.state = STATE_QUEUED; dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] buffer_queue - first active\n", @@ -672,7 +644,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", @@ -680,7 +652,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = VIDEOBUF_QUEUED; + buf->vb.state = STATE_QUEUED; dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } @@ -850,8 +822,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) + if (buf->vb.state == STATE_DONE || + buf->vb.state == STATE_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -1524,7 +1496,7 @@ static void cx8800_vid_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; + buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); diff --git a/trunk/drivers/media/video/cx88/cx88.h b/trunk/drivers/media/video/cx88/cx88.h index 4e823f2a539a..eb296bdecb1e 100644 --- a/trunk/drivers/media/video/cx88/cx88.h +++ b/trunk/drivers/media/video/cx88/cx88.h @@ -210,7 +210,6 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TE_DTV_250_OEM_SWANN 55 #define CX88_BOARD_HAUPPAUGE_HVR1300 56 #define CX88_BOARD_ADSTECH_PTV_390 57 -#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -229,7 +228,7 @@ struct cx88_input { enum cx88_itype type; u32 gpio0, gpio1, gpio2, gpio3; unsigned int vmux:2; - unsigned int audioroute:2; + unsigned int extadc:1; }; struct cx88_board { @@ -462,7 +461,6 @@ struct cx8802_dev { u32 mailbox; int width; int height; - unsigned char mpeg_active; /* nonzero if mpeg encoder is active */ /* mpeg params */ struct cx2341x_mpeg_params params; @@ -590,7 +588,6 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern int cx88_tuner_callback(void *dev, int command, int arg); extern int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci); extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); @@ -636,6 +633,12 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev, void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf); void cx8802_cancel_buffers(struct cx8802_dev *dev); +int cx8802_init_common(struct cx8802_dev *dev); +void cx8802_fini_common(struct cx8802_dev *dev); + +int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); +int cx8802_resume_common(struct pci_dev *pci_dev); + /* ----------------------------------------------------------- */ /* cx88-video.c*/ extern const u32 cx88_user_ctrls[]; diff --git a/trunk/drivers/media/video/em28xx/Kconfig b/trunk/drivers/media/video/em28xx/Kconfig index abbd38c1ebba..c1127802ad9c 100644 --- a/trunk/drivers/media/video/em28xx/Kconfig +++ b/trunk/drivers/media/video/em28xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_EM28XX tristate "Empia EM2800/2820/2840 USB video capture support" - depends on VIDEO_DEV && I2C && INPUT + depends on VIDEO_V4L1 && I2C && INPUT select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR @@ -11,18 +11,3 @@ config VIDEO_EM28XX To compile this driver as a module, choose M here: the module will be called em28xx - -config VIDEO_EM28XX_ALSA - depends on VIDEO_EM28XX - tristate "Empia EM28xx ALSA audio module" - ---help--- - This is an ALSA driver for some Empia 28xx based TV cards. - - This is not required for em2800/em2820/em2821 boards. However, - newer em28xx devices uses Vendor Class for audio, instead of - implementing the USB Audio Class. For those chips, this module - will enable digital audio. - - To compile this driver as a module, choose M here: the - module will be called em28xx-alsa - diff --git a/trunk/drivers/media/video/em28xx/Makefile b/trunk/drivers/media/video/em28xx/Makefile index 0924550992d0..826d0e340753 100644 --- a/trunk/drivers/media/video/em28xx/Makefile +++ b/trunk/drivers/media/video/em28xx/Makefile @@ -1,12 +1,6 @@ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ em28xx-input.o -em28xx-alsa-objs := em28xx-audio.o - obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o -obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - diff --git a/trunk/drivers/media/video/em28xx/em28xx-audio.c b/trunk/drivers/media/video/em28xx/em28xx-audio.c deleted file mode 100644 index 941357c4f3f5..000000000000 --- a/trunk/drivers/media/video/em28xx/em28xx-audio.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Empiatech em28x1 audio extension - * - * Copyright (C) 2006 Markus Rechberger - * - * Copyright (C) 2007 Mauro Carvalho Chehab - * - Port to work with the in-kernel driver - * - Several cleanups - * - * This driver is based on my previous au600 usb pstn audio driver - * and inherits all the copyrights - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "em28xx.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -#define dprintk(fmt, arg...) do { \ - if (debug) \ - printk(KERN_INFO "em28xx-audio %s: " fmt, \ - __FUNCTION__, ##arg); \ - } while (0) - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; - -static int em28xx_isoc_audio_deinit(struct em28xx *dev) -{ - int i; - - dprintk("Stopping isoc\n"); - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_kill_urb(dev->adev->urb[i]); - usb_free_urb(dev->adev->urb[i]); - dev->adev->urb[i] = NULL; - } - - return 0; -} - -static void em28xx_audio_isocirq(struct urb *urb) -{ - struct em28xx *dev = urb->context; - int i; - unsigned int oldptr; - unsigned long flags; - int period_elapsed = 0; - int status; - unsigned char *cp; - unsigned int stride; - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - if (dev->adev->capture_pcm_substream) { - substream = dev->adev->capture_pcm_substream; - runtime = substream->runtime; - stride = runtime->frame_bits >> 3; - - for (i = 0; i < urb->number_of_packets; i++) { - int length = - urb->iso_frame_desc[i].actual_length / stride; - cp = (unsigned char *)urb->transfer_buffer + - urb->iso_frame_desc[i].offset; - - if (!length) - continue; - - spin_lock_irqsave(&dev->adev->slock, flags); - - oldptr = dev->adev->hwptr_done_capture; - dev->adev->hwptr_done_capture += length; - if (dev->adev->hwptr_done_capture >= - runtime->buffer_size) - dev->adev->hwptr_done_capture -= - runtime->buffer_size; - - dev->adev->capture_transfer_done += length; - if (dev->adev->capture_transfer_done >= - runtime->period_size) { - dev->adev->capture_transfer_done -= - runtime->period_size; - period_elapsed = 1; - } - - spin_unlock_irqrestore(&dev->adev->slock, flags); - - if (oldptr + length >= runtime->buffer_size) { - unsigned int cnt = - runtime->buffer_size - oldptr - 1; - memcpy(runtime->dma_area + oldptr * stride, cp, - cnt * stride); - memcpy(runtime->dma_area, cp + cnt, - length * stride - cnt * stride); - } else { - memcpy(runtime->dma_area + oldptr * stride, cp, - length * stride); - } - } - if (period_elapsed) - snd_pcm_period_elapsed(substream); - } - urb->status = 0; - - if (dev->adev->shutdown) - return; - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - em28xx_errdev("resubmit of audio urb failed (error=%i)\n", - status); - } - return; -} - -static int em28xx_init_audio_isoc(struct em28xx *dev) -{ - int i, errCode; - const int sb_size = EM28XX_NUM_AUDIO_PACKETS * - EM28XX_AUDIO_MAX_PACKET_SIZE; - - dprintk("Starting isoc transfers\n"); - - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - struct urb *urb; - int j, k; - - dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev->transfer_buffer[i]) - return -ENOMEM; - - memset(dev->adev->transfer_buffer[i], 0x80, sb_size); - urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->adev->transfer_buffer[i]; - urb->interval = 1; - urb->complete = em28xx_audio_isocirq; - urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; - urb->transfer_buffer_length = sb_size; - - for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; - j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - EM28XX_AUDIO_MAX_PACKET_SIZE; - } - dev->adev->urb[i] = urb; - } - - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC); - if (errCode) { - em28xx_isoc_audio_deinit(dev); - - return errCode; - } - } - - return 0; -} - -static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) -{ - dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)? - "stop" : "start"); - - switch (cmd) { - case EM28XX_CAPTURE_STREAM_EN: - if (dev->adev->capture_stream == STREAM_OFF && arg == 1) { - dev->adev->capture_stream = STREAM_ON; - em28xx_init_audio_isoc(dev); - } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) { - dev->adev->capture_stream = STREAM_OFF; - em28xx_isoc_audio_deinit(dev); - } else { - printk(KERN_ERR "An underrun very likely occurred. " - "Ignoring it.\n"); - } - return 0; - default: - return -EINVAL; - } -} - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - dprintk("Alocating vbuffer\n"); - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - - runtime->dma_bytes = size; - - return 0; -} - -static struct snd_pcm_hardware snd_em28xx_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, - - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, /* 12544/2, */ - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98, /* 12544, */ -}; - -static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int ret = 0; - - dprintk("opening device and trying to acquire exclusive lock\n"); - - /* Sets volume, mute, etc */ - dev->mute = 0; - ret = em28xx_audio_analog_set(dev); - if (ret < 0) - goto err; - - runtime->hw = snd_em28xx_hw_capture; - if (dev->alt == 0 && dev->adev->users == 0) { - int errCode; - dev->alt = 7; - errCode = usb_set_interface(dev->udev, 0, 7); - dprintk("changing alternate number to 7\n"); - } - - dev->adev->users++; - - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - dev->adev->capture_pcm_substream = substream; - runtime->private_data = dev; - - return 0; -err: - printk(KERN_ERR "Error while configuring em28xx mixer\n"); - return ret; -} - -static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - dev->adev->users--; - - dprintk("closing device\n"); - - dev->mute = 1; - em28xx_audio_analog_set(dev); - - if (dev->adev->users == 0 && dev->adev->shutdown == 1) { - dprintk("audio users: %d\n", dev->adev->users); - dprintk("disabling audio stream!\n"); - dev->adev->shutdown = 0; - dprintk("released lock\n"); - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); - } - return 0; -} - -static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - unsigned int channels, rate, format; - int ret; - - dprintk("Setting capture parameters\n"); - - ret = snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - format = params_format(hw_params); - rate = params_rate(hw_params); - channels = params_channels(hw_params); - - /* TODO: set up em28xx audio chip to deliver the correct audio format, - current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono */ - return 0; -} - -static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - - dprintk("Stop capture, if needed\n"); - - if (dev->adev->capture_stream == STREAM_ON) - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); - - return 0; -} - -static int snd_em28xx_prepare(struct snd_pcm_substream *substream) -{ - return 0; -} - -static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - - dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)? - "start": "stop"); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1); - return 0; - case SNDRV_PCM_TRIGGER_STOP: - dev->adev->shutdown = 1; - return 0; - default: - return -EINVAL; - } -} - -static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream - *substream) -{ - struct em28xx *dev; - - snd_pcm_uframes_t hwptr_done; - dev = snd_pcm_substream_chip(substream); - hwptr_done = dev->adev->hwptr_done_capture; - - return hwptr_done; -} - -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - - return vmalloc_to_page(pageptr); -} - -static struct snd_pcm_ops snd_em28xx_pcm_capture = { - .open = snd_em28xx_capture_open, - .close = snd_em28xx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_em28xx_hw_capture_params, - .hw_free = snd_em28xx_hw_capture_free, - .prepare = snd_em28xx_prepare, - .trigger = snd_em28xx_capture_trigger, - .pointer = snd_em28xx_capture_pointer, - .page = snd_pcm_get_vmalloc_page, -}; - -static int em28xx_audio_init(struct em28xx *dev) -{ - struct em28xx_audio *adev; - struct snd_pcm *pcm; - struct snd_card *card; - static int devnr; - int ret, err; - - printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " - "non standard usbaudio\n"); - printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " - "Rechberger\n"); - - adev = kzalloc(sizeof(*adev), GFP_KERNEL); - if (!adev) { - printk(KERN_ERR "em28xx-audio.c: out of memory\n"); - return -1; - } - card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0); - if (card == NULL) { - kfree(adev); - return -ENOMEM; - } - - spin_lock_init(&adev->slock); - ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); - pcm->info_flags = 0; - pcm->private_data = dev; - strcpy(pcm->name, "Empia 28xx Capture"); - strcpy(card->driver, "Empia Em28xx Audio"); - strcpy(card->shortname, "Em28xx Audio"); - strcpy(card->longname, "Empia Em28xx Audio"); - - err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return -ENOMEM; - } - adev->sndcard = card; - adev->udev = dev->udev; - dev->adev = adev; - - return 0; -} - -static int em28xx_audio_fini(struct em28xx *dev) -{ - if (dev == NULL) - return 0; - - if (dev->adev) { - snd_card_free(dev->adev->sndcard); - kfree(dev->adev); - dev->adev = NULL; - } - - return 0; -} - -static struct em28xx_ops audio_ops = { - .id = EM28XX_AUDIO, - .name = "Em28xx Audio Extension", - .init = em28xx_audio_init, - .fini = em28xx_audio_fini, -}; - -static int __init em28xx_alsa_register(void) -{ - return em28xx_register_extension(&audio_ops); -} - -static void __exit em28xx_alsa_unregister(void) -{ - em28xx_unregister_extension(&audio_ops); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Markus Rechberger "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_DESCRIPTION("Em28xx Audio driver"); - -module_init(em28xx_alsa_register); -module_exit(em28xx_alsa_unregister); diff --git a/trunk/drivers/media/video/em28xx/em28xx-cards.c b/trunk/drivers/media/video/em28xx/em28xx-cards.c index 2159d0160df2..418ea8b7f85a 100644 --- a/trunk/drivers/media/video/em28xx/em28xx-cards.c +++ b/trunk/drivers/media/video/em28xx/em28xx-cards.c @@ -1,6 +1,5 @@ /* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices + em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices Copyright (C) 2005 Ludovico Cavedon Markus Rechberger @@ -36,735 +35,294 @@ #include #include "em28xx.h" -#include "tuner-xc2028.h" - -static int tuner = -1; -module_param(tuner, int, 0444); -MODULE_PARM_DESC(tuner, "tuner type"); - -static unsigned int disable_ir; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); - -struct em28xx_hash_table { - unsigned long hash; - unsigned int model; - unsigned int tuner; -}; - -/* Boards supported by driver */ - -#define EM2800_BOARD_UNKNOWN 0 -#define EM2820_BOARD_UNKNOWN 1 -#define EM2820_BOARD_TERRATEC_CINERGY_250 2 -#define EM2820_BOARD_PINNACLE_USB_2 3 -#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 -#define EM2820_BOARD_MSI_VOX_USB_2 5 -#define EM2800_BOARD_TERRATEC_CINERGY_200 6 -#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 -#define EM2800_BOARD_KWORLD_USB2800 8 -#define EM2820_BOARD_PINNACLE_DVC_90 9 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 -#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 -#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 -#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 -#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 -#define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", .is_em2800 = 1, .vchannels = 2, + .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = { { + .input = {{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, [EM2820_BOARD_UNKNOWN] = { - .name = "Unknown EM2750/28xx video grabber", + .name = "Unknown EM2820/2840 video grabber", .is_em2800 = 0, - .tuner_type = TUNER_ABSENT, + .vchannels = 2, + .norm = VIDEO_MODE_PAL, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .input = {{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + }}, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", .is_em2800 = 0, .vchannels = 2, - .tuner_type = TUNER_TEMIC_PAL, + .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = { { + .input = {{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, [EM2820_BOARD_TERRATEC_CINERGY_250] = { .name = "Terratec Cinergy 250 USB", .vchannels = 3, + .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = { { + .input = {{ .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, [EM2820_BOARD_PINNACLE_USB_2] = { .name = "Pinnacle PCTV USB 2", .vchannels = 3, + .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = { { + .input = {{ .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - }, { + },{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { .name = "Hauppauge WinTV USB 2", .vchannels = 3, + .norm = VIDEO_MODE_NTSC, .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE| - TDA9887_PORT2_ACTIVE, + .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, + .has_tuner = 1, .decoder = EM28XX_TVP5150, .has_msp34xx = 1, /*FIXME: S-Video not tested */ - .input = { { + .input = {{ .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = MSP_INPUT_DEFAULT, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), - } }, - }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { - .name = "Hauppauge WinTV HVR 900", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { - .name = "Hauppauge WinTV HVR 950", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - - /* gpio's 4, 1, 0 */ - .analog_gpio = 0x003d2d, + }}, }, - [EM2880_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Hybrid XS", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - /* maybe there's a reason behind it why Terratec sells the Hybrid XS - as Prodigy XS with a different PID, let's keep it separated for now - maybe we'll need it lateron */ - [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { - .name = "Terratec Prodigy XS", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { + [EM2820_BOARD_MSI_VOX_USB_2] = { + .name = "MSI VOX USB 2.0", + .vchannels = 3, + .norm = VIDEO_MODE_PAL, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, + .has_tuner = 1, + .decoder = EM28XX_SAA7114, + .input = {{ .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, + .vmux = SAA7115_COMPOSITE4, .amux = 0, - }, { + },{ .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, + .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, - }, - [EM2820_BOARD_MSI_VOX_USB_2] = { - .name = "MSI VOX USB 2.0", - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .max_range_640_480 = 1, - - .decoder = EM28XX_SAA7114, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE4, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, + }}, }, [EM2800_BOARD_TERRATEC_CINERGY_200] = { .name = "Terratec Cinergy 200 USB", .is_em2800 = 1, .vchannels = 3, + .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = { { + .input = {{ .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - }, { + },{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { .name = "Leadtek Winfast USB II", .is_em2800 = 1, .vchannels = 3, + .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = { { + .input = {{ .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - }, { + },{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, [EM2800_BOARD_KWORLD_USB2800] = { .name = "Kworld USB2800", .is_em2800 = 1, .vchannels = 3, + .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_PHILIPS_ATSC, .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = { { + .input = {{ .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, .amux = 0, - }, { + },{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, [EM2820_BOARD_PINNACLE_DVC_90] = { - .name = "Pinnacle Dazzle DVC 90/DVC 100", - .vchannels = 3, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2800_BOARD_VGEAR_POCKETTV] = { - .name = "V-Gear PocketTV", - .is_em2800 = 1, - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { - .name = "Pixelview Prolink PlayTV USB 2.0", + .name = "Pinnacle Dazzle DVC 90", .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_YMEC_TVF_5533MF, + .norm = VIDEO_MODE_PAL, + .has_tuner = 0, .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 1, - }, { + .input = {{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - }, { + },{ .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - } }, + }}, }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ struct usb_device_id em28xx_id_table [] = { - { USB_DEVICE(0xeb1a, 0x2750), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2800), - .driver_info = EM2800_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2820), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2821), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2860), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2861), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2870), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2881), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2883), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0x0ccd, 0x0036), - .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, - { USB_DEVICE(0x2304, 0x0208), - .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, - { USB_DEVICE(0x2040, 0x4200), - .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2040, 0x4201), - .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2304, 0x0207), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x021a), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2040, 0x6500), - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, - { USB_DEVICE(0x2040, 0x6513), - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x0ccd, 0x0042), - .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0047), - .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 }, + { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, + { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, + { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { }, }; -MODULE_DEVICE_TABLE(usb, em28xx_id_table); - -/* EEPROM hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_eeprom_hash [] = { - /* P/N: SA 60002070465 Tuner: TVF7533-MF */ - {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, -}; - -/* I2C devicelist hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_i2c_hash[] = { - {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, - {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, -}; -/* Since em28xx_pre_card_setup() requires a proper dev->model, - * this won't work for boards with generic PCI IDs - */ void em28xx_pre_card_setup(struct em28xx *dev) { /* request some modules */ - switch (dev->model) { - case EM2880_BOARD_TERRATEC_PRODIGY_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - em28xx_write_regs(dev, XCLK_REG, "\x27", 1); - em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1); - em28xx_write_regs(dev, 0x08, "\xff", 1); - em28xx_write_regs(dev, 0x04, "\x00", 1); - msleep(100); - em28xx_write_regs(dev, 0x04, "\x08", 1); - msleep(100); - em28xx_write_regs(dev, 0x08, "\xff", 1); - msleep(50); - em28xx_write_regs(dev, 0x08, "\x2d", 1); - msleep(50); - em28xx_write_regs(dev, 0x08, "\x3d", 1); - break; - } -} - -static int em28xx_tuner_callback(void *ptr, int command, int arg) -{ - int rc = 0; - struct em28xx *dev = ptr; - - if (dev->tuner_type != TUNER_XC2028) - return 0; - - switch (command) { - case XC2028_TUNER_RESET: - { - /* GPIO and initialization codes for analog TV and radio - This code should be complemented for DTV, since reset - codes are different. - */ - - dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); - dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); - - if (dev->analog_gpio) { - char gpio0 = dev->analog_gpio & 0xff; - char gpio1 = (dev->analog_gpio >> 8) & 0xff; - char gpio4 = dev->analog_gpio >> 24; - - if (gpio4) { - dev->em28xx_write_regs(dev, 0x04, &gpio4, 1); - msleep(140); + switch(dev->model){ + case EM2880_BOARD_TERRATEC_PRODIGY_XS: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + { + em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO? + break; } - - msleep(6); - dev->em28xx_write_regs(dev, 0x08, &gpio0, 1); - msleep(10); - dev->em28xx_write_regs(dev, 0x08, &gpio1, 1); - msleep(5); - } - - break; - } - } - return rc; -} - -static void em28xx_config_tuner(struct em28xx *dev) -{ - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - struct tuner_setup tun_setup; - struct v4l2_frequency f; - - if (dev->tuner_type == TUNER_ABSENT) - return; - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - tun_setup.tuner_callback = em28xx_tuner_callback; - - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - - if (dev->tuner_type == TUNER_XC2028) { - memset(&ctl, 0, sizeof(ctl)); - - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; - ctl.mts = em28xx_boards[dev->model].mts_firmware; - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); - } - - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* just a magic number */ - dev->ctl_freq = f.frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); -} - -static int em28xx_hint_board(struct em28xx *dev) -{ - int i; - - /* HINT method: EEPROM - * - * This method works only for boards with eeprom. - * Uses a hash of all eeprom bytes. The hash should be - * unique for a vendor/tuner pair. - * There are a high chance that tuners for different - * video standards produce different hashes. - */ - for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { - if (dev->hash == em28xx_eeprom_hash[i].hash) { - dev->model = em28xx_eeprom_hash[i].model; - dev->tuner_type = em28xx_eeprom_hash[i].tuner; - - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on eeprom hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " \n"); - em28xx_errdev("Board detected as %s\n", - em28xx_boards[dev->model].name); - - return 0; - } - } - - /* HINT method: I2C attached devices - * - * This method works for all boards. - * Uses a hash of i2c scanned devices. - * Devices with the same i2c attached chips will - * be considered equal. - * This method is less precise than the eeprom one. - */ - - /* user did not request i2c scanning => do it now */ - if (!dev->i2c_hash) - em28xx_do_i2c_scan(dev); - - for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { - if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { - dev->model = em28xx_i2c_hash[i].model; - dev->tuner_type = em28xx_i2c_hash[i].tuner; - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on i2c devicelist hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " \n"); - em28xx_errdev("Board detected as %s\n", - em28xx_boards[dev->model].name); - - return 0; - } - } - - em28xx_errdev("Your board has no unique USB ID and thus need a " - "hint to be detected.\n"); - em28xx_errdev("You may try to use card= insmod option to " - "workaround that.\n"); - em28xx_errdev("Please send an email with this log to:\n"); - em28xx_errdev("\tV4L Mailing List \n"); - em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); - em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); - - em28xx_errdev("Here is a list of valid choices for the card=" - " insmod option:\n"); - for (i = 0; i < em28xx_bcount; i++) { - em28xx_errdev(" card=%d -> %s\n", - i, em28xx_boards[i].name); - } - return -1; -} - - -static void em28xx_set_model(struct em28xx *dev) -{ - dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; - dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; - dev->decoder = em28xx_boards[dev->model].decoder; - dev->video_inputs = em28xx_boards[dev->model].vchannels; - dev->analog_gpio = em28xx_boards[dev->model].analog_gpio; - dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; - dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; -} - -/* ----------------------------------------------------------------------- */ -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) -{ - if (disable_ir) { - ir->get_key = NULL; - return ; - } - - /* detect & configure */ - switch (dev->model) { - case (EM2800_BOARD_UNKNOWN): - break; - case (EM2820_BOARD_UNKNOWN): - break; - case (EM2800_BOARD_TERRATEC_CINERGY_200): - case (EM2820_BOARD_TERRATEC_CINERGY_250): - ir->ir_codes = ir_codes_em_terratec; - ir->get_key = em28xx_get_key_terratec; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Terratec)"); - break; - case (EM2820_BOARD_PINNACLE_USB_2): - ir->ir_codes = ir_codes_pinnacle_grey; - ir->get_key = em28xx_get_key_pinnacle_usb_grey; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Pinnacle PCTV)"); - break; - case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): - ir->ir_codes = ir_codes_hauppauge_new; - ir->get_key = em28xx_get_key_em_haup; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM2840 Hauppauge)"); - break; - case (EM2820_BOARD_MSI_VOX_USB_2): - break; - case (EM2800_BOARD_LEADTEK_WINFAST_USBII): - break; - case (EM2800_BOARD_KWORLD_USB2800): - break; } } void em28xx_card_setup(struct em28xx *dev) { - em28xx_set_model(dev); - - dev->tuner_type = em28xx_boards[dev->model].tuner_type; - /* request some modules */ - switch (dev->model) { - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: - { - struct tveeprom tv; + switch(dev->model){ + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + { + struct tveeprom tv; #ifdef CONFIG_MODULES - request_module("tveeprom"); + request_module("tveeprom"); + request_module("ir-kbd-i2c"); + request_module("msp3400"); #endif - /* Call first TVeeprom */ - - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - - dev->tuner_type = tv.tuner_type; + /* Call first TVeeprom */ + + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); + + dev->tuner_type= tv.tuner_type; + if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + dev->i2s_speed=2048000; + dev->has_msp34xx=1; + } else + dev->has_msp34xx=0; + break; + } + case EM2820_BOARD_KWORLD_PVRTV2800RF: + { + em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF + break; + } - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { - dev->i2s_speed = 2048000; - dev->has_msp34xx = 1; - } -#ifdef CONFIG_MODULES - if (tv.has_ir) - request_module("ir-kbd-i2c"); -#endif - break; - } - case EM2820_BOARD_KWORLD_PVRTV2800RF: - /* GPIO enables sound on KWORLD PVR TV 2800RF */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1); - break; - case EM2820_BOARD_UNKNOWN: - case EM2800_BOARD_UNKNOWN: - if (!em28xx_hint_board(dev)) - em28xx_set_model(dev); } - - /* Allow override tuner type by a module parameter */ - if (tuner >= 0) - dev->tuner_type = tuner; - -#ifdef CONFIG_MODULES - /* request some modules */ - if (dev->has_msp34xx) - request_module("msp3400"); - if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) - request_module("saa7115"); - if (dev->decoder == EM28XX_TVP5150) - request_module("tvp5150"); - if (dev->tuner_type != TUNER_ABSENT) - request_module("tuner"); -#endif - - em28xx_config_tuner(dev); } + +MODULE_DEVICE_TABLE (usb, em28xx_id_table); diff --git a/trunk/drivers/media/video/em28xx/em28xx-core.c b/trunk/drivers/media/video/em28xx/em28xx-core.c index f6b78357f0e5..d56484f20467 100644 --- a/trunk/drivers/media/video/em28xx/em28xx-core.c +++ b/trunk/drivers/media/video/em28xx/em28xx-core.c @@ -252,7 +252,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, * em28xx_write_ac97() * write a 16 bit value to the specified AC97 address (LSB first!) */ -static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) +int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val) { int ret; u8 addr = reg & 0x7f; @@ -268,98 +268,16 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) return 0; } -int em28xx_set_audio_source(struct em28xx *dev) -{ - static char *enable = "\x08\x08"; - static char *disable = "\x08\x88"; - char *video = enable, *line = disable; - int ret, no_ac97; - u8 input; - - if (dev->is_em2800) { - if (dev->ctl_ainput) - input = EM2800_AUDIO_SRC_LINE; - else - input = EM2800_AUDIO_SRC_TUNER; - - ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1); - if (ret < 0) - return ret; - } - - if (dev->has_msp34xx) - input = EM28XX_AUDIO_SRC_TUNER; - else { - switch (dev->ctl_ainput) { - case EM28XX_AMUX_VIDEO: - input = EM28XX_AUDIO_SRC_TUNER; - no_ac97 = 1; - break; - case EM28XX_AMUX_LINE_IN: - input = EM28XX_AUDIO_SRC_LINE; - no_ac97 = 1; - break; - case EM28XX_AMUX_AC97_VIDEO: - input = EM28XX_AUDIO_SRC_LINE; - break; - case EM28XX_AMUX_AC97_LINE_IN: - input = EM28XX_AUDIO_SRC_LINE; - video = disable; - line = enable; - break; - } - } - - ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); - if (ret < 0) - return ret; - - if (no_ac97) - return 0; - - /* Sets AC97 mixer registers */ - - ret = em28xx_write_ac97(dev, VIDEO_AC97, video); - if (ret < 0) - return ret; - - ret = em28xx_write_ac97(dev, LINE_IN_AC97, line); - - return ret; -} - int em28xx_audio_analog_set(struct em28xx *dev) { - int ret; char s[2] = { 0x00, 0x00 }; - u8 xclk = 0x07; - s[0] |= 0x1f - dev->volume; s[1] |= 0x1f - dev->volume; - if (dev->mute) s[1] |= 0x80; - ret = em28xx_write_ac97(dev, MASTER_AC97, s); - if (ret < 0) - return ret; - - if (dev->has_12mhz_i2s) - xclk |= 0x20; - - if (!dev->mute) - xclk |= 0x80; - - ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7); - if (ret < 0) - return ret; - msleep(10); - - /* Selects the proper audio input */ - ret = em28xx_set_audio_source(dev); - - return ret; + return em28xx_write_ac97(dev, MASTER_AC97, s); } -EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); + int em28xx_colorlevels_set_default(struct em28xx *dev) { diff --git a/trunk/drivers/media/video/em28xx/em28xx-i2c.c b/trunk/drivers/media/video/em28xx/em28xx-i2c.c index cacd04d46e99..e3a4aa7a9df4 100644 --- a/trunk/drivers/media/video/em28xx/em28xx-i2c.c +++ b/trunk/drivers/media/video/em28xx/em28xx-i2c.c @@ -25,9 +25,9 @@ #include #include #include +#include #include "em28xx.h" -#include "tuner-xc2028.h" #include #include @@ -291,31 +291,6 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return rc; } -/* based on linux/sunrpc/svcauth.h and linux/hash.h - * The original hash function returns a different value, if arch is x86_64 - * or i386. - */ -static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) -{ - unsigned long hash = 0; - unsigned long l = 0; - int len = 0; - unsigned char c; - do { - if (len == length) { - c = (char)len; - len = -1; - } else - c = *buf++; - l = (l << 8) | c; - len++; - if ((len & (32 / 8 - 1)) == 0) - hash = ((hash^l) * 0x9e370001UL); - } while (len); - - return (hash >> (32 - bits)) & 0xffffffffUL; -} - static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) { unsigned char buf, *p = eedata; @@ -359,11 +334,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) printk("\n"); } - if (em_eeprom->id == 0x9567eb1a) - dev->hash = em28xx_hash_mem(eedata, len, 32); - - printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n", - em_eeprom->id, dev->hash); + printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id); printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, em_eeprom->product_ID); @@ -420,6 +391,21 @@ static u32 functionality(struct i2c_adapter *adap) } +static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) +{ + struct em28xx *dev = client->adapter->algo_data; + struct tuner_setup tun_setup; + + if (dev->has_tuner) { + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + } + + return (0); +} + /* * attach_inform() * gets called when a device attaches to the i2c bus @@ -435,8 +421,6 @@ static int attach_inform(struct i2c_client *client) case 0x96: case 0x94: { - struct v4l2_priv_tun_config tda9887_cfg; - struct tuner_setup tun_setup; tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; @@ -444,11 +428,7 @@ static int attach_inform(struct i2c_client *client) tun_setup.addr = client->addr; em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); + em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf); break; } case 0x42: @@ -478,11 +458,9 @@ static int attach_inform(struct i2c_client *client) break; default: - if (!dev->tuner_addr) - dev->tuner_addr = client->addr; - dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1); - + dev->tuner_addr = client->addr; + em28xx_set_tuner(-1, client); } return 0; @@ -532,26 +510,19 @@ static char *i2c_devs[128] = { * do_i2c_scan() * check i2c address range for devices */ -void em28xx_do_i2c_scan(struct em28xx *dev) +static void do_i2c_scan(char *name, struct i2c_client *c) { - u8 i2c_devicelist[128]; unsigned char buf; int i, rc; - memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - dev->i2c_client.addr = i; - rc = i2c_master_recv(&dev->i2c_client, &buf, 0); + c->addr = i; + rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; - i2c_devicelist[i] = i; - printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", - dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name, + i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } - - dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, - ARRAY_SIZE(i2c_devicelist), 32); } /* @@ -584,7 +555,7 @@ int em28xx_i2c_register(struct em28xx *dev) em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); if (i2c_scan) - em28xx_do_i2c_scan(dev); + do_i2c_scan(dev->name, &dev->i2c_client); return 0; } diff --git a/trunk/drivers/media/video/em28xx/em28xx-input.c b/trunk/drivers/media/video/em28xx/em28xx-input.c index 10da2fd8d987..e3894b68c4ee 100644 --- a/trunk/drivers/media/video/em28xx/em28xx-input.c +++ b/trunk/drivers/media/video/em28xx/em28xx-input.c @@ -30,7 +30,11 @@ #include "em28xx.h" -static unsigned int ir_debug; +static unsigned int disable_ir = 0; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir,"disable infrared remote support"); + +static unsigned int ir_debug = 0; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); @@ -39,7 +43,7 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); /* ----------------------------------------------------------------------- */ -int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -68,7 +72,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) } -int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[2]; unsigned char code; @@ -99,8 +103,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw) +static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[3]; @@ -122,6 +125,45 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, return 1; } +/* ----------------------------------------------------------------------- */ +void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir) +{ + if (disable_ir) { + ir->get_key=NULL; + return ; + } + + /* detect & configure */ + switch (dev->model) { + case (EM2800_BOARD_UNKNOWN): + break; + case (EM2820_BOARD_UNKNOWN): + break; + case (EM2800_BOARD_TERRATEC_CINERGY_200): + case (EM2820_BOARD_TERRATEC_CINERGY_250): + ir->ir_codes = ir_codes_em_terratec; + ir->get_key = get_key_terratec; + snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)"); + break; + case (EM2820_BOARD_PINNACLE_USB_2): + ir->ir_codes = ir_codes_pinnacle_grey; + ir->get_key = get_key_pinnacle_usb_grey; + snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)"); + break; + case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): + ir->ir_codes = ir_codes_hauppauge_new; + ir->get_key = get_key_em_haup; + snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)"); + break; + case (EM2820_BOARD_MSI_VOX_USB_2): + break; + case (EM2800_BOARD_LEADTEK_WINFAST_USBII): + break; + case (EM2800_BOARD_KWORLD_USB2800): + break; + } +} + /* ---------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 diff --git a/trunk/drivers/media/video/em28xx/em28xx-video.c b/trunk/drivers/media/video/em28xx/em28xx-video.c index a0c334672488..0906bc5766cc 100644 --- a/trunk/drivers/media/video/em28xx/em28xx-video.c +++ b/trunk/drivers/media/video/em28xx/em28xx-video.c @@ -33,12 +33,13 @@ #include #include #include +#include #include #include "em28xx.h" +#include #include #include -#include #define DRIVER_AUTHOR "Ludovico Cavedon , " \ "Markus Rechberger , " \ @@ -47,7 +48,7 @@ #define DRIVER_NAME "em28xx" #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0) +#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ @@ -62,17 +63,17 @@ static LIST_HEAD(em28xx_devlist); static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; - +static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); +MODULE_PARM_DESC(card,"card type"); +MODULE_PARM_DESC(video_nr,"video device numbers"); +MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); + +static int tuner = -1; +module_param(tuner, int, 0444); +MODULE_PARM_DESC(tuner, "tuner type"); static unsigned int video_debug = 0; module_param(video_debug,int,0644); @@ -81,6 +82,29 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ static unsigned long em28xx_devused; +/* supported tv norms */ +static struct em28xx_tvnorm tvnorms[] = { + { + .name = "PAL", + .id = V4L2_STD_PAL, + .mode = VIDEO_MODE_PAL, + }, { + .name = "NTSC", + .id = V4L2_STD_NTSC, + .mode = VIDEO_MODE_NTSC, + }, { + .name = "SECAM", + .id = V4L2_STD_SECAM, + .mode = VIDEO_MODE_SECAM, + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + .mode = VIDEO_MODE_PAL, + } +}; + +#define TVNORMS ARRAY_SIZE(tvnorms) + /* supported controls */ /* Common to all boards */ static struct v4l2_queryctrl em28xx_qctrl[] = { @@ -107,6 +131,8 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { static struct usb_driver em28xx_usb_driver; +static DEFINE_MUTEX(em28xx_sysfs_lock); +static DECLARE_RWSEM(em28xx_disconnect); /********************* v4l2 interface ******************************************/ @@ -127,9 +153,11 @@ static int em28xx_config(struct em28xx *dev) /* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */ em28xx_write_regs_req(dev,0x00,0x11,"\x51",1); + em28xx_audio_usb_mute(dev, 1); dev->mute = 1; /* maybe not the right place... */ dev->volume = 0x1f; - + em28xx_audio_analog_set(dev); + em28xx_audio_analog_setup(dev); em28xx_outfmt_set_yuv422(dev); em28xx_colorlevels_set_default(dev); em28xx_compression_disable(dev); @@ -143,6 +171,7 @@ static int em28xx_config(struct em28xx *dev) */ static void em28xx_config_i2c(struct em28xx *dev) { + struct v4l2_frequency f; struct v4l2_routing route; route.input = INPUT(dev->ctl_input)->vmux; @@ -150,6 +179,18 @@ static void em28xx_config_i2c(struct em28xx *dev) em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); + + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* FIXME:remove magic number */ + dev->ctl_freq = f.frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); + + /* configure tda9887 */ + + +/* em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */ } /* @@ -171,6 +212,7 @@ static void em28xx_empty_framequeues(struct em28xx *dev) static void video_mux(struct em28xx *dev, int index) { + int ainput; struct v4l2_routing route; route.input = INPUT(index)->vmux; @@ -180,6 +222,8 @@ static void video_mux(struct em28xx *dev, int index) em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); + em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput); + if (dev->has_msp34xx) { if (dev->i2s_speed) em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); @@ -187,1693 +231,1314 @@ static void video_mux(struct em28xx *dev, int index) route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); /* Note: this is msp3400 specific */ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route); + ainput = EM28XX_AUDIO_SRC_TUNER; + em28xx_audio_source(dev, ainput); + } else { + switch (dev->ctl_ainput) { + case 0: + ainput = EM28XX_AUDIO_SRC_TUNER; + break; + default: + ainput = EM28XX_AUDIO_SRC_LINE; + } + em28xx_audio_source(dev, ainput); } - - em28xx_set_audio_source(dev); } -/* Usage lock check functions */ -static int res_get(struct em28xx_fh *fh) +/* + * em28xx_v4l2_open() + * inits the device and starts isoc transfer + */ +static int em28xx_v4l2_open(struct inode *inode, struct file *filp) { - struct em28xx *dev = fh->dev; - int rc = 0; + int minor = iminor(inode); + int errCode = 0; + struct em28xx *h,*dev = NULL; + + list_for_each_entry(h, &em28xx_devlist, devlist) { + if (h->vdev->minor == minor) { + dev = h; + dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + if (h->vbi_dev->minor == minor) { + dev = h; + dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; + } + } + if (NULL == dev) + return -ENODEV; + + em28xx_videodbg("open minor=%d type=%s users=%d\n", + minor,v4l2_type_names[dev->type],dev->users); + + if (!down_read_trylock(&em28xx_disconnect)) + return -ERESTARTSYS; + + if (dev->users) { + em28xx_warn("this driver can be opened only once\n"); + up_read(&em28xx_disconnect); + return -EBUSY; + } - /* This instance already has stream_on */ - if (fh->stream_on) - return rc; + mutex_init(&dev->fileop_lock); /* to 1 == available */ + spin_lock_init(&dev->queue_lock); + init_waitqueue_head(&dev->wait_frame); + init_waitqueue_head(&dev->wait_stream); mutex_lock(&dev->lock); - if (dev->stream_on) - rc = -EINVAL; - else { - dev->stream_on = 1; - fh->stream_on = 1; + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + em28xx_set_alternate(dev); + + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ + dev->bytesperline = dev->width * 2; + dev->hscale = 0; + dev->vscale = 0; + + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); + + /* device needs to be initialized before isoc transfer */ + video_mux(dev, 0); + + /* start the transfer */ + errCode = em28xx_init_isoc(dev); + if (errCode) + goto err; + } - mutex_unlock(&dev->lock); - return rc; -} + dev->users++; + filp->private_data = dev; + dev->io = IO_NONE; + dev->stream = STREAM_OFF; + dev->num_frames = 0; -static int res_check(struct em28xx_fh *fh) -{ - return (fh->stream_on); -} + /* prepare queues */ + em28xx_empty_framequeues(dev); -static void res_free(struct em28xx_fh *fh) -{ - struct em28xx *dev = fh->dev; + dev->state |= DEV_INITIALIZED; - mutex_lock(&dev->lock); - fh->stream_on = 0; - dev->stream_on = 0; +err: mutex_unlock(&dev->lock); + up_read(&em28xx_disconnect); + return errCode; } /* - * em28xx_vm_open() - */ -static void em28xx_vm_open(struct vm_area_struct *vma) + * em28xx_realease_resources() + * unregisters the v4l2,i2c and usb devices + * called when the device gets disconected or at module unload +*/ +static void em28xx_release_resources(struct em28xx *dev) { - struct em28xx_frame_t *f = vma->vm_private_data; - f->vma_use_count++; + mutex_lock(&em28xx_sysfs_lock); + + /*FIXME: I2C IR should be disconnected */ + + em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", + dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, + dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); + list_del(&dev->devlist); + video_unregister_device(dev->vdev); + video_unregister_device(dev->vbi_dev); + em28xx_i2c_unregister(dev); + usb_put_dev(dev->udev); + mutex_unlock(&em28xx_sysfs_lock); + + + /* Mark device as unused */ + em28xx_devused&=~(1<devno); } /* - * em28xx_vm_close() + * em28xx_v4l2_close() + * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls */ -static void em28xx_vm_close(struct vm_area_struct *vma) +static int em28xx_v4l2_close(struct inode *inode, struct file *filp) { - /* NOTE: buffers are not freed here */ - struct em28xx_frame_t *f = vma->vm_private_data; + int errCode; + struct em28xx *dev=filp->private_data; - if (f->vma_use_count) - f->vma_use_count--; -} + em28xx_videodbg("users=%d\n", dev->users); -static struct vm_operations_struct em28xx_vm_ops = { - .open = em28xx_vm_open, - .close = em28xx_vm_close, -}; + mutex_lock(&dev->lock); + em28xx_uninit_isoc(dev); -/* - * em28xx_get_ctrl() - * return the current saturation, brightness or contrast, mute state - */ -static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = dev->volume; + em28xx_release_buffers(dev); + + /* the device is already disconnect, free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + em28xx_release_resources(dev); + mutex_unlock(&dev->lock); + kfree(dev); return 0; - default: - return -EINVAL; } -} -/* - * em28xx_set_ctrl() - * mute or set new saturation, brightness or contrast - */ -static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value != dev->mute) { - dev->mute = ctrl->value; - return em28xx_audio_analog_set(dev); - } - return 0; - case V4L2_CID_AUDIO_VOLUME: - dev->volume = ctrl->value; - return em28xx_audio_analog_set(dev); - default: - return -EINVAL; + /* set alternate 0 */ + dev->alt = 0; + em28xx_videodbg("setting alternate 0\n"); + errCode = usb_set_interface(dev->udev, 0, 0); + if (errCode < 0) { + em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n", + errCode); } + + dev->users--; + wake_up_interruptible_nr(&dev->open, 1); + mutex_unlock(&dev->lock); + return 0; } /* - * em28xx_stream_interrupt() - * stops streaming + * em28xx_v4l2_read() + * will allocate buffers when called for the first time */ -static int em28xx_stream_interrupt(struct em28xx *dev) +static ssize_t +em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, + loff_t * f_pos) { - int rc = 0; - - /* stop reading from the device */ - - dev->stream = STREAM_INTERRUPT; - rc = wait_event_timeout(dev->wait_stream, - (dev->stream == STREAM_OFF) || - (dev->state & DEV_DISCONNECTED), - EM28XX_URB_TIMEOUT); + struct em28xx_frame_t *f, *i; + unsigned long lock_flags; + int ret = 0; + struct em28xx *dev = filp->private_data; - if (rc) { - dev->state |= DEV_MISCONFIGURED; - em28xx_videodbg("device is misconfigured; close and " - "open /dev/video%d again\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); - return rc; + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); + } + if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { + mutex_unlock(&dev->fileop_lock); + return -EFAULT; + } + return (1); + } + if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { + mutex_unlock(&dev->fileop_lock); + return -EFAULT; + } + return (1); } - return 0; -} - + if (mutex_lock_interruptible(&dev->fileop_lock)) + return -ERESTARTSYS; -static int check_dev(struct em28xx *dev) -{ if (dev->state & DEV_DISCONNECTED) { - em28xx_errdev("v4l2 ioctl: device not present\n"); + em28xx_videodbg("device not present\n"); + mutex_unlock(&dev->fileop_lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { - em28xx_errdev("v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); + em28xx_videodbg("device misconfigured; close and open it again\n"); + mutex_unlock(&dev->fileop_lock); return -EIO; } - return 0; -} -static void get_scale(struct em28xx *dev, - unsigned int width, unsigned int height, - unsigned int *hscale, unsigned int *vscale) -{ - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); + if (dev->io == IO_MMAP) { + em28xx_videodbg ("IO method is set to mmap; close and open" + " the device again to choose the read method\n"); + mutex_unlock(&dev->fileop_lock); + return -EINVAL; + } - *hscale = (((unsigned long)maxw) << 12) / width - 4096L; - if (*hscale >= 0x4000) - *hscale = 0x3fff; + if (dev->io == IO_NONE) { + if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { + em28xx_errdev("read failed, not enough memory\n"); + mutex_unlock(&dev->fileop_lock); + return -ENOMEM; + } + dev->io = IO_READ; + dev->stream = STREAM_ON; + em28xx_queue_unusedframes(dev); + } - *vscale = (((unsigned long)maxh) << 12) / height - 4096L; - if (*vscale >= 0x4000) - *vscale = 0x3fff; -} + if (!count) { + mutex_unlock(&dev->fileop_lock); + return 0; + } -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ + if (list_empty(&dev->outqueue)) { + if (filp->f_flags & O_NONBLOCK) { + mutex_unlock(&dev->fileop_lock); + return -EAGAIN; + } + ret = wait_event_interruptible + (dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (ret) { + mutex_unlock(&dev->fileop_lock); + return ret; + } + if (dev->state & DEV_DISCONNECTED) { + mutex_unlock(&dev->fileop_lock); + return -ENODEV; + } + } -static int vidioc_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; + f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); - mutex_lock(&dev->lock); + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_for_each_entry(i, &dev->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&dev->outqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - f->fmt.pix.bytesperline = dev->bytesperline; - f->fmt.pix.sizeimage = dev->frame_size; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + em28xx_queue_unusedframes(dev); - /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - f->fmt.pix.field = dev->interlaced ? - V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; + if (count > f->buf.length) + count = f->buf.length; - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int width = f->fmt.pix.width; - int height = f->fmt.pix.height; - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); - unsigned int hscale, vscale; - - /* width must even because of the YUYV format - height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; - - if (height < 32) - height = 32; - if (height > maxh) - height = maxh; - if (width < 48) - width = 48; - if (width > maxw) - width = maxw; - - mutex_lock(&dev->lock); - - if (dev->is_em2800) { - /* the em2800 can only scale down to 50% */ - if (height % (maxh / 2)) - height = maxh; - if (width % (maxw / 2)) - width = maxw; - /* according to empiatech support */ - /* the MaxPacketSize is to small to support */ - /* framesizes larger than 640x480 @ 30 fps */ - /* or 640x576 @ 25 fps. As this would cut */ - /* of a part of the image we prefer */ - /* 360x576 or 360x480 for now */ - if (width == maxw && height == maxh) - width /= 2; - } - - get_scale(dev, width, height, &hscale, &vscale); - - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - - f->fmt.pix.width = width; - f->fmt.pix.height = height; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - f->fmt.pix.bytesperline = width * 2; - f->fmt.pix.sizeimage = width * 2 * height; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc, i; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - vidioc_try_fmt_cap(file, priv, f); - - mutex_lock(&dev->lock); - - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg("VIDIOC_S_FMT failed. " - "Unmap the buffers first.\n"); - rc = -EINVAL; - goto err; - } - - /* stop io in case it is already in progress */ - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); - rc = em28xx_stream_interrupt(dev); - if (rc < 0) - goto err; - } - - em28xx_release_buffers(dev); - dev->io = IO_NONE; - - /* set new image size */ - dev->width = f->fmt.pix.width; - dev->height = f->fmt.pix.height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; - dev->bytesperline = dev->width * 2; - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - - /* FIXME: This is really weird! Why capture is starting with - this ioctl ??? - */ - em28xx_uninit_isoc(dev); - em28xx_set_alternate(dev); - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); - em28xx_init_isoc(dev); - rc = 0; - -err: - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - struct v4l2_format f; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - dev->norm = *norm; - mutex_unlock(&dev->lock); - - /* Adjusts width/height, if needed */ - f.fmt.pix.width = dev->width; - f.fmt.pix.height = dev->height; - vidioc_try_fmt_cap(file, priv, &f); - - mutex_lock(&dev->lock); - - /* set new image size */ - dev->width = f.fmt.pix.width; - dev->height = f.fmt.pix.height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; - dev->bytesperline = dev->width * 2; - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - - em28xx_resolution_set(dev); - em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm); - - mutex_unlock(&dev->lock); - return 0; -} - -static const char *iname[] = { - [EM28XX_VMUX_COMPOSITE1] = "Composite1", - [EM28XX_VMUX_COMPOSITE2] = "Composite2", - [EM28XX_VMUX_COMPOSITE3] = "Composite3", - [EM28XX_VMUX_COMPOSITE4] = "Composite4", - [EM28XX_VMUX_SVIDEO] = "S-Video", - [EM28XX_VMUX_TELEVISION] = "Television", - [EM28XX_VMUX_CABLE] = "Cable TV", - [EM28XX_VMUX_DVB] = "DVB", - [EM28XX_VMUX_DEBUG] = "for debug only", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - - strcpy(i->name, iname[INPUT(n)->type]); - - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || - (EM28XX_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - - i->std = dev->vdev->tvnorms; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - *i = dev->ctl_input; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (i >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(i)->type) - return -EINVAL; - - mutex_lock(&dev->lock); - - video_mux(dev, i); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - unsigned int index = a->index; - - if (a->index > 1) - return -EINVAL; - - index = dev->ctl_ainput; - - if (index == 0) { - strcpy(a->name, "Television"); - } else { - strcpy(a->name, "Line In"); - } - a->capability = V4L2_AUDCAP_STEREO; - a->index = index; - - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (a->index != dev->ctl_ainput) - return -EINVAL; - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int id = qc->id; - int i; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - memset(qc, 0, sizeof(*qc)); - - qc->id = id; - - if (!dev->has_msp34xx) { - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); - return 0; - } - } - } - mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc); - mutex_unlock(&dev->lock); - - if (qc->type) - return 0; - else - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - mutex_lock(&dev->lock); - - if (!dev->has_msp34xx) - rc = em28xx_get_ctrl(dev, ctrl); - else - rc = -EINVAL; - - if (rc == -EINVAL) { - em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl); - rc = 0; - } - - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - u8 i; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - - if (dev->has_msp34xx) - em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); - else { - rc = 1; - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (ctrl->id == em28xx_qctrl[i].id) { - if (ctrl->value < em28xx_qctrl[i].minimum || - ctrl->value > em28xx_qctrl[i].maximum) { - rc = -ERANGE; - break; - } - - rc = em28xx_set_ctrl(dev, ctrl); - break; - } - } - } - - /* Control not found - try to send it to the attached devices */ - if (rc == 1) { - em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); - rc = 0; - } - - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Tuner"); - - mutex_lock(&dev->lock); - - em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; - - mutex_lock(&dev->lock); - - em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != f->tuner) - return -EINVAL; - - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - mutex_lock(&dev->lock); - - dev->ctl_freq = f->frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cc) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&dev->inqueue)) - return -EINVAL; - - mutex_lock(&dev->lock); - - if (unlikely(res_get(fh) < 0)) { - mutex_unlock(&dev->lock); - return -EBUSY; - } - - dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) - return -EINVAL; - - mutex_lock(&dev->lock); - - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n"); - rc = em28xx_stream_interrupt(dev); - if (rc < 0) { - mutex_unlock(&dev->lock); - return rc; - } - } - - em28xx_empty_framequeues(dev); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); - - cap->version = EM28XX_VERSION_CODE; - - cap->capabilities = - V4L2_CAP_SLICED_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - - if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; -} - -static int vidioc_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmtd) -{ - if (fmtd->index != 0) - return -EINVAL; - - fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmtd->description, "Packed YUY2"); - fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); - - return 0; -} - -/* Sliced VBI ioctls */ -static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - - f->fmt.sliced.service_set = 0; - - em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); - - if (f->fmt.sliced.service_set == 0) - rc = -EINVAL; - - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_try_set_vbi_capture(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); - mutex_unlock(&dev->lock); - - if (f->fmt.sliced.service_set == 0) - return -EINVAL; - - return 0; -} - - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - u32 i; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (dev->io == IO_READ) { - em28xx_videodbg("method is set to read;" - " close and open the device again to" - " choose the mmap I/O method\n"); - return -EINVAL; - } - - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg("VIDIOC_REQBUFS failed; " - "previous buffers are still mapped\n"); - return -EINVAL; - } - - mutex_lock(&dev->lock); - - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); - rc = em28xx_stream_interrupt(dev); - if (rc < 0) { - mutex_unlock(&dev->lock); - return rc; - } + if (copy_to_user(buf, f->bufmem, count)) { + mutex_unlock(&dev->fileop_lock); + return -EFAULT; } + *f_pos += count; - em28xx_empty_framequeues(dev); - - em28xx_release_buffers(dev); - if (rb->count) - rb->count = em28xx_request_buffers(dev, rb->count); - - dev->frame_current = NULL; - dev->io = rb->count ? IO_MMAP : IO_NONE; + mutex_unlock(&dev->fileop_lock); - mutex_unlock(&dev->lock); - return 0; + return count; } -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) +/* + * em28xx_v4l2_poll() + * will allocate buffers when called for the first time + */ +static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) { - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; + unsigned int mask = 0; + struct em28xx *dev = filp->private_data; - rc = check_dev(dev); - if (rc < 0) - return rc; + if (mutex_lock_interruptible(&dev->fileop_lock)) + return POLLERR; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) - return -EINVAL; + if (dev->state & DEV_DISCONNECTED) { + em28xx_videodbg("device not present\n"); + } else if (dev->state & DEV_MISCONFIGURED) { + em28xx_videodbg("device is misconfigured; close and open it again\n"); + } else { + if (dev->io == IO_NONE) { + if (!em28xx_request_buffers + (dev, EM28XX_NUM_READ_FRAMES)) { + em28xx_warn + ("poll() failed, not enough memory\n"); + } else { + dev->io = IO_READ; + dev->stream = STREAM_ON; + } + } - mutex_lock(&dev->lock); + if (dev->io == IO_READ) { + em28xx_queue_unusedframes(dev); + poll_wait(filp, &dev->wait_frame, wait); - memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); + if (!list_empty(&dev->outqueue)) + mask |= POLLIN | POLLRDNORM; - if (dev->frame[b->index].vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; + mutex_unlock(&dev->fileop_lock); - if (dev->frame[b->index].state == F_DONE) - b->flags |= V4L2_BUF_FLAG_DONE; - else if (dev->frame[b->index].state != F_UNUSED) - b->flags |= V4L2_BUF_FLAG_QUEUED; + return mask; + } + } - mutex_unlock(&dev->lock); - return 0; + mutex_unlock(&dev->fileop_lock); + return POLLERR; } -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +/* + * em28xx_vm_open() + */ +static void em28xx_vm_open(struct vm_area_struct *vma) { - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - unsigned long lock_flags; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP || - b->index >= dev->num_frames) - return -EINVAL; - - if (dev->frame[b->index].state != F_UNUSED) - return -EAGAIN; - - dev->frame[b->index].state = F_QUEUED; - - /* add frame to fifo */ - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_add_tail(&dev->frame[b->index].frame, &dev->inqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - return 0; + struct em28xx_frame_t *f = vma->vm_private_data; + f->vma_use_count++; } -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +/* + * em28xx_vm_close() + */ +static void em28xx_vm_close(struct vm_area_struct *vma) { - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - struct em28xx_frame_t *f; - unsigned long lock_flags; + /* NOTE: buffers are not freed here */ + struct em28xx_frame_t *f = vma->vm_private_data; - rc = check_dev(dev); - if (rc < 0) - return rc; + if (f->vma_use_count) + f->vma_use_count--; +} - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) - return -EINVAL; +static struct vm_operations_struct em28xx_vm_ops = { + .open = em28xx_vm_open, + .close = em28xx_vm_close, +}; - if (list_empty(&dev->outqueue)) { - if (dev->stream == STREAM_OFF) - return -EINVAL; +/* + * em28xx_v4l2_mmap() + */ +static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long size = vma->vm_end - vma->vm_start, + start = vma->vm_start; + void *pos; + u32 i; - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; + struct em28xx *dev = filp->private_data; - rc = wait_event_interruptible(dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (rc) - return rc; + if (mutex_lock_interruptible(&dev->fileop_lock)) + return -ERESTARTSYS; - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; + if (dev->state & DEV_DISCONNECTED) { + em28xx_videodbg("mmap: device not present\n"); + mutex_unlock(&dev->fileop_lock); + return -ENODEV; } - spin_lock_irqsave(&dev->queue_lock, lock_flags); - f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame); - list_del(dev->outqueue.next); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - f->state = F_UNUSED; - memcpy(b, &f->buf, sizeof(*b)); + if (dev->state & DEV_MISCONFIGURED) { + em28xx_videodbg ("mmap: Device is misconfigured; close and " + "open it again\n"); + mutex_unlock(&dev->fileop_lock); + return -EIO; + } - if (f->vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; + if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || + size != PAGE_ALIGN(dev->frame[0].buf.length)) { + mutex_unlock(&dev->fileop_lock); + return -EINVAL; + } - return 0; -} + for (i = 0; i < dev->num_frames; i++) { + if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) + break; + } + if (i == dev->num_frames) { + em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); + mutex_unlock(&dev->fileop_lock); + return -EINVAL; + } -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ + /* 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 */ -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + pos = dev->frame[i].bufmem; + while (size > 0) { /* size is page-aligned */ + if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { + em28xx_videodbg("mmap: vm_insert_page failed\n"); + mutex_unlock(&dev->fileop_lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); + vma->vm_ops = &em28xx_vm_ops; + vma->vm_private_data = &dev->frame[i]; - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; + em28xx_vm_open(vma); + mutex_unlock(&dev->fileop_lock); return 0; } -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) +/* + * em28xx_get_ctrl() + * return the current saturation, brightness or contrast, mute state + */ +static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) { - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - if (unlikely(t->index > 0)) + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->mute; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = dev->volume; + return 0; + default: return -EINVAL; - - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - return 0; + } } -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) +/* + * em28xx_set_ctrl() + * mute or set new saturation, brightness or contrast + */ +static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) { - if (i->index != 0) + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value != dev->mute) { + dev->mute = ctrl->value; + em28xx_audio_usb_mute(dev, ctrl->value); + return em28xx_audio_analog_set(dev); + } + return 0; + case V4L2_CID_AUDIO_VOLUME: + dev->volume = ctrl->value; + return em28xx_audio_analog_set(dev); + default: return -EINVAL; - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; + } } -static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +/* + * em28xx_stream_interrupt() + * stops streaming + */ +static int em28xx_stream_interrupt(struct em28xx *dev) { - if (unlikely(a->index)) - return -EINVAL; + int ret = 0; + + /* stop reading from the device */ + + dev->stream = STREAM_INTERRUPT; + ret = wait_event_timeout(dev->wait_stream, + (dev->stream == STREAM_OFF) || + (dev->state & DEV_DISCONNECTED), + EM28XX_URB_TIMEOUT); + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + else if (ret) { + dev->state |= DEV_MISCONFIGURED; + em28xx_videodbg("device is misconfigured; close and " + "open /dev/video%d again\n", + dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); + return ret; + } - strcpy(a->name, "Radio"); return 0; } -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) +static int em28xx_set_norm(struct em28xx *dev, int width, int height) { - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - if (0 != t->index) - return -EINVAL; + unsigned int hscale, vscale; + unsigned int maxh, maxw; - em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + maxw = norm_maxw(dev); + maxh = norm_maxh(dev); - return 0; -} + /* width must even because of the YUYV format */ + /* height must be even because of interlacing */ + height &= 0xfffe; + width &= 0xfffe; -static int radio_s_audio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - return 0; -} + if (height < 32) + height = 32; + if (height > maxh) + height = maxh; + if (width < 48) + width = 48; + if (width > maxw) + width = maxw; -static int radio_s_input(struct file *file, void *fh, unsigned int i) -{ - return 0; -} + if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) + hscale = 0x3fff; + width = (((unsigned long)maxw) << 12) / (hscale + 4096L); -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; + if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) + vscale = 0x3fff; + height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - if (qc->id < V4L2_CID_BASE || - qc->id >= V4L2_CID_LASTP1) - return -EINVAL; + /* set new image size */ + dev->width = width; + dev->height = height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ + dev->bytesperline = dev->width * 2; + dev->hscale = hscale; + dev->vscale = vscale; - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); - return 0; - } - } + em28xx_resolution_set(dev); - return -EINVAL; + return 0; } -/* - * em28xx_v4l2_open() - * inits the device and starts isoc transfer - */ -static int em28xx_v4l2_open(struct inode *inode, struct file *filp) +static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format) { - int minor = iminor(inode); - int errCode = 0, radio = 0; - struct em28xx *h,*dev = NULL; - struct em28xx_fh *fh; + em28xx_videodbg("VIDIOC_G_FMT: type=%s\n", + (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ? + "V4L2_BUF_TYPE_VIDEO_CAPTURE" : + (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ? + "V4L2_BUF_TYPE_VBI_CAPTURE" : + (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ? + "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " : + "not supported"); - list_for_each_entry(h, &em28xx_devlist, devlist) { - if (h->vdev->minor == minor) { - dev = h; - dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev->minor == minor) { - dev = h; - dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && - h->radio_dev->minor == minor) { - radio = 1; - dev = h; - } + switch (format->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + format->fmt.pix.width = dev->width; + format->fmt.pix.height = dev->height; + format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + format->fmt.pix.bytesperline = dev->bytesperline; + format->fmt.pix.sizeimage = dev->frame_size; + format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ + + em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width, + dev->height); + break; } - if (NULL == dev) - return -ENODEV; - em28xx_videodbg("open minor=%d type=%s users=%d\n", - minor,v4l2_type_names[dev->type],dev->users); + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + { + format->fmt.sliced.service_set=0; - fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); + em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); - if (!fh) { - em28xx_errdev("em28xx-video.c: Out of memory?!\n"); - return -ENOMEM; + if (format->fmt.sliced.service_set==0) + return -EINVAL; + + break; } - mutex_lock(&dev->lock); - fh->dev = dev; - fh->radio = radio; - filp->private_data = fh; - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - em28xx_set_alternate(dev); + default: + return -EINVAL; + } + return (0); +} - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = 0; - dev->vscale = 0; +static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format) +{ + u32 i; + int ret = 0; + int width = format->fmt.pix.width; + int height = format->fmt.pix.height; + unsigned int hscale, vscale; + unsigned int maxh, maxw; - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); + maxw = norm_maxw(dev); + maxh = norm_maxh(dev); + em28xx_videodbg("%s: type=%s\n", + cmd == VIDIOC_TRY_FMT ? + "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", + format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? + "V4L2_BUF_TYPE_VIDEO_CAPTURE" : + format->type == V4L2_BUF_TYPE_VBI_CAPTURE ? + "V4L2_BUF_TYPE_VBI_CAPTURE " : + "not supported"); - /* start the transfer */ - errCode = em28xx_init_isoc(dev); - if (errCode) - goto err; + if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); - em28xx_empty_framequeues(dev); - } - if (fh->radio) { - em28xx_videodbg("video_open: setting radio device\n"); - em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL); + if (format->fmt.sliced.service_set==0) + return -EINVAL; + + return 0; } - dev->users++; -err: - mutex_unlock(&dev->lock); - return errCode; -} + if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; -/* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -static void em28xx_release_resources(struct em28xx *dev) -{ + em28xx_videodbg("%s: requested %dx%d\n", + cmd == VIDIOC_TRY_FMT ? + "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", + format->fmt.pix.width, format->fmt.pix.height); - /*FIXME: I2C IR should be disconnected */ + /* FIXME: Move some code away from here */ + /* width must even because of the YUYV format */ + /* height must be even because of interlacing */ + height &= 0xfffe; + width &= 0xfffe; - em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, - dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); - list_del(&dev->devlist); - if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - if (dev->vbi_dev) { - if (-1 != dev->vbi_dev->minor) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->vdev) { - if (-1 != dev->vdev->minor) - video_unregister_device(dev->vdev); - else - video_device_release(dev->vdev); - dev->vdev = NULL; + if (height < 32) + height = 32; + if (height > maxh) + height = maxh; + if (width < 48) + width = 48; + if (width > maxw) + width = maxw; + + if(dev->is_em2800){ + /* the em2800 can only scale down to 50% */ + if(height % (maxh / 2)) + height=maxh; + if(width % (maxw / 2)) + width=maxw; + /* according to empiatech support */ + /* the MaxPacketSize is to small to support */ + /* framesizes larger than 640x480 @ 30 fps */ + /* or 640x576 @ 25 fps. As this would cut */ + /* of a part of the image we prefer */ + /* 360x576 or 360x480 for now */ + if(width == maxw && height == maxh) + width /= 2; } - em28xx_i2c_unregister(dev); - usb_put_dev(dev->udev); - /* Mark device as unused */ - em28xx_devused&=~(1<devno); -} + if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) + hscale = 0x3fff; -/* - * em28xx_v4l2_close() - * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls - */ -static int em28xx_v4l2_close(struct inode *inode, struct file *filp) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int errCode; + width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - em28xx_videodbg("users=%d\n", dev->users); + if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) + vscale = 0x3fff; + height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - if (res_check(fh)) - res_free(fh); + format->fmt.pix.width = width; + format->fmt.pix.height = height; + format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + format->fmt.pix.bytesperline = width * 2; + format->fmt.pix.sizeimage = width * 2 * height; + format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + format->fmt.pix.field = V4L2_FIELD_INTERLACED; - mutex_lock(&dev->lock); + em28xx_videodbg("%s: returned %dx%d (%d, %d)\n", + cmd == VIDIOC_TRY_FMT ? + "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT", + format->fmt.pix.width, format->fmt.pix.height, hscale, vscale); - if (dev->users == 1) { - em28xx_uninit_isoc(dev); - em28xx_release_buffers(dev); - dev->io = IO_NONE; + if (cmd == VIDIOC_TRY_FMT) + return 0; - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return 0; + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg("VIDIOC_S_FMT failed. " + "Unmap the buffers first.\n"); + return -EINVAL; } - /* set alternate 0 */ - dev->alt = 0; - em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); - if (errCode < 0) { - em28xx_errdev("cannot change alternate number to " - "0 (error=%i)\n", errCode); - } + /* stop io in case it is already in progress */ + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); + if ((ret = em28xx_stream_interrupt(dev))) + return ret; } - kfree(fh); - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); - mutex_unlock(&dev->lock); + + em28xx_release_buffers(dev); + dev->io = IO_NONE; + + /* set new image size */ + dev->width = width; + dev->height = height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; + dev->bytesperline = dev->width * 2; + dev->hscale = hscale; + dev->vscale = vscale; + em28xx_uninit_isoc(dev); + em28xx_set_alternate(dev); + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); + em28xx_init_isoc(dev); + return 0; } /* - * em28xx_v4l2_read() - * will allocate buffers when called for the first time + * em28xx_v4l2_do_ioctl() + * This function is _not_ called directly, but from + * em28xx_v4l2_ioctl. Userspace + * copying is done already, arg is a kernel pointer. */ -static ssize_t -em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, - loff_t * f_pos) +static int em28xx_do_ioctl(struct inode *inode, struct file *filp, + struct em28xx *dev, unsigned int cmd, void *arg, + v4l2_kioctl driver_ioctl) { - struct em28xx_frame_t *f, *i; - unsigned long lock_flags; - int ret = 0; - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; + int ret; - /* FIXME: read() is not prepared to allow changing the video - resolution while streaming. Seems a bug at em28xx_set_fmt - */ + switch (cmd) { + /* ---------- tv norms ---------- */ + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *e = arg; + unsigned int i; - if (unlikely(res_get(fh) < 0)) - return -EBUSY; + i = e->index; + if (i >= TVNORMS) + return -EINVAL; + ret = v4l2_video_std_construct(e, tvnorms[e->index].id, + tvnorms[e->index].name); + e->index = i; + if (ret < 0) + return ret; + return 0; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; - mutex_lock(&dev->lock); + *id = dev->tvnorm->id; + return 0; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + unsigned int i; - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); + for (i = 0; i < TVNORMS; i++) + if (*id == tvnorms[i].id) + break; + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) + if (*id & tvnorms[i].id) + break; + if (i == TVNORMS) + return -EINVAL; + + mutex_lock(&dev->lock); + dev->tvnorm = &tvnorms[i]; + + em28xx_set_norm(dev, dev->width, dev->height); + + em28xx_i2c_call_clients(dev, VIDIOC_S_STD, + &dev->tvnorm->id); - if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } - mutex_unlock(&dev->lock); - return (1); - } - if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); - em28xx_videodbg("not supported yet! ...\n"); - if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } mutex_unlock(&dev->lock); - return (1); + + return 0; } - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - mutex_unlock(&dev->lock); - return -ENODEV; + /* ------ input switching ---------- */ + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + unsigned int n; + static const char *iname[] = { + [EM28XX_VMUX_COMPOSITE1] = "Composite1", + [EM28XX_VMUX_COMPOSITE2] = "Composite2", + [EM28XX_VMUX_COMPOSITE3] = "Composite3", + [EM28XX_VMUX_COMPOSITE4] = "Composite4", + [EM28XX_VMUX_SVIDEO] = "S-Video", + [EM28XX_VMUX_TELEVISION] = "Television", + [EM28XX_VMUX_CABLE] = "Cable TV", + [EM28XX_VMUX_DVB] = "DVB", + [EM28XX_VMUX_DEBUG] = "for debug only", + }; + + n = i->index; + if (n >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, iname[INPUT(n)->type]); + if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || + (EM28XX_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + for (n = 0; n < ARRAY_SIZE(tvnorms); n++) + i->std |= tvnorms[n].id; + return 0; } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = dev->ctl_input; - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device misconfigured; close and open it again\n"); - mutex_unlock(&dev->lock); - return -EIO; + return 0; } + case VIDIOC_S_INPUT: + { + int *index = arg; - if (dev->io == IO_MMAP) { - em28xx_videodbg ("IO method is set to mmap; close and open" - " the device again to choose the read method\n"); + if (*index >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(*index)->type) + return -EINVAL; + + mutex_lock(&dev->lock); + video_mux(dev, *index); mutex_unlock(&dev->lock); - return -EINVAL; + + return 0; } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; + unsigned int index = a->index; - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_errdev("read failed, not enough memory\n"); - mutex_unlock(&dev->lock); - return -ENOMEM; + if (a->index > 1) + return -EINVAL; + memset(a, 0, sizeof(*a)); + index = dev->ctl_ainput; + + if (index == 0) { + strcpy(a->name, "Television"); + } else { + strcpy(a->name, "Line In"); } - dev->io = IO_READ; - dev->stream = STREAM_ON; - em28xx_queue_unusedframes(dev); + a->capability = V4L2_AUDCAP_STEREO; + a->index = index; + return 0; } + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *a = arg; + + if (a->index != dev->ctl_ainput) + return -EINVAL; - if (!count) { - mutex_unlock(&dev->lock); return 0; } - if (list_empty(&dev->outqueue)) { - if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&dev->lock); - return -EAGAIN; - } - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) { - mutex_unlock(&dev->lock); - return ret; - } - if (dev->state & DEV_DISCONNECTED) { - mutex_unlock(&dev->lock); - return -ENODEV; + /* --- controls ---------------------------------------------- */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i, id=qc->id; + + memset(qc,0,sizeof(*qc)); + qc->id=id; + + if (!dev->has_msp34xx) { + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (qc->id && qc->id == em28xx_qctrl[i].id) { + memcpy(qc, &(em28xx_qctrl[i]), + sizeof(*qc)); + return 0; + } + } } - dev->video_bytesread = 0; + em28xx_i2c_call_clients(dev,cmd,qc); + if (qc->type) + return 0; + else + return -EINVAL; } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl = arg; + int retval=-EINVAL; - f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); + if (!dev->has_msp34xx) + retval=em28xx_get_ctrl(dev, ctrl); + if (retval==-EINVAL) { + em28xx_i2c_call_clients(dev,cmd,arg); + return 0; + } else return retval; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl = arg; + u8 i; + + if (!dev->has_msp34xx){ + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (ctrl->id == em28xx_qctrl[i].id) { + if (ctrl->value < + em28xx_qctrl[i].minimum + || ctrl->value > + em28xx_qctrl[i].maximum) + return -ERANGE; + return em28xx_set_ctrl(dev, ctrl); + } + } + } - em28xx_queue_unusedframes(dev); + em28xx_i2c_call_clients(dev,cmd,arg); + return 0; + } + /* --- tuner ioctls ------------------------------------------ */ + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; - if (count > f->buf.length) - count = f->buf.length; + if (0 != t->index) + return -EINVAL; - if ((dev->video_bytesread + count) > dev->frame_size) - count = dev->frame_size - dev->video_bytesread; + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Tuner"); + mutex_lock(&dev->lock); + /* let clients fill in the remainder of this struct */ + em28xx_i2c_call_clients(dev, cmd, t); + mutex_unlock(&dev->lock); + em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, + t->afc); + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; - if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) { - em28xx_err("Error while copying to user\n"); - return -EFAULT; + if (0 != t->index) + return -EINVAL; + mutex_lock(&dev->lock); + /* let clients handle this */ + em28xx_i2c_call_clients(dev, cmd, t); + mutex_unlock(&dev->lock); + return 0; } - dev->video_bytesread += count; + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; - if (dev->video_bytesread == dev->frame_size) { - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_for_each_entry(i, &dev->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&dev->outqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + memset(f, 0, sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; - em28xx_queue_unusedframes(dev); - dev->video_bytesread = 0; + return 0; } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; - *f_pos += count; + if (0 != f->tuner) + return -EINVAL; - mutex_unlock(&dev->lock); + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; - return count; -} + mutex_lock(&dev->lock); + dev->ctl_freq = f->frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); + mutex_unlock(&dev->lock); + return 0; + } + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *cc = arg; -/* - * em28xx_v4l2_poll() - * will allocate buffers when called for the first time - */ -static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) -{ - unsigned int mask = 0; - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->width; + cc->bounds.height = dev->height; + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ + cc->pixelaspect.denominator = 59; + return 0; + } + case VIDIOC_STREAMON: + { + int *type = arg; - if (unlikely(res_get(fh) < 0)) - return POLLERR; + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || dev->io != IO_MMAP) + return -EINVAL; - mutex_lock(&dev->lock); + if (list_empty(&dev->inqueue)) + return -EINVAL; - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("device not present\n"); - } else if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg("device is misconfigured; close and open it again\n"); - } else { - if (dev->io == IO_NONE) { - if (!em28xx_request_buffers - (dev, EM28XX_NUM_READ_FRAMES)) { - em28xx_warn - ("poll() failed, not enough memory\n"); - } else { - dev->io = IO_READ; - dev->stream = STREAM_ON; - } - } + dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ - if (dev->io == IO_READ) { - em28xx_queue_unusedframes(dev); - poll_wait(filp, &dev->wait_frame, wait); + em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); - if (!list_empty(&dev->outqueue)) - mask |= POLLIN | POLLRDNORM; + return 0; + } + case VIDIOC_STREAMOFF: + { + int *type = arg; + int ret; - mutex_unlock(&dev->lock); + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || dev->io != IO_MMAP) + return -EINVAL; - return mask; + if (dev->stream == STREAM_ON) { + em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); + if ((ret = em28xx_stream_interrupt(dev))) + return ret; } - } + em28xx_empty_framequeues(dev); - mutex_unlock(&dev->lock); - return POLLERR; + return 0; + } + default: + return v4l_compat_translate_ioctl(inode, filp, cmd, arg, + driver_ioctl); + } + return 0; } /* - * em28xx_v4l2_mmap() + * em28xx_v4l2_do_ioctl() + * This function is _not_ called directly, but from + * em28xx_v4l2_ioctl. Userspace + * copying is done already, arg is a kernel pointer. */ -static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) +static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, void *arg) { - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long start = vma->vm_start; - void *pos; - u32 i; - - if (unlikely(res_get(fh) < 0)) - return -EBUSY; - - mutex_lock(&dev->lock); + struct em28xx *dev = filp->private_data; - if (dev->state & DEV_DISCONNECTED) { - em28xx_videodbg("mmap: device not present\n"); - mutex_unlock(&dev->lock); + if (!dev) return -ENODEV; - } - if (dev->state & DEV_MISCONFIGURED) { - em28xx_videodbg ("mmap: Device is misconfigured; close and " - "open it again\n"); - mutex_unlock(&dev->lock); - return -EIO; + if (video_debug > 1) + v4l_print_ioctl(dev->name,cmd); + + switch (cmd) { + + /* --- capabilities ------------------------------------------ */ + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap, 0, sizeof(*cap)); + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, + sizeof(cap->card)); + strlcpy(cap->bus_info, dev->udev->dev.bus_id, + sizeof(cap->bus_info)); + cap->version = EM28XX_VERSION_CODE; + cap->capabilities = + V4L2_CAP_SLICED_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (dev->has_tuner) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; } + /* --- capture ioctls ---------------------------------------- */ + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *fmtd = arg; - if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) { - mutex_unlock(&dev->lock); - return -EINVAL; + if (fmtd->index != 0) + return -EINVAL; + memset(fmtd, 0, sizeof(*fmtd)); + fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmtd->description, "Packed YUY2"); + fmtd->pixelformat = V4L2_PIX_FMT_YUYV; + memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); + return 0; } + case VIDIOC_G_FMT: + return em28xx_get_fmt(dev, (struct v4l2_format *) arg); - if (size > PAGE_ALIGN(dev->frame[0].buf.length)) - size = PAGE_ALIGN(dev->frame[0].buf.length); + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); - for (i = 0; i < dev->num_frames; i++) { - if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == dev->num_frames) { - em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); - mutex_unlock(&dev->lock); - return -EINVAL; - } + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *rb = arg; + u32 i; + int ret; - /* 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 */ + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; - pos = dev->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - em28xx_videodbg("mmap: vm_insert_page failed\n"); - mutex_unlock(&dev->lock); - return -EAGAIN; + if (dev->io == IO_READ) { + em28xx_videodbg ("method is set to read;" + " close and open the device again to" + " choose the mmap I/O method\n"); + return -EINVAL; } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - vma->vm_ops = &em28xx_vm_ops; - vma->vm_private_data = &dev->frame[i]; + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n"); + return -EINVAL; + } - em28xx_vm_open(vma); - mutex_unlock(&dev->lock); - return 0; -} + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); + if ((ret = em28xx_stream_interrupt(dev))) + return ret; + } -static const struct file_operations em28xx_v4l_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .read = em28xx_v4l2_read, - .poll = em28xx_v4l2_poll, - .mmap = em28xx_v4l2_mmap, - .ioctl = video_ioctl2, - .llseek = no_llseek, - .compat_ioctl = v4l_compat_ioctl32, -}; + em28xx_empty_framequeues(dev); -static const struct file_operations radio_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; + em28xx_release_buffers(dev); + if (rb->count) + rb->count = + em28xx_request_buffers(dev, rb->count); -static const struct video_device em28xx_video_template = { - .fops = &em28xx_v4l_fops, - .release = video_device_release, - - .minor = -1, - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, - .vidioc_g_fmt_cap = vidioc_g_fmt_cap, - .vidioc_try_fmt_cap = vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = vidioc_s_fmt_cap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, - - .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture, - .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture, - .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture, - - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - - .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_PAL, -}; + dev->frame_current = NULL; -static struct video_device em28xx_radio_template = { - .name = "em28xx-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -}; + em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", + rb->count); + dev->io = rb->count ? IO_MMAP : IO_NONE; + return 0; + } + case VIDIOC_QUERYBUF: + { + struct v4l2_buffer *b = arg; -/******************************** usb interface *****************************************/ + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b->index >= dev->num_frames || dev->io != IO_MMAP) + return -EINVAL; + memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); -static LIST_HEAD(em28xx_extension_devlist); -static DEFINE_MUTEX(em28xx_extension_devlist_lock); + if (dev->frame[b->index].vma_use_count) { + b->flags |= V4L2_BUF_FLAG_MAPPED; + } + if (dev->frame[b->index].state == F_DONE) + b->flags |= V4L2_BUF_FLAG_DONE; + else if (dev->frame[b->index].state != F_UNUSED) + b->flags |= V4L2_BUF_FLAG_QUEUED; + return 0; + } + case VIDIOC_QBUF: + { + struct v4l2_buffer *b = arg; + unsigned long lock_flags; -int em28xx_register_extension(struct em28xx_ops *ops) -{ - struct em28xx *h, *dev = NULL; + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b->index >= dev->num_frames || dev->io != IO_MMAP) { + return -EINVAL; + } + + if (dev->frame[b->index].state != F_UNUSED) { + return -EAGAIN; + } + dev->frame[b->index].state = F_QUEUED; - list_for_each_entry(h, &em28xx_devlist, devlist) - dev = h; + /* add frame to fifo */ + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_add_tail(&dev->frame[b->index].frame, + &dev->inqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - mutex_lock(&em28xx_extension_devlist_lock); - list_add_tail(&ops->next, &em28xx_extension_devlist); - if (dev) - ops->init(dev); + return 0; + } + case VIDIOC_DQBUF: + { + struct v4l2_buffer *b = arg; + struct em28xx_frame_t *f; + unsigned long lock_flags; + int ret = 0; - printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); - mutex_unlock(&em28xx_extension_devlist_lock); + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || dev->io != IO_MMAP) + return -EINVAL; - return 0; -} -EXPORT_SYMBOL(em28xx_register_extension); + if (list_empty(&dev->outqueue)) { + if (dev->stream == STREAM_OFF) + return -EINVAL; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible + (dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (ret) + return ret; + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + } -void em28xx_unregister_extension(struct em28xx_ops *ops) -{ - struct em28xx *h, *dev = NULL; + spin_lock_irqsave(&dev->queue_lock, lock_flags); + f = list_entry(dev->outqueue.next, + struct em28xx_frame_t, frame); + list_del(dev->outqueue.next); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - list_for_each_entry(h, &em28xx_devlist, devlist) - dev = h; + f->state = F_UNUSED; + memcpy(b, &f->buf, sizeof(*b)); - if (dev) - ops->fini(dev); + if (f->vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; - mutex_lock(&em28xx_extension_devlist_lock); - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); - list_del(&ops->next); - mutex_unlock(&em28xx_extension_devlist_lock); + return 0; + } + default: + return em28xx_do_ioctl(inode, filp, dev, cmd, arg, + em28xx_video_do_ioctl); + } + return 0; } -EXPORT_SYMBOL(em28xx_unregister_extension); -struct video_device *em28xx_vdev_init(struct em28xx *dev, - const struct video_device *template, - const int type, - const char *type_name) +/* + * em28xx_v4l2_ioctl() + * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl() + */ +static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) { - struct video_device *vfd; + int ret = 0; + struct em28xx *dev = filp->private_data; + + if (mutex_lock_interruptible(&dev->fileop_lock)) + return -ERESTARTSYS; + + if (dev->state & DEV_DISCONNECTED) { + em28xx_errdev("v4l2 ioctl: device not present\n"); + mutex_unlock(&dev->fileop_lock); + return -ENODEV; + } + + if (dev->state & DEV_MISCONFIGURED) { + em28xx_errdev + ("v4l2 ioctl: device is misconfigured; close and open it again\n"); + mutex_unlock(&dev->fileop_lock); + return -EIO; + } - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->minor = -1; - vfd->dev = &dev->udev->dev; - vfd->release = video_device_release; - vfd->type = type; + ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); - snprintf(vfd->name, sizeof(vfd->name), "%s %s", - dev->name, type_name); + mutex_unlock(&dev->fileop_lock); - return vfd; + return ret; } +static const struct file_operations em28xx_v4l_fops = { + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .ioctl = em28xx_v4l2_ioctl, + .read = em28xx_v4l2_read, + .poll = em28xx_v4l2_poll, + .mmap = em28xx_v4l2_mmap, + .llseek = no_llseek, + .compat_ioctl = v4l_compat_ioctl32, + +}; + +/******************************** usb interface *****************************************/ /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, - int minor) + int minor, int model) { - struct em28xx_ops *ops = NULL; struct em28xx *dev = *devhandle; int retval = -ENOMEM; - int errCode; + int errCode, i; unsigned int maxh, maxw; dev->udev = udev; + dev->model = model; mutex_init(&dev->lock); - spin_lock_init(&dev->queue_lock); init_waitqueue_head(&dev->open); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); dev->em28xx_write_regs = em28xx_write_regs; dev->em28xx_read_reg = em28xx_read_reg; dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; dev->em28xx_write_regs_req = em28xx_write_regs_req; dev->em28xx_read_reg_req = em28xx_read_reg_req; - dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - - errCode = em28xx_read_reg(dev, CHIPID_REG); - if (errCode >= 0) - em28xx_info("em28xx chip ID = %d\n", errCode); - - em28xx_pre_card_setup(dev); - - errCode = em28xx_config(dev); - if (errCode) { - em28xx_errdev("error configuring device\n"); - em28xx_devused &= ~(1<devno); - kfree(dev); - return -ENOMEM; - } - - /* register i2c bus */ - em28xx_i2c_register(dev); + dev->is_em2800 = em28xx_boards[model].is_em2800; + dev->has_tuner = em28xx_boards[model].has_tuner; + dev->has_msp34xx = em28xx_boards[model].has_msp34xx; + dev->tda9887_conf = em28xx_boards[model].tda9887_conf; + dev->decoder = em28xx_boards[model].decoder; + + if (tuner >= 0) + dev->tuner_type = tuner; + else + dev->tuner_type = em28xx_boards[model].tuner_type; - /* Do board specific init and eeprom reading */ - em28xx_card_setup(dev); + dev->video_inputs = em28xx_boards[model].vchannels; - /* Configure audio */ - em28xx_audio_analog_set(dev); + for (i = 0; i < TVNORMS; i++) + if (em28xx_boards[model].norm == tvnorms[i].mode) + break; + if (i == TVNORMS) + i = 0; - /* configure the device */ - em28xx_config_i2c(dev); + dev->tvnorm = &tvnorms[i]; /* set default norm */ - /* set default norm */ - dev->norm = em28xx_video_template.current_norm; + em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); maxw = norm_maxw(dev); maxh = norm_maxh(dev); @@ -1890,110 +1555,138 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vscale = 0; dev->ctl_input = 2; + /* setup video picture settings for saa7113h */ + memset(&dev->vpic, 0, sizeof(dev->vpic)); + dev->vpic.colour = 128 << 8; + dev->vpic.hue = 128 << 8; + dev->vpic.brightness = 128 << 8; + dev->vpic.contrast = 192 << 8; + dev->vpic.whiteness = 128 << 8; /* This one isn't used */ + dev->vpic.depth = 16; + dev->vpic.palette = VIDEO_PALETTE_YUV422; + + em28xx_pre_card_setup(dev); +#ifdef CONFIG_MODULES + /* request some modules */ + if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) + request_module("saa7115"); + if (dev->decoder == EM28XX_TVP5150) + request_module("tvp5150"); + if (dev->has_tuner) + request_module("tuner"); +#endif errCode = em28xx_config(dev); + if (errCode) { + em28xx_errdev("error configuring device\n"); + em28xx_devused&=~(1<devno); + kfree(dev); + return -ENOMEM; + } + + mutex_lock(&dev->lock); + /* register i2c bus */ + em28xx_i2c_register(dev); + + /* Do board specific init and eeprom reading */ + em28xx_card_setup(dev); + + /* configure the device */ + em28xx_config_i2c(dev); + + mutex_unlock(&dev->lock); - list_add_tail(&dev->devlist, &em28xx_devlist); + errCode = em28xx_config(dev); - /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, - VID_TYPE_CAPTURE, "video"); +#ifdef CONFIG_MODULES + if (dev->has_msp34xx) + request_module("msp3400"); +#endif + /* allocate and fill v4l2 device struct */ + dev->vdev = video_device_alloc(); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; + em28xx_devused&=~(1<devno); + kfree(dev); + return -ENOMEM; + } + + dev->vbi_dev = video_device_alloc(); + if (NULL == dev->vbi_dev) { + em28xx_errdev("cannot allocate video_device.\n"); + kfree(dev->vdev); + em28xx_devused&=~(1<devno); + kfree(dev); + return -ENOMEM; } - if (dev->tuner_type != TUNER_ABSENT) + + /* Fills VBI device info */ + dev->vbi_dev->type = VFL_TYPE_VBI; + dev->vbi_dev->fops = &em28xx_v4l_fops; + dev->vbi_dev->minor = -1; + dev->vbi_dev->dev = &dev->udev->dev; + dev->vbi_dev->release = video_device_release; + snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", + "em28xx",dev->devno,"vbi"); + + /* Fills CAPTURE device info */ + dev->vdev->type = VID_TYPE_CAPTURE; + if (dev->has_tuner) dev->vdev->type |= VID_TYPE_TUNER; + dev->vdev->fops = &em28xx_v4l_fops; + dev->vdev->minor = -1; + dev->vdev->dev = &dev->udev->dev; + dev->vdev->release = video_device_release; + snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", + "em28xx",dev->devno,"video"); + + list_add_tail(&dev->devlist,&em28xx_devlist); - /* register v4l2 video video_device */ - retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]); - if (retval) { + /* register v4l2 device */ + mutex_lock(&dev->lock); + if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]))) { em28xx_errdev("unable to register video device (error=%i).\n", retval); - goto fail_unreg; + mutex_unlock(&dev->lock); + list_del(&dev->devlist); + video_device_release(dev->vdev); + em28xx_devused&=~(1<devno); + kfree(dev); + return -ENODEV; } - /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, - VFL_TYPE_VBI, "vbi"); - /* register v4l2 vbi video_device */ if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]) < 0) { - em28xx_errdev("unable to register vbi device\n"); - retval = -ENODEV; - goto fail_unreg; - } - - if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, - VFL_TYPE_RADIO, "radio"); - if (NULL == dev->radio_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; - } - retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->devno]); - if (retval < 0) { - em28xx_errdev("can't register radio device\n"); - goto fail_unreg; - } - em28xx_info("Registered radio device as /dev/radio%d\n", - dev->radio_dev->minor & 0x1f); + printk("unable to register vbi device\n"); + mutex_unlock(&dev->lock); + list_del(&dev->devlist); + video_device_release(dev->vbi_dev); + video_device_release(dev->vdev); + em28xx_devused&=~(1<devno); + kfree(dev); + return -ENODEV; + } else { + printk("registered VBI\n"); } - if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); msleep(3); em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); msleep(3); - } + } video_mux(dev, 0); + mutex_unlock(&dev->lock); + em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); - mutex_lock(&em28xx_extension_devlist_lock); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->id) - ops->init(dev); - } - } - mutex_unlock(&em28xx_extension_devlist_lock); - return 0; - -fail_unreg: - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return retval; -} - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct em28xx *dev = container_of(work, - struct em28xx, request_module_wk); - - if (dev->has_audio_class) - request_module("snd-usb-audio"); - else - request_module("em28xx-alsa"); -} - -static void request_modules(struct em28xx *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); } -#else -#define request_modules(dev) -#endif /* CONFIG_MODULES */ /* * em28xx_usb_probe() @@ -2007,7 +1700,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct usb_interface *uif; struct em28xx *dev = NULL; int retval = -ENODEV; - int i, nr, ifnum; + int model,i,nr,ifnum; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; @@ -2047,6 +1740,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, return -ENODEV; } + model=id->driver_info; + if (nr >= EM28XX_MAXBOARDS) { printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); em28xx_devused&=~(1<name, 29, "em28xx #%d", nr); - dev->devno = nr; - dev->model = id->driver_info; - - /* Checks if audio is provided by some interface */ - for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { - uif = udev->config->interface[i]; - if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev->has_audio_class = 1; - break; - } - } - - printk(KERN_INFO DRIVER_NAME " %s usb audio class\n", - dev->has_audio_class ? "Has" : "Doesn't have"); + dev->devno=nr; /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; @@ -2102,20 +1784,33 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if ((card[nr]>=0)&&(card[nr]model = card[nr]; + model=card[nr]; + + if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) { + em28xx_errdev( "Your board has no eeprom inside it and thus can't\n" + "%s: be autodetected. Please pass card= insmod option to\n" + "%s: workaround that. Redirect complaints to the vendor of\n" + "%s: the TV card. Generic type will be used." + "%s: Best regards,\n" + "%s: -- tux\n", + dev->name,dev->name,dev->name,dev->name,dev->name); + em28xx_errdev("%s: Here is a list of valid choices for the card= insmod option:\n", + dev->name); + for (i = 0; i < em28xx_bcount; i++) { + em28xx_errdev(" card=%d -> %s\n", i, + em28xx_boards[i].name); + } + } /* allocate device struct */ - retval = em28xx_init_dev(&dev, udev, nr); + retval = em28xx_init_dev(&dev, udev, nr, model); if (retval) return retval; - em28xx_info("Found %s\n", em28xx_boards[dev->model].name); + em28xx_info("Found %s\n", em28xx_boards[model].name); /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); - - request_modules(dev); - return 0; } @@ -2126,20 +1821,18 @@ static int em28xx_usb_probe(struct usb_interface *interface, */ static void em28xx_usb_disconnect(struct usb_interface *interface) { - struct em28xx *dev; - struct em28xx_ops *ops = NULL; - - dev = usb_get_intfdata(interface); + struct em28xx *dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!dev) return; - em28xx_info("disconnecting %s\n", dev->vdev->name); + down_write(&em28xx_disconnect); - /* wait until all current v4l2 io is finished then deallocate resources */ mutex_lock(&dev->lock); + em28xx_info("disconnecting %s\n", dev->vdev->name); + wake_up_interruptible_all(&dev->open); if (dev->users) { @@ -2157,20 +1850,15 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) dev->state |= DEV_DISCONNECTED; em28xx_release_resources(dev); } - mutex_unlock(&dev->lock); - mutex_lock(&em28xx_extension_devlist_lock); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - ops->fini(dev); - } - } - mutex_unlock(&em28xx_extension_devlist_lock); + mutex_unlock(&dev->lock); if (!dev->users) { kfree(dev->alt_max_pkt_size); kfree(dev); } + + up_write(&em28xx_disconnect); } static struct usb_driver em28xx_usb_driver = { diff --git a/trunk/drivers/media/video/em28xx/em28xx.h b/trunk/drivers/media/video/em28xx/em28xx.h index f3bad0c1c517..d8fcc9e17ac0 100644 --- a/trunk/drivers/media/video/em28xx/em28xx.h +++ b/trunk/drivers/media/video/em28xx/em28xx.h @@ -25,11 +25,28 @@ #ifndef _EM28XX_H #define _EM28XX_H -#include +#include #include #include #include +/* Boards supported by driver */ + +#define EM2800_BOARD_UNKNOWN 0 +#define EM2820_BOARD_UNKNOWN 1 +#define EM2820_BOARD_TERRATEC_CINERGY_250 2 +#define EM2820_BOARD_PINNACLE_USB_2 3 +#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 +#define EM2820_BOARD_MSI_VOX_USB_2 5 +#define EM2800_BOARD_TERRATEC_CINERGY_200 6 +#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 +#define EM2800_BOARD_KWORLD_USB2800 8 +#define EM2820_BOARD_PINNACLE_DVC_90 9 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 +#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 +#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 +#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 + #define UNSET -1 /* maximum number of em28xx boards */ @@ -131,17 +148,10 @@ enum enum28xx_itype { EM28XX_RADIO, }; -enum em28xx_amux { - EM28XX_AMUX_VIDEO, - EM28XX_AMUX_LINE_IN, - EM28XX_AMUX_AC97_VIDEO, - EM28XX_AMUX_AC97_LINE_IN, -}; - struct em28xx_input { enum enum28xx_itype type; unsigned int vmux; - enum em28xx_amux amux; + unsigned int amux; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -155,23 +165,19 @@ enum em28xx_decoder { struct em28xx_board { char *name; int vchannels; + int norm; int tuner_type; /* i2c flags */ + unsigned int is_em2800; unsigned int tda9887_conf; - unsigned int is_em2800:1; + unsigned int has_tuner:1; unsigned int has_msp34xx:1; - unsigned int mts_firmware:1; - unsigned int has_12mhz_i2s:1; - unsigned int max_range_640_480:1; - - unsigned int analog_gpio; enum em28xx_decoder decoder; struct em28xx_input input[MAX_EM28XX_INPUT]; - struct em28xx_input radio; }; struct em28xx_eeprom { @@ -195,26 +201,12 @@ enum em28xx_dev_state { DEV_MISCONFIGURED = 0x04, }; -#define EM28XX_AUDIO_BUFS 5 -#define EM28XX_NUM_AUDIO_PACKETS 64 -#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ -#define EM28XX_CAPTURE_STREAM_EN 1 -#define EM28XX_AUDIO 0x10 - -struct em28xx_audio { - char name[50]; - char *transfer_buffer[EM28XX_AUDIO_BUFS]; - struct urb *urb[EM28XX_AUDIO_BUFS]; - struct usb_device *udev; - unsigned int capture_transfer_done; - struct snd_pcm_substream *capture_pcm_substream; - - unsigned int hwptr_done_capture; - struct snd_card *sndcard; - - int users, shutdown; - enum em28xx_stream_state capture_stream; - spinlock_t slock; +/* tvnorms */ +struct em28xx_tvnorm { + char *name; + v4l2_std_id id; + /* mode for saa7113h */ + int mode; }; /* main device struct */ @@ -223,17 +215,12 @@ struct em28xx { char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ - unsigned int analog_gpio; - unsigned int is_em2800:1; - unsigned int has_msp34xx:1; - unsigned int has_tda9887:1; - unsigned int stream_on:1; /* Locks streams */ - unsigned int has_audio_class:1; - unsigned int has_12mhz_i2s:1; - unsigned int max_range_640_480:1; - + unsigned int is_em2800; int video_inputs; /* number of video inputs */ struct list_head devlist; + unsigned int has_tuner:1; + unsigned int has_msp34xx:1; + unsigned int has_tda9887:1; u32 i2s_speed; /* I2S speed for audio digital stream */ @@ -248,7 +235,8 @@ struct em28xx { /* video for linux */ int users; /* user count for exclusive use */ struct video_device *vdev; /* video for linux device struct */ - v4l2_std_id norm; /* selected tv norm */ + struct video_picture vpic; /* picture settings only used to init saa7113h */ + struct em28xx_tvnorm *tvnorm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ unsigned int ctl_ainput; /* slected audio input */ @@ -268,27 +256,17 @@ struct em28xx { int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; - unsigned int video_bytesread; /* Number of bytes read */ - - unsigned long hash; /* eeprom hash - for boards with generic ID */ - unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ - - struct em28xx_audio *adev; /* states */ enum em28xx_dev_state state; enum em28xx_stream_state stream; enum em28xx_io_method io; - - struct work_struct request_module_wk; - /* locks */ - struct mutex lock; + struct mutex lock, fileop_lock; spinlock_t queue_lock; struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; struct video_device *vbi_dev; - struct video_device *radio_dev; unsigned char eedata[256]; @@ -311,27 +289,16 @@ struct em28xx { int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg); }; -struct em28xx_fh { - struct em28xx *dev; - unsigned int stream_on:1; /* Locks streams */ - int radio; -}; - -struct em28xx_ops { - struct list_head next; - char *name; - int id; - int (*init)(struct em28xx *); - int (*fini)(struct em28xx *); -}; - /* Provided by em28xx-i2c.c */ void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg); -void em28xx_do_i2c_scan(struct em28xx *dev); int em28xx_i2c_register(struct em28xx *dev); int em28xx_i2c_unregister(struct em28xx *dev); +/* Provided by em28xx-input.c */ + +void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir); + /* Provided by em28xx-core.c */ u32 em28xx_request_buffers(struct em28xx *dev, u32 count); @@ -347,9 +314,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 bitmask); -int em28xx_set_audio_source(struct em28xx *dev); +int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val); int em28xx_audio_analog_set(struct em28xx *dev); - int em28xx_colorlevels_set_default(struct em28xx *dev); int em28xx_capture_start(struct em28xx *dev, int start); int em28xx_outfmt_set_yuv422(struct em28xx *dev); @@ -358,10 +324,6 @@ int em28xx_init_isoc(struct em28xx *dev); void em28xx_uninit_isoc(struct em28xx *dev); int em28xx_set_alternate(struct em28xx *dev); -/* Provided by em28xx-video.c */ -int em28xx_register_extension(struct em28xx_ops *dev); -void em28xx_unregister_extension(struct em28xx_ops *dev); - /* Provided by em28xx-cards.c */ extern int em2800_variant_detect(struct usb_device* udev,int model); extern void em28xx_pre_card_setup(struct em28xx *dev); @@ -369,20 +331,8 @@ extern void em28xx_card_setup(struct em28xx *dev); extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); - -/* Provided by em28xx-input.c */ -/* TODO: Check if the standard get_key handlers on ir-common can be used */ -int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw); - -/* em2800 registers */ -#define EM2800_AUDIOSRC_REG 0x08 /* em28xx registers */ -#define I2C_CLK_REG 0x06 #define CHIPID_REG 0x0a #define USBSUSP_REG 0x0c /* */ @@ -434,12 +384,9 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, /* em202 registers */ #define MASTER_AC97 0x02 -#define LINE_IN_AC97 0x10 #define VIDEO_AC97 0x14 /* register settings */ -#define EM2800_AUDIO_SRC_TUNER 0x0d -#define EM2800_AUDIO_SRC_LINE 0x0c #define EM28XX_AUDIO_SRC_TUNER 0xc0 #define EM28XX_AUDIO_SRC_LINE 0x80 @@ -459,6 +406,22 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, printk(KERN_WARNING "%s: "fmt,\ dev->name , ##arg); } while (0) +inline static int em28xx_audio_source(struct em28xx *dev, int input) +{ + return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); +} + +inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute) +{ + return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80); +} + +inline static int em28xx_audio_analog_setup(struct em28xx *dev) +{ + /* unmute video mixer with default volume level */ + return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08"); +} + inline static int em28xx_compression_disable(struct em28xx *dev) { /* side effect of disabling scaler and mixer */ @@ -534,17 +497,18 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val) /*FIXME: maxw should be dependent of alt mode */ inline static unsigned int norm_maxw(struct em28xx *dev) { - if (dev->max_range_640_480) - return 640; - else - return 720; + switch(dev->model){ + case (EM2820_BOARD_MSI_VOX_USB_2): return(640); + default: return(720); + } } inline static unsigned int norm_maxh(struct em28xx *dev) { - if (dev->max_range_640_480) - return 480; - else - return (dev->norm & V4L2_STD_625_50) ? 576 : 480; + switch(dev->model){ + case (EM2820_BOARD_MSI_VOX_USB_2): return(480); + default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480; + } } + #endif diff --git a/trunk/drivers/media/video/et61x251/et61x251_core.c b/trunk/drivers/media/video/et61x251/et61x251_core.c index 06b6a3ae06c4..d19d73b81ede 100644 --- a/trunk/drivers/media/video/et61x251/et61x251_core.c +++ b/trunk/drivers/media/video/et61x251/et61x251_core.c @@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) } -static int et61x251_read_reg(struct et61x251_device* cam, u16 index) +int et61x251_read_reg(struct et61x251_device* cam, u16 index) { struct usb_device* udev = cam->usbdev; u8* buff = cam->control_buffer; @@ -268,6 +268,73 @@ et61x251_i2c_wait(struct et61x251_device* cam, } +int +et61x251_i2c_try_read(struct et61x251_device* cam, + const 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, + const 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, @@ -320,6 +387,17 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, } +int et61x251_i2c_read(struct et61x251_device* cam, u8 address) +{ + return et61x251_i2c_try_read(cam, &cam->sensor, address); +} + + +int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) +{ + return et61x251_i2c_try_write(cam, &cam->sensor, address, value); +} + /*****************************************************************************/ static void et61x251_urb_complete(struct urb *urb) @@ -597,83 +675,6 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam) /*****************************************************************************/ #ifdef CONFIG_VIDEO_ADV_DEBUG - -static int et61x251_i2c_try_read(struct et61x251_device* cam, - const 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]; -} - - -static int et61x251_i2c_try_write(struct et61x251_device* cam, - const 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; -} - -static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) -{ - return et61x251_i2c_try_read(cam, &cam->sensor, address); -} - -static int et61x251_i2c_write(struct et61x251_device* cam, - u8 address, u8 value) -{ - return et61x251_i2c_try_write(cam, &cam->sensor, address, value); -} - static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) { char str[5]; diff --git a/trunk/drivers/media/video/et61x251/et61x251_sensor.h b/trunk/drivers/media/video/et61x251/et61x251_sensor.h index 71a03148cb09..e14586330623 100644 --- a/trunk/drivers/media/video/et61x251/et61x251_sensor.h +++ b/trunk/drivers/media/video/et61x251/et61x251_sensor.h @@ -52,6 +52,14 @@ et61x251_attach_sensor(struct et61x251_device* cam, /*****************************************************************************/ 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*, + const struct et61x251_sensor*, u8 address, + u8 value); +extern int et61x251_i2c_try_read(struct et61x251_device*, + const 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); diff --git a/trunk/drivers/media/video/ir-kbd-i2c.c b/trunk/drivers/media/video/ir-kbd-i2c.c index 9851987b95fb..29779d8bf7fb 100644 --- a/trunk/drivers/media/video/ir-kbd-i2c.c +++ b/trunk/drivers/media/video/ir-kbd-i2c.c @@ -398,7 +398,6 @@ static int ir_attach(struct i2c_adapter *adap, int addr, case 0x7a: case 0x47: case 0x71: - case 0x2d: if (adap->id == I2C_HW_B_CX2388x) { /* Handled by cx88-input */ name = "CX2388x remote"; @@ -505,7 +504,7 @@ static int ir_probe(struct i2c_adapter *adap) */ static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; - static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 }; + static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; static const int probe_cx23885[] = { 0x6b, -1 }; diff --git a/trunk/drivers/media/video/ivtv/Kconfig b/trunk/drivers/media/video/ivtv/Kconfig index 270906fc3146..854cc9c30ca9 100644 --- a/trunk/drivers/media/video/ivtv/Kconfig +++ b/trunk/drivers/media/video/ivtv/Kconfig @@ -3,7 +3,6 @@ config VIDEO_IVTV depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL select I2C_ALGOBIT select FW_LOADER - select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X @@ -13,7 +12,6 @@ config VIDEO_IVTV select VIDEO_SAA7127 select VIDEO_TVAUDIO select VIDEO_CS53L32A - select VIDEO_M52790 select VIDEO_WM8775 select VIDEO_WM8739 select VIDEO_VP27SMPX diff --git a/trunk/drivers/media/video/ivtv/Makefile b/trunk/drivers/media/video/ivtv/Makefile index a0389014fa88..e8eefd96d897 100644 --- a/trunk/drivers/media/video/ivtv/Makefile +++ b/trunk/drivers/media/video/ivtv/Makefile @@ -6,8 +6,3 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - diff --git a/trunk/drivers/media/video/ivtv/ivtv-cards.c b/trunk/drivers/media/video/ivtv/ivtv-cards.c index f23c6b8d6911..b6a8be622d3c 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-cards.c +++ b/trunk/drivers/media/video/ivtv/ivtv-cards.c @@ -23,7 +23,6 @@ #include "ivtv-i2c.h" #include -#include #include #include #include @@ -40,27 +39,6 @@ #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) -/* usual i2c tuner addresses to probe */ -static struct ivtv_card_tuner_i2c ivtv_i2c_std = { - .radio = { I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, 0x60, I2C_CLIENT_END }, -}; - -/* as above, but with possible radio tuner */ -static struct ivtv_card_tuner_i2c ivtv_i2c_radio = { - .radio = { 0x60, I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, I2C_CLIENT_END }, -}; - -/* using the tda8290+75a combo */ -static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = { - .radio = { I2C_CLIENT_END }, - .demod = { I2C_CLIENT_END }, - .tv = { 0x4b, I2C_CLIENT_END }, -}; - /********************** card configuration *******************************/ /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii @@ -94,7 +72,6 @@ static const struct ivtv_card ivtv_card_pvr250 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -149,7 +126,6 @@ static const struct ivtv_card ivtv_card_pvr350 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, - .i2c = &ivtv_i2c_std, }; /* PVR-350 V1 boards have a different audio tuner input and use a @@ -181,7 +157,6 @@ static const struct ivtv_card ivtv_card_pvr350_v1 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -217,7 +192,6 @@ static const struct ivtv_card ivtv_card_pvr150 = { CX25840_AUDIO_SERIAL, WM8775_AIN4 }, /* apparently needed for the IR blaster */ .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -260,7 +234,6 @@ static const struct ivtv_card ivtv_card_m179 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, }, .pci_list = ivtv_pci_m179, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -302,7 +275,6 @@ static const struct ivtv_card ivtv_card_mpg600 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg600, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -343,7 +315,6 @@ static const struct ivtv_card ivtv_card_mpg160 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg160, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -379,7 +350,6 @@ static const struct ivtv_card ivtv_card_pg600 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_pg600, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -423,7 +393,6 @@ static const struct ivtv_card ivtv_card_avc2410 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_avc2410, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -494,7 +463,6 @@ static const struct ivtv_card ivtv_card_tg5000tv = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_tg5000tv, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -525,7 +493,6 @@ static const struct ivtv_card ivtv_card_va2000 = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_va2000, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -570,7 +537,6 @@ static const struct ivtv_card ivtv_card_cx23416gyc = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_cx23416gyc, - .i2c = &ivtv_i2c_std, }; static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { @@ -601,7 +567,6 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, - .i2c = &ivtv_i2c_std, }; static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { @@ -631,7 +596,6 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -671,7 +635,6 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -708,7 +671,6 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx2e, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -743,7 +705,6 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -782,7 +743,6 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd2, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -818,7 +778,6 @@ static const struct ivtv_card ivtv_card_yuan_mpc622 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, }, .pci_list = ivtv_pci_yuan_mpc622, - .i2c = &ivtv_i2c_tda8290, }; /* ------------------------------------------------------------------------- */ @@ -860,7 +819,6 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_dctmvtvp1, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -880,7 +838,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, .video_inputs = { { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, @@ -889,8 +847,10 @@ static const struct ivtv_card ivtv_card_pg600v2 = { .audio_inputs = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + }, .pci_list = ivtv_pci_pg600v2, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -911,22 +871,17 @@ static const struct ivtv_card ivtv_card_club3d = { .hw_audio_ctrl = IVTV_HW_CX25840, .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 }, }, .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, - .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, }, .pci_list = ivtv_pci_club3d, - .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -945,7 +900,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, .video_inputs = { { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, @@ -954,115 +909,10 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, }, .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ - .pci_list = ivtv_pci_avertv_mce116, - .i2c = &ivtv_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia PVR-150 Plus (M113) card */ - -static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_aver_pvr150 = { - .type = IVTV_CARD_AVER_PVR150PLUS, - .name = "AVerMedia PVR-150 Plus", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_GPIO, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, - CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, - .gpio_init = { .direction = 0x0800, .initial_value = 0 }, - .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, - .tuners = { - /* This card has a Partsnic PTI-5NF05 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, - }, - .pci_list = ivtv_pci_aver_pvr150, - .i2c = &ivtv_i2c_radio, -}; - -/* ------------------------------------------------------------------------- */ - -/* AVerMedia EZMaker PCI Deluxe card */ - -static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_aver_ezmaker = { - .type = IVTV_CARD_AVER_EZMAKER, - .name = "AVerMedia EZMaker PCI Deluxe", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, - .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 0 }, - }, - .gpio_init = { .direction = 0x4000, .initial_value = 0x4000 }, - /* Does not have a tuner */ - .pci_list = ivtv_pci_aver_ezmaker, -}; - -/* ------------------------------------------------------------------------- */ - -/* ASUS Falcon2 */ - -static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e }, - { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e }, - { 0, 0, 0 } -}; - -static const struct ivtv_card ivtv_card_asus_falcon2 = { - .type = IVTV_CARD_ASUS_FALCON2, - .name = "ASUS Falcon2", - .v4l2_capabilities = IVTV_CAP_ENCODER, - .hw_video = IVTV_HW_CX25840, - .hw_audio = IVTV_HW_CX25840, - .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_muxer = IVTV_HW_M52790, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER, - .video_inputs = { - { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, - { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 }, - }, - .audio_inputs = { - { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, - M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX }, - { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 }, - }, - .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, }, - .pci_list = ivtv_pci_asus_falcon2, - .i2c = &ivtv_i2c_std, + .pci_list = ivtv_pci_avertv_mce116, }; static const struct ivtv_card *ivtv_card_list[] = { @@ -1087,9 +937,6 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pg600v2, &ivtv_card_club3d, &ivtv_card_avertv_mce116, - &ivtv_card_asus_falcon2, - &ivtv_card_aver_pvr150, - &ivtv_card_aver_ezmaker, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/trunk/drivers/media/video/ivtv/ivtv-cards.h b/trunk/drivers/media/video/ivtv/ivtv-cards.h index 191aafdd9968..ff46e5ae8653 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-cards.h +++ b/trunk/drivers/media/video/ivtv/ivtv-cards.h @@ -45,10 +45,7 @@ #define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ #define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ #define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ -#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ -#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ -#define IVTV_CARD_LAST 23 +#define IVTV_CARD_LAST 20 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -72,7 +69,6 @@ #define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 #define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 #define IVTV_PCI_ID_ADAPTEC 0x9005 -#define IVTV_PCI_ID_ASUSTEK 0x1043 #define IVTV_PCI_ID_AVERMEDIA 0x1461 #define IVTV_PCI_ID_YUAN1 0x12ab #define IVTV_PCI_ID_YUAN2 0xff01 @@ -84,7 +80,7 @@ #define IVTV_PCI_ID_GOTVIEW1 0xffac #define IVTV_PCI_ID_GOTVIEW2 0xffad -/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */ +/* hardware flags */ #define IVTV_HW_CX25840 (1 << 0) #define IVTV_HW_SAA7115 (1 << 1) #define IVTV_HW_SAA7127 (1 << 2) @@ -94,12 +90,12 @@ #define IVTV_HW_CS53L32A (1 << 6) #define IVTV_HW_TVEEPROM (1 << 7) #define IVTV_HW_SAA7114 (1 << 8) -#define IVTV_HW_UPD64031A (1 << 9) -#define IVTV_HW_UPD6408X (1 << 10) -#define IVTV_HW_SAA717X (1 << 11) -#define IVTV_HW_WM8739 (1 << 12) -#define IVTV_HW_VP27SMPX (1 << 13) -#define IVTV_HW_M52790 (1 << 14) +#define IVTV_HW_TVAUDIO (1 << 9) +#define IVTV_HW_UPD64031A (1 << 10) +#define IVTV_HW_UPD6408X (1 << 11) +#define IVTV_HW_SAA717X (1 << 12) +#define IVTV_HW_WM8739 (1 << 13) +#define IVTV_HW_VP27SMPX (1 << 14) #define IVTV_HW_GPIO (1 << 15) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) @@ -234,12 +230,6 @@ struct ivtv_card_tuner { int tuner; /* tuner ID (from tuner.h) */ }; -struct ivtv_card_tuner_i2c { - unsigned short radio[2];/* radio tuner i2c address to probe */ - unsigned short demod[2];/* demodulator i2c address to probe */ - unsigned short tv[4]; /* tv tuner i2c addresses to probe */ -}; - /* for card information/parameters */ struct ivtv_card { int type; @@ -267,7 +257,6 @@ struct ivtv_card { struct ivtv_gpio_audio_detect gpio_audio_detect; struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; - struct ivtv_card_tuner_i2c *i2c; /* list of device and subsystem vendor/devices that correspond to this card type. */ diff --git a/trunk/drivers/media/video/ivtv/ivtv-driver.c b/trunk/drivers/media/video/ivtv/ivtv-driver.c index d42f120354e5..6d2dd8764f81 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-driver.c +++ b/trunk/drivers/media/video/ivtv/ivtv-driver.c @@ -59,7 +59,6 @@ #include #include #include -#include "tuner-xc2028.h" /* var to keep track of the number of array elements in use */ int ivtv_cards_active = 0; @@ -186,9 +185,6 @@ MODULE_PARM_DESC(cardtype, "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" "\t\t\t20 = Club3D ZAP-TV1x01\n" "\t\t\t21 = AverTV MCE 116 Plus\n" - "\t\t\t22 = ASUS Falcon2\n" - "\t\t\t23 = AverMedia PVR-150 Plus\n" - "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -401,7 +397,6 @@ static void ivtv_process_eeprom(struct ivtv *itv) itv->v4l2_cap = itv->card->v4l2_capabilities; itv->card_name = itv->card->name; - itv->card_i2c = itv->card->i2c; /* If this is a PVR500 then it should be possible to detect whether it is the first or second unit by looking at the subsystem device ID: is bit 4 is @@ -419,14 +414,7 @@ static void ivtv_process_eeprom(struct ivtv *itv) This detection is needed since the eeprom reports incorrectly that a radio is present on the second unit. */ if (tv.model / 1000 == 23) { - static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = { - .radio = { 0x60, I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, I2C_CLIENT_END }, - }; - itv->card_name = "WinTV PVR 500"; - itv->card_i2c = &ivtv_i2c_radio; if (pci_slot == 8 || pci_slot == 9) { int is_first = (pci_slot & 1) == 0; @@ -640,11 +628,10 @@ static void ivtv_process_options(struct ivtv *itv) IVTV_ERR("Defaulting to %s card\n", itv->card->name); IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); - IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n"); + IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n"); } itv->v4l2_cap = itv->card->v4l2_capabilities; itv->card_name = itv->card->name; - itv->card_i2c = itv->card->i2c; } /* Precondition: the ivtv structure has been memset to 0. Only @@ -708,7 +695,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) atomic_set(&itv->yuv_info.next_dma_frame, -1); itv->yuv_info.lace_mode = ivtv_yuv_mode; itv->yuv_info.lace_threshold = ivtv_yuv_threshold; - itv->yuv_info.max_frames_buffered = 3; return 0; } @@ -826,61 +812,75 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, return 0; } -static u32 ivtv_request_module(struct ivtv *itv, u32 hw, - const char *name, u32 id) +static void ivtv_request_module(struct ivtv *itv, const char *name) { - if ((hw & id) == 0) - return hw; if (request_module(name) != 0) { IVTV_ERR("Failed to load module %s\n", name); - return hw & ~id; + } else { + IVTV_DEBUG_INFO("Loaded module %s\n", name); } - IVTV_DEBUG_INFO("Loaded module %s\n", name); - return hw; } static void ivtv_load_and_init_modules(struct ivtv *itv) { u32 hw = itv->card->hw_all; - unsigned i; + int i; /* load modules */ #ifndef CONFIG_VIDEO_TUNER - hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); + if (hw & IVTV_HW_TUNER) { + if (itv->options.tuner == TUNER_XCEIVE_XC3028) { + IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); + itv->tunerid = 1; + } + else { + ivtv_request_module(itv, "tuner"); + } + } #endif #ifndef CONFIG_VIDEO_CX25840 - hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840); + if (hw & IVTV_HW_CX25840) + ivtv_request_module(itv, "cx25840"); #endif #ifndef CONFIG_VIDEO_SAA711X - hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X); + if (hw & IVTV_HW_SAA711X) + ivtv_request_module(itv, "saa7115"); #endif #ifndef CONFIG_VIDEO_SAA7127 - hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127); + if (hw & IVTV_HW_SAA7127) + ivtv_request_module(itv, "saa7127"); #endif - hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X); + if (hw & IVTV_HW_SAA717X) + ivtv_request_module(itv, "saa717x"); #ifndef CONFIG_VIDEO_UPD64031A - hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A); + if (hw & IVTV_HW_UPD64031A) + ivtv_request_module(itv, "upd64031a"); #endif #ifndef CONFIG_VIDEO_UPD64083 - hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X); + if (hw & IVTV_HW_UPD6408X) + ivtv_request_module(itv, "upd64083"); #endif #ifndef CONFIG_VIDEO_MSP3400 - hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX); + if (hw & IVTV_HW_MSP34XX) + ivtv_request_module(itv, "msp3400"); #endif #ifndef CONFIG_VIDEO_VP27SMPX - hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX); + if (hw & IVTV_HW_VP27SMPX) + ivtv_request_module(itv, "vp27smpx"); #endif + if (hw & IVTV_HW_TVAUDIO) + ivtv_request_module(itv, "tvaudio"); #ifndef CONFIG_VIDEO_WM8775 - hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775); + if (hw & IVTV_HW_WM8775) + ivtv_request_module(itv, "wm8775"); #endif #ifndef CONFIG_VIDEO_WM8739 - hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739); + if (hw & IVTV_HW_WM8739) + ivtv_request_module(itv, "wm8739"); #endif #ifndef CONFIG_VIDEO_CS53L32A - hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A); -#endif -#ifndef CONFIG_VIDEO_M52790 - hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790); + if (hw & IVTV_HW_CS53L32A) + ivtv_request_module(itv, "cs53l32a"); #endif /* check which i2c devices are actually found */ @@ -889,12 +889,11 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) if (!(device & hw)) continue; - if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) { - /* GPIO and TVEEPROM do not use i2c probing */ - itv->hw_flags |= device; + if (device == IVTV_HW_GPIO) { + /* GPIO is always available */ + itv->hw_flags |= IVTV_HW_GPIO; continue; } - ivtv_i2c_register(itv, i); if (ivtv_i2c_hw_addr(itv, device) > 0) itv->hw_flags |= device; } @@ -965,6 +964,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; + int yuv_buf_size; int vbi_buf_size; struct ivtv *itv; @@ -979,7 +979,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, } itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); - if (itv == NULL) { + if (itv == 0) { spin_unlock(&ivtv_cards_lock); return -ENOMEM; } @@ -1068,6 +1068,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); if (itv->card->hw_all & IVTV_HW_TVEEPROM) { +#ifdef CONFIG_VIDEO_TVEEPROM_MODULE + ivtv_request_module(itv, "tveeprom"); +#endif /* Based on the model number the cardtype may be changed. The PCI IDs are not always reliable. */ ivtv_process_eeprom(itv); @@ -1108,19 +1111,16 @@ static int __devinit ivtv_probe(struct pci_dev *dev, itv->is_50hz = 1; itv->is_out_50hz = 1; } - - itv->yuv_info.osd_full_w = 720; - itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480; - itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w; - itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h; - itv->params.video_gop_size = itv->is_60hz ? 15 : 12; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000; + + /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */ + yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500; + itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2; + itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8; /* Setup VBI Raw Size. Should be big enough to hold PAL. It is possible to switch between PAL and NTSC, so we need to @@ -1140,26 +1140,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev, if (itv->options.radio > 0) itv->v4l2_cap |= V4L2_CAP_RADIO; - if (itv->options.tuner > -1) { + if (itv->options.tuner > -1 && itv->tunerid == 0) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ - setup.tuner_callback = (setup.type == TUNER_XC2028) ? - ivtv_reset_tuner_gpio : NULL; ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); - if (setup.type == TUNER_XC2028) { - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - }; - struct v4l2_priv_tun_config cfg = { - .tuner = itv->options.tuner, - .priv = &ctrl, - }; - ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg); - } } /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) diff --git a/trunk/drivers/media/video/ivtv/ivtv-driver.h b/trunk/drivers/media/video/ivtv/ivtv-driver.h index 536140f0c19e..49ce14d14a54 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-driver.h +++ b/trunk/drivers/media/video/ivtv/ivtv-driver.h @@ -65,6 +65,7 @@ #include + /* Memory layout */ #define IVTV_ENCODER_OFFSET 0x00000000 #define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ @@ -391,9 +392,6 @@ struct yuv_frame_info u32 tru_h; u32 offset_y; s32 lace_mode; - u32 sync_field; - u32 delay; - u32 interlaced; }; #define IVTV_YUV_MODE_INTERLACED 0x00 @@ -405,8 +403,6 @@ struct yuv_frame_info #define IVTV_YUV_SYNC_ODD 0x04 #define IVTV_YUV_SYNC_MASK 0x04 -#define IVTV_YUV_BUFFERS 8 - struct yuv_playback_info { u32 reg_2834; @@ -465,11 +461,10 @@ struct yuv_playback_info u32 osd_vis_w; u32 osd_vis_h; - u32 osd_full_w; - u32 osd_full_h; - int decode_height; + int frame_interlaced; + int lace_mode; int lace_threshold; int lace_sync_field; @@ -480,23 +475,16 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; + int sync_field[4]; /* Field to sync on */ + int field_delay[4]; /* Flag to extend duration of previous frame */ u8 fields_lapsed; /* Counter used when delaying a frame */ - struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS]; + struct yuv_frame_info new_frame_info[4]; struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info_args; void *blanking_ptr; dma_addr_t blanking_dmaptr; - - int stream_size; - - u8 draw_frame; /* PVR350 buffer to draw into */ - u8 max_frames_buffered; /* Maximum number of frames to buffer */ - - struct v4l2_rect main_rect; - u32 v4l2_src_w; - u32 v4l2_src_h; }; #define IVTV_VBI_FRAMES 32 @@ -589,13 +577,13 @@ struct ivtv { struct pci_dev *dev; /* PCI device */ const struct ivtv_card *card; /* card information */ const char *card_name; /* full name of the card */ - const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ u8 nof_inputs; /* number of video inputs */ u8 nof_audio_inputs; /* number of audio inputs */ u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* hardware description of the board */ + int tunerid; /* userspace tuner ID for experimental Xceive tuner support */ v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ /* controlling video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); diff --git a/trunk/drivers/media/video/ivtv/ivtv-fileops.c b/trunk/drivers/media/video/ivtv/ivtv-fileops.c index 6fb96f19a866..a200a8a95a2d 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-fileops.c +++ b/trunk/drivers/media/video/ivtv/ivtv-fileops.c @@ -542,7 +542,6 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c struct ivtv_open_id *id = filp->private_data; struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; - struct yuv_playback_info *yi = &itv->yuv_info; struct ivtv_buffer *buf; struct ivtv_queue q; int bytes_written = 0; @@ -581,24 +580,6 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c set_bit(IVTV_F_S_APPL_IO, &s->s_flags); retry: - /* If possible, just DMA the entire frame - Check the data transfer size - since we may get here before the stream has been fully set-up */ - if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) { - while (count >= itv->dma_data_req_size) { - if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) { - bytes_written += itv->dma_data_req_size; - user_buf += itv->dma_data_req_size; - count -= itv->dma_data_req_size; - } else { - break; - } - } - if (count == 0) { - IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); - return bytes_written; - } - } - for (;;) { /* Gather buffers */ while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) @@ -623,16 +604,9 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c /* copy user data into buffers */ while ((buf = ivtv_dequeue(s, &q))) { - /* yuv is a pain. Don't copy more data than needed for a single - frame, otherwise we lose sync with the incoming stream */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && - yi->stream_size + count > itv->dma_data_req_size) - rc = ivtv_buf_copy_from_user(s, buf, user_buf, - itv->dma_data_req_size - yi->stream_size); - else - rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); - /* Make sure we really got all the user data */ + rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); + if (rc < 0) { ivtv_queue_move(s, &q, NULL, &s->q_free, 0); return rc; @@ -641,16 +615,6 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c count -= rc; bytes_written += rc; - if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { - yi->stream_size += rc; - /* If we have a complete yuv frame, break loop now */ - if (yi->stream_size == itv->dma_data_req_size) { - ivtv_enqueue(s, buf, &s->q_full); - yi->stream_size = 0; - break; - } - } - if (buf->bytesused != s->buf_size) { /* incomplete, leave in q_io for next time */ ivtv_enqueue(s, buf, &s->q_io); @@ -678,9 +642,6 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c if (s->q_full.length >= itv->dma_data_req_size) { int got_sig; - if (mode == OUT_YUV) - ivtv_yuv_setup_stream_frame(itv); - prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (!(got_sig = signal_pending(current)) && test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { @@ -961,15 +922,10 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) } /* YUV or MPG Decoding Mode? */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) { + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { + else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - /* For yuv, we need to know the dma size before we start */ - itv->dma_data_req_size = - 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); - itv->yuv_info.stream_size = 0; - } return 0; } diff --git a/trunk/drivers/media/video/ivtv/ivtv-gpio.c b/trunk/drivers/media/video/ivtv/ivtv-gpio.c index 688cd3856685..132fb5f71366 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-gpio.c +++ b/trunk/drivers/media/video/ivtv/ivtv-gpio.c @@ -22,7 +22,6 @@ #include "ivtv-driver.h" #include "ivtv-cards.h" #include "ivtv-gpio.h" -#include "tuner-xc2028.h" #include /* @@ -123,29 +122,6 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) write_reg(curdir, IVTV_REG_GPIO_DIR); } -/* Xceive tuner reset function */ -int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) -{ - struct i2c_algo_bit_data *algo = dev; - struct ivtv *itv = algo->data; - int curdir, curout; - - if (cmd != XC2028_TUNER_RESET) - return 0; - IVTV_DEBUG_INFO("Resetting tuner\n"); - curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - - curout |= (1 << 12); - write_reg(curout, IVTV_REG_GPIO_OUT); - schedule_timeout_interruptible(msecs_to_jiffies(1)); - return 0; -} void ivtv_gpio_init(struct ivtv *itv) { diff --git a/trunk/drivers/media/video/ivtv/ivtv-i2c.c b/trunk/drivers/media/video/ivtv/ivtv-i2c.c index fa5ab1eb1800..36e54f78aa2a 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-i2c.c +++ b/trunk/drivers/media/video/ivtv/ivtv-i2c.c @@ -80,7 +80,6 @@ #endif /* I2C_ADAP_CLASS_TV_ANALOG */ #define IVTV_CS53L32A_I2C_ADDR 0x11 -#define IVTV_M52790_I2C_ADDR 0x48 #define IVTV_CX25840_I2C_ADDR 0x44 #define IVTV_SAA7115_I2C_ADDR 0x21 #define IVTV_SAA7127_I2C_ADDR 0x44 @@ -92,8 +91,7 @@ #define IVTV_TEA5767_I2C_ADDR 0x60 #define IVTV_UPD64031A_I2C_ADDR 0x12 #define IVTV_UPD64083_I2C_ADDR 0x5c -#define IVTV_VP27SMPX_I2C_ADDR 0x5b -#define IVTV_M52790_I2C_ADDR 0x48 +#define IVTV_TDA985X_I2C_ADDR 0x5b /* This array should match the IVTV_HW_ defines */ static const u8 hw_driverids[] = { @@ -106,38 +104,18 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_CS53L32A, I2C_DRIVERID_TVEEPROM, I2C_DRIVERID_SAA711X, + I2C_DRIVERID_TVAUDIO, I2C_DRIVERID_UPD64031A, I2C_DRIVERID_UPD64083, I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, I2C_DRIVERID_VP27SMPX, - I2C_DRIVERID_M52790, - 0 /* IVTV_HW_GPIO dummy driver ID */ -}; - -/* This array should match the IVTV_HW_ defines */ -static const u8 hw_addrs[] = { - IVTV_CX25840_I2C_ADDR, - IVTV_SAA7115_I2C_ADDR, - IVTV_SAA7127_I2C_ADDR, - IVTV_MSP3400_I2C_ADDR, - 0, - IVTV_WM8775_I2C_ADDR, - IVTV_CS53L32A_I2C_ADDR, - 0, - IVTV_SAA7115_I2C_ADDR, - IVTV_UPD64031A_I2C_ADDR, - IVTV_UPD64083_I2C_ADDR, - IVTV_SAA717x_I2C_ADDR, - IVTV_WM8739_I2C_ADDR, - IVTV_VP27SMPX_I2C_ADDR, - IVTV_M52790_I2C_ADDR, 0 /* IVTV_HW_GPIO dummy driver ID */ }; /* This array should match the IVTV_HW_ defines */ static const char * const hw_drivernames[] = { - "cx25840", + "cx2584x", "saa7115", "saa7127", "msp3400", @@ -145,67 +123,31 @@ static const char * const hw_drivernames[] = { "wm8775", "cs53l32a", "tveeprom", - "saa7115", + "saa7114", + "tvaudio", "upd64031a", "upd64083", "saa717x", "wm8739", "vp27smpx", - "m52790", "gpio", }; -int ivtv_i2c_register(struct ivtv *itv, unsigned idx) +static int attach_inform(struct i2c_client *client) { - struct i2c_board_info info; - struct i2c_client *c; - u8 id; + struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); int i; - IVTV_DEBUG_I2C("i2c client register\n"); - if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0) - return -1; - id = hw_driverids[idx]; - memset(&info, 0, sizeof(info)); - strcpy(info.driver_name, hw_drivernames[idx]); - info.addr = hw_addrs[idx]; - for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {} - - if (i == I2C_CLIENTS_MAX) { - IVTV_ERR("insufficient room for new I2C client!\n"); - return -ENOMEM; + IVTV_DEBUG_I2C("i2c client attach\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (itv->i2c_clients[i] == NULL) { + itv->i2c_clients[i] = client; + break; + } } - - if (id != I2C_DRIVERID_TUNER) { - c = i2c_new_device(&itv->i2c_adap, &info); - if (c->driver == NULL) - i2c_unregister_device(c); - else - itv->i2c_clients[i] = c; - return itv->i2c_clients[i] ? 0 : -ENODEV; + if (i == I2C_CLIENTS_MAX) { + IVTV_ERR("Insufficient room for new I2C client\n"); } - - /* special tuner handling */ - c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio); - if (c && c->driver == NULL) - i2c_unregister_device(c); - else if (c) - itv->i2c_clients[i++] = c; - c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod); - if (c && c->driver == NULL) - i2c_unregister_device(c); - else if (c) - itv->i2c_clients[i++] = c; - c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv); - if (c && c->driver == NULL) - i2c_unregister_device(c); - else if (c) - itv->i2c_clients[i++] = c; - return 0; -} - -static int attach_inform(struct i2c_client *client) -{ return 0; } @@ -533,6 +475,9 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = { .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE, +#ifdef I2C_ADAP_CLASS_TV_ANALOG + .class = I2C_ADAP_CLASS_TV_ANALOG, +#endif }; static void ivtv_setscl_old(void *data, int state) @@ -580,12 +525,15 @@ static int ivtv_getsda_old(void *data) /* template for i2c-bit-algo */ static struct i2c_adapter ivtv_i2c_adap_template = { .name = "ivtv i2c driver", - .id = I2C_HW_B_CX2341X, + .id = I2C_HW_B_CX2341X, /* algo-bit is OR'd with this */ .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE, +#ifdef I2C_ADAP_CLASS_TV_ANALOG + .class = I2C_ADAP_CLASS_TV_ANALOG, +#endif }; static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { @@ -610,9 +558,12 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; - if (client == NULL || client->driver == NULL || - client->driver->command == NULL) + if (client == NULL) { + continue; + } + if (client->driver->command == NULL) { continue; + } if (addr == client->addr) { retval = client->driver->command(client, cmd, arg); return retval; @@ -633,7 +584,7 @@ static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id) for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; - if (client == NULL || client->driver == NULL) + if (client == NULL) continue; if (id == client->driver->id) { retval = client->addr; @@ -759,16 +710,6 @@ int init_ivtv_i2c(struct ivtv *itv) { IVTV_DEBUG_I2C("i2c init\n"); - /* Sanity checks for the I2C hardware arrays. They must be the - * same size and GPIO must be the last entry. - */ - if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) || - ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) || - IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) || - hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) { - IVTV_ERR("Mismatched I2C hardware arrays\n"); - return -ENODEV; - } if (itv->options.newi2c > 0) { memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, sizeof(struct i2c_adapter)); @@ -777,9 +718,9 @@ int init_ivtv_i2c(struct ivtv *itv) sizeof(struct i2c_adapter)); memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); + itv->i2c_algo.data = itv; + itv->i2c_adap.algo_data = &itv->i2c_algo; } - itv->i2c_algo.data = itv; - itv->i2c_adap.algo_data = &itv->i2c_algo; sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", itv->num); diff --git a/trunk/drivers/media/video/ivtv/ivtv-i2c.h b/trunk/drivers/media/video/ivtv/ivtv-i2c.h index 022978cf533d..987042c09b64 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-i2c.h +++ b/trunk/drivers/media/video/ivtv/ivtv-i2c.h @@ -33,7 +33,6 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg); int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg); int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg); void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); -int ivtv_i2c_register(struct ivtv *itv, unsigned idx); /* init + register i2c algo-bit adapter */ int init_ivtv_i2c(struct ivtv *itv); diff --git a/trunk/drivers/media/video/ivtv/ivtv-ioctl.c b/trunk/drivers/media/video/ivtv/ivtv-ioctl.c index edef2a579617..fd6826f472e3 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/trunk/drivers/media/video/ivtv/ivtv-ioctl.c @@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm fmt->fmt.pix.height = itv->main_rect.height; fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + if (itv->output_mode == OUT_UDMA_YUV) { switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { case IVTV_YUV_MODE_INTERLACED: fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? @@ -386,13 +386,14 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm break; } fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; - fmt->fmt.pix.bytesperline = 720; - fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w; - fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ fmt->fmt.pix.sizeimage = - 1080 * ((fmt->fmt.pix.height + 31) & ~31); - } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) { + fmt->fmt.pix.height * fmt->fmt.pix.width + + fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); + } + else if (itv->output_mode == OUT_YUV || + streamtype == IVTV_ENC_STREAM_TYPE_YUV || + streamtype == IVTV_DEC_STREAM_TYPE_YUV) { fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ fmt->fmt.pix.sizeimage = @@ -489,7 +490,6 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt, int set_fmt) { - struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; u16 set; @@ -505,52 +505,39 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, r.width = fmt->fmt.pix.width; r.height = fmt->fmt.pix.height; ivtv_get_fmt(itv, streamtype, fmt); - fmt->fmt.pix.width = r.width; - fmt->fmt.pix.height = r.height; - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + if (itv->output_mode != OUT_UDMA_YUV) { + /* TODO: would setting the rect also be valid for this mode? */ + fmt->fmt.pix.width = r.width; + fmt->fmt.pix.height = r.height; + } + if (itv->output_mode == OUT_UDMA_YUV) { + /* TODO: add checks for validity */ fmt->fmt.pix.field = field; - if (fmt->fmt.pix.width < 2) - fmt->fmt.pix.width = 2; - if (fmt->fmt.pix.width > 720) - fmt->fmt.pix.width = 720; - if (fmt->fmt.pix.height < 2) - fmt->fmt.pix.height = 2; - if (fmt->fmt.pix.height > 576) - fmt->fmt.pix.height = 576; } - if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - /* Return now if we already have some frame data */ - if (yi->stream_size) - return -EBUSY; - - yi->v4l2_src_w = r.width; - yi->v4l2_src_h = r.height; + if (set_fmt) { + if (itv->output_mode == OUT_UDMA_YUV) { + switch (field) { + case V4L2_FIELD_NONE: + itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE; + break; + case V4L2_FIELD_ANY: + itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO; + break; + case V4L2_FIELD_INTERLACED_BT: + itv->yuv_info.lace_mode = + IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; + break; + case V4L2_FIELD_INTERLACED_TB: + default: + itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED; + break; + } + itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; - switch (field) { - case V4L2_FIELD_NONE: - yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; - break; - case V4L2_FIELD_ANY: - yi->lace_mode = IVTV_YUV_MODE_AUTO; - break; - case V4L2_FIELD_INTERLACED_BT: - yi->lace_mode = - IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; - break; - case V4L2_FIELD_INTERLACED_TB: - default: - yi->lace_mode = IVTV_YUV_MODE_INTERLACED; - break; + /* Force update of yuv registers */ + itv->yuv_info.yuv_forced_update = 1; + return 0; } - yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; - - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - itv->dma_data_req_size = - 1080 * ((yi->v4l2_src_h + 31) & ~31); - - /* Force update of yuv registers */ - yi->yuv_forced_update = 1; - return 0; } return 0; } @@ -673,8 +660,11 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) chip->ident = V4L2_IDENT_NONE; chip->revision = 0; if (reg->match_type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { + struct v4l2_chip_ident *chip = arg; + chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; + } return 0; } if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) @@ -698,7 +688,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) ivtv_reset_ir_gpio(itv); } if (val & 0x02) { - itv->video_dec_func(itv, cmd, NULL); + itv->video_dec_func(itv, cmd, 0); } break; } @@ -713,12 +703,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void { struct ivtv_open_id *id = NULL; u32 data[CX2341X_MBOX_MAX_DATA]; - int streamtype = 0; - if (filp) { - id = (struct ivtv_open_id *)filp->private_data; - streamtype = id->type; - } + if (filp) id = (struct ivtv_open_id *)filp->private_data; switch (cmd) { case VIDIOC_G_PRIORITY: @@ -836,11 +822,6 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void cropcap->bounds.height = itv->is_50hz ? 576 : 480; cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; - } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - cropcap->bounds.width = itv->yuv_info.osd_full_w; - cropcap->bounds.height = itv->yuv_info.osd_full_h; - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; } else { cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; @@ -855,15 +836,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - itv->yuv_info.main_rect = crop->c; + if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { + itv->main_rect = crop->c; return 0; - } else { - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { - itv->main_rect = crop->c; - return 0; - } } return -EINVAL; } @@ -877,10 +853,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) - crop->c = itv->yuv_info.main_rect; - else - crop->c = itv->main_rect; + crop->c = itv->main_rect; return 0; } if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -891,7 +864,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_ENUM_FMT: { static struct v4l2_fmtdesc formats[] = { { 0, 0, 0, - "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, + "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } }, { 1, 0, V4L2_FMT_FLAG_COMPRESSED, @@ -1070,12 +1043,6 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void itv->main_rect.height = itv->params.height; ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 720, itv->main_rect.height, 0, 0); - itv->yuv_info.main_rect = itv->main_rect; - if (!itv->osd_info) { - itv->yuv_info.osd_full_w = 720; - itv->yuv_info.osd_full_h = - itv->is_out_50hz ? 576 : 480; - } } break; } diff --git a/trunk/drivers/media/video/ivtv/ivtv-irq.c b/trunk/drivers/media/video/ivtv/ivtv-irq.c index 65604dde9726..fd1688e4757d 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-irq.c +++ b/trunk/drivers/media/video/ivtv/ivtv-irq.c @@ -204,7 +204,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA s->sg_pending[idx].dst = buf->dma_handle; s->sg_pending[idx].src = offset; s->sg_pending[idx].size = s->buf_size; - buf->bytesused = min(size, s->buf_size); + buf->bytesused = (size < s->buf_size) ? size : s->buf_size; buf->dma_xfer_cnt = s->dma_xfer_cnt; s->q_predma.bytesused += buf->bytesused; @@ -302,11 +302,8 @@ static void dma_post(struct ivtv_stream *s) void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) { struct ivtv *itv = s->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - u8 frame = yi->draw_frame; - struct yuv_frame_info *f = &yi->new_frame_info[frame]; struct ivtv_buffer *buf; - u32 y_size = 720 * ((f->src_h + 31) & ~31); + u32 y_size = itv->params.height * itv->params.width; u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; int bytes_written = 0; @@ -314,42 +311,17 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); - - /* Insert buffer block for YUV if needed */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { - if (yi->blanking_dmaptr) { - s->sg_pending[idx].src = yi->blanking_dmaptr; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = 720 * 16; - } - offset += 720 * 16; - idx++; - } - list_for_each_entry(buf, &s->q_predma.list, list) { /* YUV UV Offset from Y Buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && - (bytes_written + buf->bytesused) >= y_size) { - s->sg_pending[idx].src = buf->dma_handle; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = y_size - bytes_written; + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { offset = uv_offset; - if (s->sg_pending[idx].size != buf->bytesused) { - idx++; - s->sg_pending[idx].src = - buf->dma_handle + s->sg_pending[idx - 1].size; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = - buf->bytesused - s->sg_pending[idx - 1].size; - offset += s->sg_pending[idx].size; - } y_done = 1; - } else { - s->sg_pending[idx].src = buf->dma_handle; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = buf->bytesused; - offset += buf->bytesused; } + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; + + offset += buf->bytesused; bytes_written += buf->bytesused; /* Sync SG buffers */ @@ -436,7 +408,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) s_vbi->sg_pending_size = 0; s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name); + IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); } s->dma_xfer_cnt++; @@ -728,15 +700,12 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - itv->dma_data_req_size = - 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); - itv->dma_data_req_offset = data[1]; - if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0) - ivtv_yuv_frame_complete(itv); + itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2; + itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0]; s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; } else { - itv->dma_data_req_size = min_t(u32, data[2], 0x10000); + itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2]; itv->dma_data_req_offset = data[1]; s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; } @@ -746,8 +715,6 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); } else { - if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) - ivtv_yuv_setup_stream_frame(itv); clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); @@ -764,26 +731,24 @@ static void ivtv_irq_vsync(struct ivtv *itv) * one vsync per frame. */ unsigned int frame = read_reg(0x28c0) & 1; - struct yuv_playback_info *yi = &itv->yuv_info; int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); - struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ f->sync_field) == 0 && - ((itv->last_vsync_field & 1) ^ f->sync_field)) || - (frame != (itv->last_vsync_field & 1) && !f->interlaced)) { + if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && + ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || + (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) { int next_dma_frame = last_dma_frame; - if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) { - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { + if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; - atomic_set(&yi->next_dma_frame, next_dma_frame); - yi->fields_lapsed = -1; + next_dma_frame = (next_dma_frame + 1) & 0x3; + atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); + itv->yuv_info.fields_lapsed = -1; } } } @@ -816,22 +781,20 @@ static void ivtv_irq_vsync(struct ivtv *itv) } /* Check if we need to update the yuv registers */ - if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) { - if (!f->update) { - last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS; - f = &yi->new_frame_info[last_dma_frame]; - } - - if (f->src_w) { - yi->update_frame = last_dma_frame; - f->update = 0; - yi->yuv_forced_update = 0; + if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { + if (!itv->yuv_info.new_frame_info[last_dma_frame].update) + last_dma_frame = (last_dma_frame - 1) & 3; + + if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) { + itv->yuv_info.update_frame = last_dma_frame; + itv->yuv_info.new_frame_info[last_dma_frame].update = 0; + itv->yuv_info.yuv_forced_update = 0; set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } } - yi->fields_lapsed++; + itv->yuv_info.fields_lapsed ++; } } diff --git a/trunk/drivers/media/video/ivtv/ivtv-mailbox.c b/trunk/drivers/media/video/ivtv/ivtv-mailbox.c index 13a6c374d2db..b05436da7136 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/trunk/drivers/media/video/ivtv/ivtv-mailbox.c @@ -333,7 +333,7 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; } -int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { return ivtv_api(priv, cmd, in, data); } diff --git a/trunk/drivers/media/video/ivtv/ivtv-mailbox.h b/trunk/drivers/media/video/ivtv/ivtv-mailbox.h index 6ef12091e3f3..71a54eef8fc7 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/trunk/drivers/media/video/ivtv/ivtv-mailbox.h @@ -28,6 +28,6 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); -int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); +int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); #endif diff --git a/trunk/drivers/media/video/ivtv/ivtv-routing.c b/trunk/drivers/media/video/ivtv/ivtv-routing.c index 05564919b57f..398bd33033ed 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-routing.c +++ b/trunk/drivers/media/video/ivtv/ivtv-routing.c @@ -25,7 +25,6 @@ #include "ivtv-routing.h" #include -#include #include #include @@ -33,26 +32,28 @@ settings. */ void ivtv_audio_set_io(struct ivtv *itv) { - const struct ivtv_card_audio_input *in; struct v4l2_routing route; + u32 audio_input; + int mux_input; /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) - in = &itv->card->radio_input; - else - in = &itv->card->audio_inputs[itv->audio_input]; + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { + audio_input = itv->card->radio_input.audio_input; + mux_input = itv->card->radio_input.muxer_input; + } else { + audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; + mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; + } /* handle muxer chips */ - route.input = in->muxer_input; + route.input = mux_input; route.output = 0; - if (itv->card->hw_muxer & IVTV_HW_M52790) - route.output = M52790_OUT_STEREO; ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - route.input = in->audio_input; - route.output = 0; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) + route.input = audio_input; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) { route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); + } ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); } diff --git a/trunk/drivers/media/video/ivtv/ivtv-streams.c b/trunk/drivers/media/video/ivtv/ivtv-streams.c index 24d98ecf35ad..74fb0e021979 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-streams.c +++ b/trunk/drivers/media/video/ivtv/ivtv-streams.c @@ -43,7 +43,7 @@ #include "ivtv-cards.h" #include "ivtv-streams.h" -static const struct file_operations ivtv_v4l2_enc_fops = { +static struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, @@ -53,7 +53,7 @@ static const struct file_operations ivtv_v4l2_enc_fops = { .poll = ivtv_v4l2_enc_poll, }; -static const struct file_operations ivtv_v4l2_dec_fops = { +static struct file_operations ivtv_v4l2_dec_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, @@ -572,10 +572,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* Initialize Digitizer for Capture */ - itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL); + itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0); ivtv_msleep_timeout(300, 1); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - itv->video_dec_func(itv, VIDIOC_STREAMON, NULL); + itv->video_dec_func(itv, VIDIOC_STREAMON, 0); } /* begin_capture */ @@ -661,12 +661,27 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); + /* Clear Streamoff */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { + /* Initialize Decoder */ + /* Reprogram Decoder YUV Buffers for YUV */ + write_reg(yuv_offset[0] >> 4, 0x82c); + write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); + write_reg(yuv_offset[0] >> 4, 0x834); + write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); + + write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24); + + write_reg_sync(0x00108080, 0x2898); + /* Enable YUV decoder output */ + write_reg_sync(0x01, IVTV_REG_VDM); + } + ivtv_setup_v4l2_decode_stream(s); /* set dma size to 65536 bytes */ ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); - /* Clear Streamoff */ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); /* Zero out decoder counters */ diff --git a/trunk/drivers/media/video/ivtv/ivtv-version.h b/trunk/drivers/media/video/ivtv/ivtv-version.h index 0f1d4cc4b4d9..d050de2a7229 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-version.h +++ b/trunk/drivers/media/video/ivtv/ivtv-version.h @@ -22,7 +22,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 2 +#define IVTV_DRIVER_VERSION_MINOR 1 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/trunk/drivers/media/video/ivtv/ivtv-yuv.c b/trunk/drivers/media/video/ivtv/ivtv-yuv.c index 85183480a225..9091c4837bbc 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-yuv.c +++ b/trunk/drivers/media/video/ivtv/ivtv-yuv.c @@ -22,37 +22,32 @@ #include "ivtv-udma.h" #include "ivtv-yuv.h" -/* YUV buffer offsets */ -const u32 yuv_offset[IVTV_YUV_BUFFERS] = { - 0x001a8600, - 0x00240400, - 0x002d8200, - 0x00370000, - 0x00029000, - 0x000C0E00, - 0x006B0400, - 0x00748200 +const u32 yuv_offset[4] = { + IVTV_YUV_BUFFER_OFFSET, + IVTV_YUV_BUFFER_OFFSET_1, + IVTV_YUV_BUFFER_OFFSET_2, + IVTV_YUV_BUFFER_OFFSET_3 }; static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, - struct ivtv_dma_frame *args) + struct ivtv_dma_frame *args) { struct ivtv_dma_page_info y_dma; struct ivtv_dma_page_info uv_dma; - struct yuv_playback_info *yi = &itv->yuv_info; - u8 frame = yi->draw_frame; - struct yuv_frame_info *f = &yi->new_frame_info[frame]; + int i; int y_pages, uv_pages; + unsigned long y_buffer_offset, uv_buffer_offset; int y_decode_height, uv_decode_height, y_size; + int frame = atomic_read(&itv->yuv_info.next_fill_frame); y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; - y_decode_height = uv_decode_height = f->src_h + f->src_y; + y_decode_height = uv_decode_height = args->src.height + args->src.top; - if (f->offset_y) + if (y_decode_height < 512-16) y_buffer_offset += 720 * 16; if (y_decode_height & 15) @@ -65,9 +60,8 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* Still in USE */ if (dma->SG_length || dma->page_count) { - IVTV_DEBUG_WARN - ("prep_user_dma: SG_length %d page_count %d still full?\n", - dma->SG_length, dma->page_count); + IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n", + dma->SG_length, dma->page_count); return -EBUSY; } @@ -83,9 +77,8 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, dma->page_count = y_dma.page_count + uv_dma.page_count; if (y_pages + uv_pages != dma->page_count) { - IVTV_DEBUG_WARN - ("failed to map user pages, returned %d instead of %d\n", - y_pages + uv_pages, dma->page_count); + IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", + y_pages + uv_pages, dma->page_count); for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); @@ -106,14 +99,16 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); /* Fill SG Array with new values */ - ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); + ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size); /* If we've offset the y plane, ensure top area is blanked */ - if (f->offset_y && yi->blanking_dmaptr) { - dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); - dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); - dma->SG_length++; + if (args->src.height + args->src.top < 512-16) { + if (itv->yuv_info.blanking_dmaptr) { + dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); + dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); + dma->SG_length++; + } } /* Tag SG Array with Interrupt Bit */ @@ -126,11 +121,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* We rely on a table held in the firmware - Quick check. */ int ivtv_yuv_filter_check(struct ivtv *itv) { - int i, y, uv; + int i, offset_y, offset_uv; - for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) { - if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) || - (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) { + for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) { + if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) || + (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) { IVTV_WARN ("YUV filter table not found in firmware.\n"); return -1; } @@ -140,67 +135,69 @@ int ivtv_yuv_filter_check(struct ivtv *itv) static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) { - u32 i, line; + int filter_index, filter_line; /* If any filter is -1, then don't update it */ if (h_filter > -1) { - if (h_filter > 4) - h_filter = 4; - i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384); - for (line = 0; line < 16; line++) { - write_reg(read_dec(i), 0x02804); - write_reg(read_dec(i), 0x0281c); - i += 4; - write_reg(read_dec(i), 0x02808); - write_reg(read_dec(i), 0x02820); - i += 4; - write_reg(read_dec(i), 0x0280c); - write_reg(read_dec(i), 0x02824); - i += 4; - write_reg(read_dec(i), 0x02810); - write_reg(read_dec(i), 0x02828); - i += 4; - write_reg(read_dec(i), 0x02814); - write_reg(read_dec(i), 0x0282c); - i += 8; + if (h_filter > 4) h_filter = 4; + filter_index = h_filter * 384; + filter_line = 0; + while (filter_line < 16) { + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804); + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c); + filter_index += 4; + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808); + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820); + filter_index += 4; + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c); + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824); + filter_index += 4; + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810); + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828); + filter_index += 4; + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814); + write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c); + filter_index += 8; write_reg(0, 0x02818); write_reg(0, 0x02830); + filter_line ++; } - IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter); + IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter); } if (v_filter_1 > -1) { - if (v_filter_1 > 4) - v_filter_1 = 4; - i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192); - for (line = 0; line < 16; line++) { - write_reg(read_dec(i), 0x02900); - i += 4; - write_reg(read_dec(i), 0x02904); - i += 8; + if (v_filter_1 > 4) v_filter_1 = 4; + filter_index = v_filter_1 * 192; + filter_line = 0; + while (filter_line < 16) { + write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900); + filter_index += 4; + write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904); + filter_index += 8; write_reg(0, 0x02908); + filter_line ++; } - IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1); + IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1); } if (v_filter_2 > -1) { - if (v_filter_2 > 4) - v_filter_2 = 4; - i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192); - for (line = 0; line < 16; line++) { - write_reg(read_dec(i), 0x0290c); - i += 4; - write_reg(read_dec(i), 0x02910); - i += 8; + if (v_filter_2 > 4) v_filter_2 = 4; + filter_index = v_filter_2 * 192; + filter_line = 0; + while (filter_line < 16) { + write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c); + filter_index += 4; + write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910); + filter_index += 8; write_reg(0, 0x02914); + filter_line ++; } - IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2); + IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2); } } -static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f) +static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window) { - struct yuv_playback_info *yi = &itv->yuv_info; u32 reg_2834, reg_2838, reg_283c; u32 reg_2844, reg_2854, reg_285c; u32 reg_2864, reg_2874, reg_2890; @@ -209,19 +206,18 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * int h_filter; u32 master_width; - IVTV_DEBUG_WARN - ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", - f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x); + IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", + window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x); /* How wide is the src image */ - x_cutoff = f->src_w + f->src_x; + x_cutoff = window->src_w + window->src_x; /* Set the display width */ - reg_2834 = f->dst_w; + reg_2834 = window->dst_w; reg_2838 = reg_2834; /* Set the display position */ - reg_2890 = f->dst_x; + reg_2890 = window->dst_x; /* Index into the image horizontally */ reg_2870 = 0; @@ -232,31 +228,32 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * Gradually adjust the offset to avoid the video 'snapping' left/right if it gets dragged through this region. Only do this if osd is full width. */ - if (f->vis_w == 720) { - if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680)) - reg_2870 = 10 - (f->tru_x - f->pan_x) / 4; - else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660)) - reg_2870 = (10 + (f->tru_x - f->pan_x) / 2); + if (window->vis_w == 720) { + if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){ + reg_2870 = 10 - (window->tru_x - window->pan_x) / 4; + } + else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) { + reg_2870 = (10 + (window->tru_x - window->pan_x) / 2); + } - if (f->dst_w >= f->src_w) + if (window->dst_w >= window->src_w) reg_2870 = reg_2870 << 16 | reg_2870; else reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); } - if (f->dst_w < f->src_w) + if (window->dst_w < window->src_w) reg_2870 = 0x000d000e - reg_2870; else reg_2870 = 0x0012000e - reg_2870; /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ - reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19; + reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19; - if (f->dst_w >= f->src_w) { + if (window->dst_w >= window->src_w) { x_cutoff &= ~1; - master_width = (f->src_w * 0x00200000) / (f->dst_w); - if (master_width * f->dst_w != f->src_w * 0x00200000) - master_width++; + master_width = (window->src_w * 0x00200000) / (window->dst_w); + if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -267,17 +264,17 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * /* We also need to factor in the scaling (src_w - dst_w) / (src_w / 4) */ - if (f->dst_w > f->src_w) - reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14); + if (window->dst_w > window->src_w) + reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14); else reg_2870_base = 0; reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); reg_2874 = 0; - } else if (f->dst_w < f->src_w / 2) { - master_width = (f->src_w * 0x00080000) / f->dst_w; - if (master_width * f->dst_w != f->src_w * 0x00080000) - master_width++; + } + else if (window->dst_w < window->src_w / 2) { + master_width = (window->src_w * 0x00080000) / window->dst_w; + if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -285,13 +282,13 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * reg_2854 = master_width; reg_285c = master_width >> 1; reg_2864 = master_width >> 1; - reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset; - reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16; + reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset); + reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16; reg_2874 = 0x00000012; - } else { - master_width = (f->src_w * 0x00100000) / f->dst_w; - if (master_width * f->dst_w != f->src_w * 0x00100000) - master_width++; + } + else { + master_width = (window->src_w * 0x00100000) / window->dst_w; + if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -299,70 +296,62 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * reg_2854 = master_width; reg_285c = master_width >> 1; reg_2864 = master_width >> 1; - reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1; - reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16; + reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1); + reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16; reg_2874 = 0x00000001; } /* Select the horizontal filter */ - if (f->src_w == f->dst_w) { + if (window->src_w == window->dst_w) { /* An exact size match uses filter 0 */ h_filter = 0; - } else { + } + else { /* Figure out which filter to use */ - h_filter = ((f->src_w << 16) / f->dst_w) >> 15; + h_filter = ((window->src_w << 16) / window->dst_w) >> 15; h_filter = (h_filter >> 1) + (h_filter & 1); /* Only an exact size match can use filter 0 */ - h_filter += !h_filter; + if (h_filter == 0) h_filter = 1; } write_reg(reg_2834, 0x02834); write_reg(reg_2838, 0x02838); - IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n", - yi->reg_2834, reg_2834, yi->reg_2838, reg_2838); + IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838); write_reg(reg_283c, 0x0283c); write_reg(reg_2844, 0x02844); - IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n", - yi->reg_283c, reg_283c, yi->reg_2844, reg_2844); + IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844); write_reg(0x00080514, 0x02840); write_reg(0x00100514, 0x02848); - IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n", - yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514); + IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514); write_reg(reg_2854, 0x02854); - IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n", - yi->reg_2854, reg_2854); + IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854); write_reg(reg_285c, 0x0285c); write_reg(reg_2864, 0x02864); - IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n", - yi->reg_285c, reg_285c, yi->reg_2864, reg_2864); + IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864); write_reg(reg_2874, 0x02874); - IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n", - yi->reg_2874, reg_2874); + IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874); write_reg(reg_2870, 0x02870); - IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n", - yi->reg_2870, reg_2870); + IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870); - write_reg(reg_2890, 0x02890); - IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n", - yi->reg_2890, reg_2890); + write_reg( reg_2890,0x02890); + IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890); /* Only update the filter if we really need to */ - if (h_filter != yi->h_filter) { - ivtv_yuv_filter(itv, h_filter, -1, -1); - yi->h_filter = h_filter; + if (h_filter != itv->yuv_info.h_filter) { + ivtv_yuv_filter (itv,h_filter,-1,-1); + itv->yuv_info.h_filter = h_filter; } } -static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) +static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window) { - struct yuv_playback_info *yi = &itv->yuv_info; u32 master_height; u32 reg_2918, reg_291c, reg_2920, reg_2928; u32 reg_2930, reg_2934, reg_293c; @@ -370,59 +359,69 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) u32 reg_2950, reg_2954, reg_2958, reg_295c; u32 reg_2960, reg_2964, reg_2968, reg_296c; u32 reg_289c; - u32 src_major_y, src_minor_y; - u32 src_major_uv, src_minor_uv; + u32 src_y_major_y, src_y_minor_y; + u32 src_y_major_uv, src_y_minor_uv; u32 reg_2964_base, reg_2968_base; int v_filter_1, v_filter_2; - IVTV_DEBUG_WARN - ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", - f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y); + IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", + window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y); /* What scaling mode is being used... */ - IVTV_DEBUG_YUV("Scaling mode Y: %s\n", - f->interlaced_y ? "Interlaced" : "Progressive"); + if (window->interlaced_y) { + IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n"); + } + else { + IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n"); + } - IVTV_DEBUG_YUV("Scaling mode UV: %s\n", - f->interlaced_uv ? "Interlaced" : "Progressive"); + if (window->interlaced_uv) { + IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n"); + } + else { + IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n"); + } /* What is the source video being treated as... */ - IVTV_DEBUG_WARN("Source video: %s\n", - f->interlaced ? "Interlaced" : "Progressive"); + if (itv->yuv_info.frame_interlaced) { + IVTV_DEBUG_WARN("Source video: Interlaced\n"); + } + else { + IVTV_DEBUG_WARN("Source video: Non-interlaced\n"); + } /* We offset into the image using two different index methods, so split the y source coord into two parts. */ - if (f->src_y < 8) { - src_minor_uv = f->src_y; - src_major_uv = 0; - } else { - src_minor_uv = 8; - src_major_uv = f->src_y - 8; + if (window->src_y < 8) { + src_y_minor_uv = window->src_y; + src_y_major_uv = 0; + } + else { + src_y_minor_uv = 8; + src_y_major_uv = window->src_y - 8; } - src_minor_y = src_minor_uv; - src_major_y = src_major_uv; + src_y_minor_y = src_y_minor_uv; + src_y_major_y = src_y_major_uv; - if (f->offset_y) - src_minor_y += 16; + if (window->offset_y) src_y_minor_y += 16; - if (f->interlaced_y) - reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y); + if (window->interlaced_y) + reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y); else - reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1); + reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1); - if (f->interlaced_uv) - reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1); + if (window->interlaced_uv) + reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1); else - reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv); + reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv); - reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14; - reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14; + reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14; + reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14; - if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) { - master_height = (f->src_h * 0x00400000) / f->dst_h; - if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2) - master_height++; + if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) { + master_height = (window->src_h * 0x00400000) / window->dst_h; + if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++; reg_2920 = master_height >> 2; reg_2928 = master_height >> 3; reg_2930 = master_height; @@ -430,42 +429,45 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) reg_2964_base >>= 3; reg_2968_base >>= 3; reg_296c = 0x00000000; - } else if (f->dst_h >= f->src_h) { - master_height = (f->src_h * 0x00400000) / f->dst_h; + } + else if (window->dst_h >= window->src_h) { + master_height = (window->src_h * 0x00400000) / window->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; reg_2930 = master_height; reg_2940 = master_height >> 1; reg_296c = 0x00000000; - if (f->interlaced_y) { + if (window->interlaced_y) { reg_2964_base >>= 3; - } else { - reg_296c++; + } + else { + reg_296c ++; reg_2964_base >>= 2; } - if (f->interlaced_uv) - reg_2928 >>= 1; + if (window->interlaced_uv) reg_2928 >>= 1; reg_2968_base >>= 3; - } else if (f->dst_h >= f->src_h / 2) { - master_height = (f->src_h * 0x00200000) / f->dst_h; + } + else if (window->dst_h >= window->src_h / 2) { + master_height = (window->src_h * 0x00200000) / window->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; reg_2930 = master_height; reg_2940 = master_height; reg_296c = 0x00000101; - if (f->interlaced_y) { + if (window->interlaced_y) { reg_2964_base >>= 2; - } else { - reg_296c++; + } + else { + reg_296c ++; reg_2964_base >>= 1; } - if (f->interlaced_uv) - reg_2928 >>= 1; + if (window->interlaced_uv) reg_2928 >>= 1; reg_2968_base >>= 2; - } else { - master_height = (f->src_h * 0x00100000) / f->dst_h; + } + else { + master_height = (window->src_h * 0x00100000) / window->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; @@ -478,12 +480,13 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) /* FIXME These registers change depending on scaled / unscaled output We really need to work out what they should be */ - if (f->src_h == f->dst_h) { + if (window->src_h == window->dst_h){ reg_2934 = 0x00020000; reg_293c = 0x00100000; reg_2944 = 0x00040000; reg_294c = 0x000b0000; - } else { + } + else { reg_2934 = 0x00000FF0; reg_293c = 0x00000FF0; reg_2944 = 0x00000FF0; @@ -491,36 +494,34 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) } /* The first line to be displayed */ - reg_2950 = 0x00010000 + src_major_y; - if (f->interlaced_y) - reg_2950 += 0x00010000; + reg_2950 = 0x00010000 + src_y_major_y; + if (window->interlaced_y) reg_2950 += 0x00010000; reg_2954 = reg_2950 + 1; - reg_2958 = 0x00010000 + (src_major_y >> 1); - if (f->interlaced_uv) - reg_2958 += 0x00010000; + reg_2958 = 0x00010000 + (src_y_major_y >> 1); + if (window->interlaced_uv) reg_2958 += 0x00010000; reg_295c = reg_2958 + 1; - if (yi->decode_height == 480) + if (itv->yuv_info.decode_height == 480) reg_289c = 0x011e0017; else reg_289c = 0x01500017; - if (f->dst_y < 0) - reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1); + if (window->dst_y < 0) + reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1); else - reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1); + reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1); /* How much of the source to decode. Take into account the source offset */ - reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) | - (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15); + reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) | + ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15); /* Calculate correct value for register 2964 */ - if (f->src_h == f->dst_h) { + if (window->src_h == window->dst_h) reg_2964 = 1; - } else { - reg_2964 = 2 + ((f->dst_h << 1) / f->src_h); + else { + reg_2964 = 2 + ((window->dst_h << 1) / window->src_h); reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); } reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); @@ -535,246 +536,283 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) /* Deviate further from what it should be. I find the flicker headache inducing so try to reduce it slightly. Leave 2968 as-is otherwise colours foul. */ - if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h)) - reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2); + if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h)) + reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2); - if (!f->interlaced_y) - reg_2964 -= 0x00010001; - if (!f->interlaced_uv) - reg_2968 -= 0x00010001; + if (!window->interlaced_y) reg_2964 -= 0x00010001; + if (!window->interlaced_uv) reg_2968 -= 0x00010001; reg_2964 += ((reg_2964_base << 16) | reg_2964_base); reg_2968 += ((reg_2968_base << 16) | reg_2968_base); /* Select the vertical filter */ - if (f->src_h == f->dst_h) { + if (window->src_h == window->dst_h) { /* An exact size match uses filter 0/1 */ v_filter_1 = 0; v_filter_2 = 1; - } else { + } + else { /* Figure out which filter to use */ - v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15; + v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15; v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); /* Only an exact size match can use filter 0 */ - v_filter_1 += !v_filter_1; + if (v_filter_1 == 0) v_filter_1 = 1; v_filter_2 = v_filter_1; } write_reg(reg_2934, 0x02934); write_reg(reg_293c, 0x0293c); - IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n", - yi->reg_2934, reg_2934, yi->reg_293c, reg_293c); + IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c); write_reg(reg_2944, 0x02944); write_reg(reg_294c, 0x0294c); - IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n", - yi->reg_2944, reg_2944, yi->reg_294c, reg_294c); + IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c); /* Ensure 2970 is 0 (does it ever change ?) */ /* write_reg(0,0x02970); */ -/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */ +/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */ write_reg(reg_2930, 0x02938); write_reg(reg_2930, 0x02930); - IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n", - yi->reg_2930, reg_2930, yi->reg_2938, reg_2930); + IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930); write_reg(reg_2928, 0x02928); - write_reg(reg_2928 + 0x514, 0x0292C); - IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n", - yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514); + write_reg(reg_2928+0x514, 0x0292C); + IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514); write_reg(reg_2920, 0x02920); - write_reg(reg_2920 + 0x514, 0x02924); - IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n", - yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514); + write_reg(reg_2920+0x514, 0x02924); + IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920); - write_reg(reg_2918, 0x02918); - write_reg(reg_291c, 0x0291C); - IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n", - yi->reg_2918, reg_2918, yi->reg_291c, reg_291c); + write_reg (reg_2918,0x02918); + write_reg (reg_291c,0x0291C); + IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c); write_reg(reg_296c, 0x0296c); - IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n", - yi->reg_296c, reg_296c); + IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c); write_reg(reg_2940, 0x02948); write_reg(reg_2940, 0x02940); - IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n", - yi->reg_2940, reg_2940, yi->reg_2948, reg_2940); + IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940); write_reg(reg_2950, 0x02950); write_reg(reg_2954, 0x02954); - IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n", - yi->reg_2950, reg_2950, yi->reg_2954, reg_2954); + IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954); write_reg(reg_2958, 0x02958); write_reg(reg_295c, 0x0295C); - IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n", - yi->reg_2958, reg_2958, yi->reg_295c, reg_295c); + IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c); write_reg(reg_2960, 0x02960); - IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n", - yi->reg_2960, reg_2960); + IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960); write_reg(reg_2964, 0x02964); write_reg(reg_2968, 0x02968); - IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n", - yi->reg_2964, reg_2964, yi->reg_2968, reg_2968); + IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968); - write_reg(reg_289c, 0x0289c); - IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n", - yi->reg_289c, reg_289c); + write_reg( reg_289c,0x0289c); + IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c); /* Only update filter 1 if we really need to */ - if (v_filter_1 != yi->v_filter_1) { - ivtv_yuv_filter(itv, -1, v_filter_1, -1); - yi->v_filter_1 = v_filter_1; + if (v_filter_1 != itv->yuv_info.v_filter_1) { + ivtv_yuv_filter (itv,-1,v_filter_1,-1); + itv->yuv_info.v_filter_1 = v_filter_1; } /* Only update filter 2 if we really need to */ - if (v_filter_2 != yi->v_filter_2) { - ivtv_yuv_filter(itv, -1, -1, v_filter_2); - yi->v_filter_2 = v_filter_2; + if (v_filter_2 != itv->yuv_info.v_filter_2) { + ivtv_yuv_filter (itv,-1,-1,v_filter_2); + itv->yuv_info.v_filter_2 = v_filter_2; } + } /* Modify the supplied coordinate information to fit the visible osd area */ -static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) +static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window) { - struct yuv_frame_info *of = &itv->yuv_info.old_frame_info; - int osd_crop; + int osd_crop, lace_threshold; u32 osd_scale; u32 yuv_update = 0; + lace_threshold = itv->yuv_info.lace_threshold; + if (lace_threshold < 0) + lace_threshold = itv->yuv_info.decode_height - 1; + + /* Work out the lace settings */ + switch (itv->yuv_info.lace_mode) { + case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ + itv->yuv_info.frame_interlaced = 0; + if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021)) + window->interlaced_y = 0; + else + window->interlaced_y = 1; + + if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) + window->interlaced_uv = 0; + else + window->interlaced_uv = 1; + break; + + case IVTV_YUV_MODE_AUTO: + if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){ + itv->yuv_info.frame_interlaced = 0; + if ((window->tru_h < 512) || + (window->tru_h > 576 && window->tru_h < 1021) || + (window->tru_w > 720 && window->tru_h < 1021)) + window->interlaced_y = 0; + else + window->interlaced_y = 1; + + if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) + window->interlaced_uv = 0; + else + window->interlaced_uv = 1; + } + else { + itv->yuv_info.frame_interlaced = 1; + window->interlaced_y = 1; + window->interlaced_uv = 1; + } + break; + + case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ + default: + itv->yuv_info.frame_interlaced = 1; + window->interlaced_y = 1; + window->interlaced_uv = 1; + break; + } + /* Sorry, but no negative coords for src */ - if (f->src_x < 0) - f->src_x = 0; - if (f->src_y < 0) - f->src_y = 0; + if (window->src_x < 0) window->src_x = 0; + if (window->src_y < 0) window->src_y = 0; /* Can only reduce width down to 1/4 original size */ - if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) { - f->src_x += osd_crop / 2; - f->src_w = (f->src_w - osd_crop) & ~3; - f->dst_w = f->src_w / 4; - f->dst_w += f->dst_w & 1; + if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) { + window->src_x += osd_crop / 2; + window->src_w = (window->src_w - osd_crop) & ~3; + window->dst_w = window->src_w / 4; + window->dst_w += window->dst_w & 1; } /* Can only reduce height down to 1/4 original size */ - if (f->src_h / f->dst_h >= 2) { - /* Overflow may be because we're running progressive, - so force mode switch */ - f->interlaced_y = 1; + if (window->src_h / window->dst_h >= 2) { + /* Overflow may be because we're running progressive, so force mode switch */ + window->interlaced_y = 1; /* Make sure we're still within limits for interlace */ - if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) { + if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) { /* If we reach here we'll have to force the height. */ - f->src_y += osd_crop / 2; - f->src_h = (f->src_h - osd_crop) & ~3; - f->dst_h = f->src_h / 4; - f->dst_h += f->dst_h & 1; + window->src_y += osd_crop / 2; + window->src_h = (window->src_h - osd_crop) & ~3; + window->dst_h = window->src_h / 4; + window->dst_h += window->dst_h & 1; } } /* If there's nothing to safe to display, we may as well stop now */ - if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || - (int)f->src_w <= 2 || (int)f->src_h <= 2) { + if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Ensure video remains inside OSD area */ - osd_scale = (f->src_h << 16) / f->dst_h; + osd_scale = (window->src_h << 16) / window->dst_h; - if ((osd_crop = f->pan_y - f->dst_y) > 0) { + if ((osd_crop = window->pan_y - window->dst_y) > 0) { /* Falls off the upper edge - crop */ - f->src_y += (osd_scale * osd_crop) >> 16; - f->src_h -= (osd_scale * osd_crop) >> 16; - f->dst_h -= osd_crop; - f->dst_y = 0; - } else { - f->dst_y -= f->pan_y; + window->src_y += (osd_scale * osd_crop) >> 16; + window->src_h -= (osd_scale * osd_crop) >> 16; + window->dst_h -= osd_crop; + window->dst_y = 0; + } + else { + window->dst_y -= window->pan_y; } - if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) { + if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) { /* Falls off the lower edge - crop */ - f->dst_h -= osd_crop; - f->src_h -= (osd_scale * osd_crop) >> 16; + window->dst_h -= osd_crop; + window->src_h -= (osd_scale * osd_crop) >> 16; } - osd_scale = (f->src_w << 16) / f->dst_w; + osd_scale = (window->src_w << 16) / window->dst_w; - if ((osd_crop = f->pan_x - f->dst_x) > 0) { + if ((osd_crop = window->pan_x - window->dst_x) > 0) { /* Fall off the left edge - crop */ - f->src_x += (osd_scale * osd_crop) >> 16; - f->src_w -= (osd_scale * osd_crop) >> 16; - f->dst_w -= osd_crop; - f->dst_x = 0; - } else { - f->dst_x -= f->pan_x; + window->src_x += (osd_scale * osd_crop) >> 16; + window->src_w -= (osd_scale * osd_crop) >> 16; + window->dst_w -= osd_crop; + window->dst_x = 0; + } + else { + window->dst_x -= window->pan_x; } - if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) { + if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) { /* Falls off the right edge - crop */ - f->dst_w -= osd_crop; - f->src_w -= (osd_scale * osd_crop) >> 16; + window->dst_w -= osd_crop; + window->src_w -= (osd_scale * osd_crop) >> 16; } /* The OSD can be moved. Track to it */ - f->dst_x += itv->yuv_info.osd_x_offset; - f->dst_y += itv->yuv_info.osd_y_offset; + window->dst_x += itv->yuv_info.osd_x_offset; + window->dst_y += itv->yuv_info.osd_y_offset; /* Width & height for both src & dst must be even. Same for coordinates. */ - f->dst_w &= ~1; - f->dst_x &= ~1; + window->dst_w &= ~1; + window->dst_x &= ~1; - f->src_w += f->src_x & 1; - f->src_x &= ~1; + window->src_w += window->src_x & 1; + window->src_x &= ~1; - f->src_w &= ~1; - f->dst_w &= ~1; + window->src_w &= ~1; + window->dst_w &= ~1; - f->dst_h &= ~1; - f->dst_y &= ~1; + window->dst_h &= ~1; + window->dst_y &= ~1; - f->src_h += f->src_y & 1; - f->src_y &= ~1; + window->src_h += window->src_y & 1; + window->src_y &= ~1; - f->src_h &= ~1; - f->dst_h &= ~1; + window->src_h &= ~1; + window->dst_h &= ~1; - /* Due to rounding, we may have reduced the output size to <1/4 of - the source. Check again, but this time just resize. Don't change - source coordinates */ - if (f->dst_w < f->src_w / 4) { - f->src_w &= ~3; - f->dst_w = f->src_w / 4; - f->dst_w += f->dst_w & 1; + /* Due to rounding, we may have reduced the output size to <1/4 of the source + Check again, but this time just resize. Don't change source coordinates */ + if (window->dst_w < window->src_w / 4) { + window->src_w &= ~3; + window->dst_w = window->src_w / 4; + window->dst_w += window->dst_w & 1; } - if (f->dst_h < f->src_h / 4) { - f->src_h &= ~3; - f->dst_h = f->src_h / 4; - f->dst_h += f->dst_h & 1; + if (window->dst_h < window->src_h / 4) { + window->src_h &= ~3; + window->dst_h = window->src_h / 4; + window->dst_h += window->dst_h & 1; } /* Check again. If there's nothing to safe to display, stop now */ - if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || - (int)f->src_w <= 2 || (int)f->src_h <= 2) { + if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Both x offset & width are linked, so they have to be done together */ - if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) || - (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || - (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { + if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) || + (itv->yuv_info.old_frame_info.src_w != window->src_w) || + (itv->yuv_info.old_frame_info.dst_x != window->dst_x) || + (itv->yuv_info.old_frame_info.src_x != window->src_x) || + (itv->yuv_info.old_frame_info.pan_x != window->pan_x) || + (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) { yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; } - if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) || - (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || - (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || - (of->lace_mode != f->lace_mode) || - (of->interlaced_y != f->interlaced_y) || - (of->interlaced_uv != f->interlaced_uv)) { + if ((itv->yuv_info.old_frame_info.src_h != window->src_h) || + (itv->yuv_info.old_frame_info.dst_h != window->dst_h) || + (itv->yuv_info.old_frame_info.dst_y != window->dst_y) || + (itv->yuv_info.old_frame_info.src_y != window->src_y) || + (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || + (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || + (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || + (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || + (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; } @@ -782,24 +820,24 @@ static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) } /* Update the scaling register to the requested value */ -void ivtv_yuv_work_handler(struct ivtv *itv) +void ivtv_yuv_work_handler (struct ivtv *itv) { - struct yuv_playback_info *yi = &itv->yuv_info; - struct yuv_frame_info f; - int frame = yi->update_frame; + struct yuv_frame_info window; u32 yuv_update; - IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame); - f = yi->new_frame_info[frame]; + int frame = itv->yuv_info.update_frame; + +/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ + memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window)); /* Update the osd pan info */ - f.pan_x = yi->osd_x_pan; - f.pan_y = yi->osd_y_pan; - f.vis_w = yi->osd_vis_w; - f.vis_h = yi->osd_vis_h; + window.pan_x = itv->yuv_info.osd_x_pan; + window.pan_y = itv->yuv_info.osd_y_pan; + window.vis_w = itv->yuv_info.osd_vis_w; + window.vis_h = itv->yuv_info.osd_vis_h; /* Calculate the display window coordinates. Exit if nothing left */ - if (!(yuv_update = ivtv_yuv_window_setup(itv, &f))) + if (!(yuv_update = ivtv_yuv_window_setup (itv, &window))) return; if (yuv_update & IVTV_YUV_UPDATE_INVALID) { @@ -808,15 +846,16 @@ void ivtv_yuv_work_handler(struct ivtv *itv) write_reg(0x00108080, 0x2898); if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) - ivtv_yuv_handle_horizontal(itv, &f); + ivtv_yuv_handle_horizontal(itv, &window); if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) - ivtv_yuv_handle_vertical(itv, &f); + ivtv_yuv_handle_vertical(itv, &window); } - yi->old_frame_info = f; + + memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info)); } -static void ivtv_yuv_init(struct ivtv *itv) +static void ivtv_yuv_init (struct ivtv *itv) { struct yuv_playback_info *yi = &itv->yuv_info; @@ -885,23 +924,25 @@ static void ivtv_yuv_init(struct ivtv *itv) if (!yi->osd_vis_w) yi->osd_vis_w = 720 - yi->osd_x_offset; - if (!yi->osd_vis_h) { + if (!yi->osd_vis_h) yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { + else { /* If output video standard has changed, requested height may - not be legal */ - IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", - yi->osd_vis_h + yi->osd_y_offset, - yi->decode_height); - yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; + not be legal */ + if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { + IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", + yi->osd_vis_h + yi->osd_y_offset, + yi->decode_height); + yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; + } } } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ - yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL); - if (yi->blanking_ptr) { + yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL); + if (yi->blanking_ptr) yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); - } else { + else { yi->blanking_dmaptr = 0; IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); } @@ -913,140 +954,77 @@ static void ivtv_yuv_init(struct ivtv *itv) atomic_set(&yi->next_dma_frame, 0); } -/* Get next available yuv buffer on PVR350 */ -void ivtv_yuv_next_free(struct ivtv *itv) +int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) { - int draw, display; - struct yuv_playback_info *yi = &itv->yuv_info; - - if (atomic_read(&yi->next_dma_frame) == -1) - ivtv_yuv_init(itv); - - draw = atomic_read(&yi->next_fill_frame); - display = atomic_read(&yi->next_dma_frame); - - if (display > draw) - display -= IVTV_YUV_BUFFERS; + DEFINE_WAIT(wait); + int rc = 0; + int got_sig = 0; + int frame, next_fill_frame, last_fill_frame; + int register_update = 0; - if (draw - display >= yi->max_frames_buffered) - draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS; - else - yi->new_frame_info[draw].update = 0; + IVTV_DEBUG_INFO("yuv_prep_frame\n"); - yi->draw_frame = draw; -} + if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); -/* Set up frame according to ivtv_dma_frame parameters */ -void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - u8 frame = yi->draw_frame; - u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS; - struct yuv_frame_info *nf = &yi->new_frame_info[frame]; - struct yuv_frame_info *of = &yi->new_frame_info[last_frame]; - int lace_threshold = yi->lace_threshold; + frame = atomic_read(&itv->yuv_info.next_fill_frame); + next_fill_frame = (frame + 1) & 0x3; + last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; - /* Preserve old update flag in case we're overwriting a queued frame */ - int update = nf->update; + if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { + /* Buffers are full - Overwrite the last frame */ + next_fill_frame = frame; + frame = (frame - 1) & 3; + register_update = itv->yuv_info.new_frame_info[frame].update; + } /* Take a snapshot of the yuv coordinate information */ - nf->src_x = args->src.left; - nf->src_y = args->src.top; - nf->src_w = args->src.width; - nf->src_h = args->src.height; - nf->dst_x = args->dst.left; - nf->dst_y = args->dst.top; - nf->dst_w = args->dst.width; - nf->dst_h = args->dst.height; - nf->tru_x = args->dst.left; - nf->tru_w = args->src_width; - nf->tru_h = args->src_height; + itv->yuv_info.new_frame_info[frame].src_x = args->src.left; + itv->yuv_info.new_frame_info[frame].src_y = args->src.top; + itv->yuv_info.new_frame_info[frame].src_w = args->src.width; + itv->yuv_info.new_frame_info[frame].src_h = args->src.height; + itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; + itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; + itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; + itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; + itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; + itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; + itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; + + /* Snapshot field order */ + itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; /* Are we going to offset the Y plane */ - nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0; + if (args->src.height + args->src.top < 512-16) + itv->yuv_info.new_frame_info[frame].offset_y = 1; + else + itv->yuv_info.new_frame_info[frame].offset_y = 0; /* Snapshot the osd pan info */ - nf->pan_x = yi->osd_x_pan; - nf->pan_y = yi->osd_y_pan; - nf->vis_w = yi->osd_vis_w; - nf->vis_h = yi->osd_vis_h; - - nf->update = 0; - nf->interlaced_y = 0; - nf->interlaced_uv = 0; - nf->delay = 0; - nf->sync_field = 0; - nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; - - if (lace_threshold < 0) - lace_threshold = yi->decode_height - 1; - - /* Work out the lace settings */ - switch (nf->lace_mode) { - case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ - nf->interlaced = 0; - if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021)) - nf->interlaced_y = 0; - else - nf->interlaced_y = 1; - - if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) - nf->interlaced_uv = 0; - else - nf->interlaced_uv = 1; - break; - - case IVTV_YUV_MODE_AUTO: - if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) { - nf->interlaced = 0; - if ((nf->tru_h < 512) || - (nf->tru_h > 576 && nf->tru_h < 1021) || - (nf->tru_w > 720 && nf->tru_h < 1021)) - nf->interlaced_y = 0; - else - nf->interlaced_y = 1; - if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) - nf->interlaced_uv = 0; - else - nf->interlaced_uv = 1; - } else { - nf->interlaced = 1; - nf->interlaced_y = 1; - nf->interlaced_uv = 1; - } - break; - - case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ - default: - nf->interlaced = 1; - nf->interlaced_y = 1; - nf->interlaced_uv = 1; - break; + itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; + itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; + itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; + itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; + + itv->yuv_info.new_frame_info[frame].update = 0; + itv->yuv_info.new_frame_info[frame].interlaced_y = 0; + itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; + itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; + + if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], + sizeof (itv->yuv_info.new_frame_info[frame]))) { + memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); + itv->yuv_info.new_frame_info[frame].update = 1; +/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ } - if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) { - yi->old_frame_info_args = *nf; - nf->update = 1; - IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame); - } + itv->yuv_info.new_frame_info[frame].update |= register_update; - nf->update |= update; - nf->sync_field = yi->lace_sync_field; - nf->delay = nf->sync_field != of->sync_field; -} - -/* Frame is complete & ready for display */ -void ivtv_yuv_frame_complete(struct ivtv *itv) -{ - atomic_set(&itv->yuv_info.next_fill_frame, - (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); -} + /* Should this frame be delayed ? */ + if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) + itv->yuv_info.field_delay[frame] = 1; + else + itv->yuv_info.field_delay[frame] = 0; -int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) -{ - DEFINE_WAIT(wait); - int rc = 0; - int got_sig = 0; /* DMA the frame */ mutex_lock(&itv->udma.lock); @@ -1058,10 +1036,10 @@ int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) ivtv_udma_prepare(itv); prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ + is finished */ while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ + a still pending DMA. */ got_sig = signal_pending(current); if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) break; @@ -1079,148 +1057,99 @@ int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) return -EINTR; } - ivtv_yuv_frame_complete(itv); + atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); mutex_unlock(&itv->udma.lock); return rc; } -/* Setup frame according to V4L2 parameters */ -void ivtv_yuv_setup_stream_frame(struct ivtv *itv) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - struct ivtv_dma_frame dma_args; - - ivtv_yuv_next_free(itv); - - /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ - dma_args.y_source = 0L; - dma_args.uv_source = 0L; - dma_args.src.left = 0; - dma_args.src.top = 0; - dma_args.src.width = yi->v4l2_src_w; - dma_args.src.height = yi->v4l2_src_h; - dma_args.dst = yi->main_rect; - dma_args.src_width = yi->v4l2_src_w; - dma_args.src_height = yi->v4l2_src_h; - - /* ... and use the same setup routine as ivtv_yuv_prep_frame */ - ivtv_yuv_setup_frame(itv, &dma_args); - - if (!itv->dma_data_req_offset) - itv->dma_data_req_offset = yuv_offset[yi->draw_frame]; -} - -/* Attempt to dma a frame from a user buffer */ -int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src) -{ - struct yuv_playback_info *yi = &itv->yuv_info; - struct ivtv_dma_frame dma_args; - - ivtv_yuv_setup_stream_frame(itv); - - /* We only need to supply source addresses for this */ - dma_args.y_source = src; - dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31); - return ivtv_yuv_udma_frame(itv, &dma_args); -} - -/* IVTV_IOC_DMA_FRAME ioctl handler */ -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) -{ -/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ - - ivtv_yuv_next_free(itv); - ivtv_yuv_setup_frame(itv, args); - return ivtv_yuv_udma_frame(itv, args); -} - void ivtv_yuv_close(struct ivtv *itv) { - struct yuv_playback_info *yi = &itv->yuv_info; int h_filter, v_filter_1, v_filter_2; IVTV_DEBUG_YUV("ivtv_yuv_close\n"); ivtv_waitq(&itv->vsync_waitq); - atomic_set(&yi->next_dma_frame, -1); - atomic_set(&yi->next_fill_frame, 0); + atomic_set(&itv->yuv_info.next_dma_frame, -1); + atomic_set(&itv->yuv_info.next_fill_frame, 0); /* Reset registers we have changed so mpeg playback works */ /* If we fully restore this register, the display may remain active. Restore, but set one bit to blank the video. Firmware will always clear this bit when needed, so not a problem. */ - write_reg(yi->reg_2898 | 0x01000000, 0x2898); - - write_reg(yi->reg_2834, 0x02834); - write_reg(yi->reg_2838, 0x02838); - write_reg(yi->reg_283c, 0x0283c); - write_reg(yi->reg_2840, 0x02840); - write_reg(yi->reg_2844, 0x02844); - write_reg(yi->reg_2848, 0x02848); - write_reg(yi->reg_2854, 0x02854); - write_reg(yi->reg_285c, 0x0285c); - write_reg(yi->reg_2864, 0x02864); - write_reg(yi->reg_2870, 0x02870); - write_reg(yi->reg_2874, 0x02874); - write_reg(yi->reg_2890, 0x02890); - write_reg(yi->reg_289c, 0x0289c); - - write_reg(yi->reg_2918, 0x02918); - write_reg(yi->reg_291c, 0x0291c); - write_reg(yi->reg_2920, 0x02920); - write_reg(yi->reg_2924, 0x02924); - write_reg(yi->reg_2928, 0x02928); - write_reg(yi->reg_292c, 0x0292c); - write_reg(yi->reg_2930, 0x02930); - write_reg(yi->reg_2934, 0x02934); - write_reg(yi->reg_2938, 0x02938); - write_reg(yi->reg_293c, 0x0293c); - write_reg(yi->reg_2940, 0x02940); - write_reg(yi->reg_2944, 0x02944); - write_reg(yi->reg_2948, 0x02948); - write_reg(yi->reg_294c, 0x0294c); - write_reg(yi->reg_2950, 0x02950); - write_reg(yi->reg_2954, 0x02954); - write_reg(yi->reg_2958, 0x02958); - write_reg(yi->reg_295c, 0x0295c); - write_reg(yi->reg_2960, 0x02960); - write_reg(yi->reg_2964, 0x02964); - write_reg(yi->reg_2968, 0x02968); - write_reg(yi->reg_296c, 0x0296c); - write_reg(yi->reg_2970, 0x02970); + write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898); + + write_reg(itv->yuv_info.reg_2834, 0x02834); + write_reg(itv->yuv_info.reg_2838, 0x02838); + write_reg(itv->yuv_info.reg_283c, 0x0283c); + write_reg(itv->yuv_info.reg_2840, 0x02840); + write_reg(itv->yuv_info.reg_2844, 0x02844); + write_reg(itv->yuv_info.reg_2848, 0x02848); + write_reg(itv->yuv_info.reg_2854, 0x02854); + write_reg(itv->yuv_info.reg_285c, 0x0285c); + write_reg(itv->yuv_info.reg_2864, 0x02864); + write_reg(itv->yuv_info.reg_2870, 0x02870); + write_reg(itv->yuv_info.reg_2874, 0x02874); + write_reg(itv->yuv_info.reg_2890, 0x02890); + write_reg(itv->yuv_info.reg_289c, 0x0289c); + + write_reg(itv->yuv_info.reg_2918, 0x02918); + write_reg(itv->yuv_info.reg_291c, 0x0291c); + write_reg(itv->yuv_info.reg_2920, 0x02920); + write_reg(itv->yuv_info.reg_2924, 0x02924); + write_reg(itv->yuv_info.reg_2928, 0x02928); + write_reg(itv->yuv_info.reg_292c, 0x0292c); + write_reg(itv->yuv_info.reg_2930, 0x02930); + write_reg(itv->yuv_info.reg_2934, 0x02934); + write_reg(itv->yuv_info.reg_2938, 0x02938); + write_reg(itv->yuv_info.reg_293c, 0x0293c); + write_reg(itv->yuv_info.reg_2940, 0x02940); + write_reg(itv->yuv_info.reg_2944, 0x02944); + write_reg(itv->yuv_info.reg_2948, 0x02948); + write_reg(itv->yuv_info.reg_294c, 0x0294c); + write_reg(itv->yuv_info.reg_2950, 0x02950); + write_reg(itv->yuv_info.reg_2954, 0x02954); + write_reg(itv->yuv_info.reg_2958, 0x02958); + write_reg(itv->yuv_info.reg_295c, 0x0295c); + write_reg(itv->yuv_info.reg_2960, 0x02960); + write_reg(itv->yuv_info.reg_2964, 0x02964); + write_reg(itv->yuv_info.reg_2968, 0x02968); + write_reg(itv->yuv_info.reg_296c, 0x0296c); + write_reg(itv->yuv_info.reg_2970, 0x02970); /* Prepare to restore filters */ /* First the horizontal filter */ - if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) { + if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) { /* An exact size match uses filter 0 */ h_filter = 0; - } else { + } + else { /* Figure out which filter to use */ - h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15; + h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15; h_filter = (h_filter >> 1) + (h_filter & 1); /* Only an exact size match can use filter 0. */ - h_filter += !h_filter; + if (h_filter < 1) h_filter = 1; } /* Now the vertical filter */ - if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) { + if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) { /* An exact size match uses filter 0/1 */ v_filter_1 = 0; v_filter_2 = 1; - } else { + } + else { /* Figure out which filter to use */ - v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15; + v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15; v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); /* Only an exact size match can use filter 0 */ - v_filter_1 += !v_filter_1; + if (v_filter_1 == 0) v_filter_1 = 1; v_filter_2 = v_filter_1; } /* Now restore the filters */ - ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2); + ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2); /* and clear a few registers */ write_reg(0, 0x02814); @@ -1229,18 +1158,19 @@ void ivtv_yuv_close(struct ivtv *itv) write_reg(0, 0x02910); /* Release the blanking buffer */ - if (yi->blanking_ptr) { - kfree(yi->blanking_ptr); - yi->blanking_ptr = NULL; - pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); + if (itv->yuv_info.blanking_ptr) { + kfree (itv->yuv_info.blanking_ptr); + itv->yuv_info.blanking_ptr = NULL; + pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); } /* Invalidate the old dimension information */ - yi->old_frame_info.src_w = 0; - yi->old_frame_info.src_h = 0; - yi->old_frame_info_args.src_w = 0; - yi->old_frame_info_args.src_h = 0; + itv->yuv_info.old_frame_info.src_w = 0; + itv->yuv_info.old_frame_info.src_h = 0; + itv->yuv_info.old_frame_info_args.src_w = 0; + itv->yuv_info.old_frame_info_args.src_h = 0; /* All done. */ clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); } + diff --git a/trunk/drivers/media/video/ivtv/ivtv-yuv.h b/trunk/drivers/media/video/ivtv/ivtv-yuv.h index 2fe5f1250762..3b966f0a204a 100644 --- a/trunk/drivers/media/video/ivtv/ivtv-yuv.h +++ b/trunk/drivers/media/video/ivtv/ivtv-yuv.h @@ -21,6 +21,11 @@ #ifndef IVTV_YUV_H #define IVTV_YUV_H +/* Buffers on hardware offsets */ +#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ +#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ /* Offset to filter table in firmware */ @@ -31,14 +36,11 @@ #define IVTV_YUV_UPDATE_VERTICAL 0x02 #define IVTV_YUV_UPDATE_INVALID 0x04 -extern const u32 yuv_offset[IVTV_YUV_BUFFERS]; +extern const u32 yuv_offset[4]; int ivtv_yuv_filter_check(struct ivtv *itv); -void ivtv_yuv_setup_stream_frame(struct ivtv *itv); -int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src); -void ivtv_yuv_frame_complete(struct ivtv *itv); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); void ivtv_yuv_close(struct ivtv *itv); -void ivtv_yuv_work_handler(struct ivtv *itv); +void ivtv_yuv_work_handler (struct ivtv *itv); #endif diff --git a/trunk/drivers/media/video/ivtv/ivtvfb.c b/trunk/drivers/media/video/ivtv/ivtvfb.c index 3b23fc05f7c4..52ffd154a3d8 100644 --- a/trunk/drivers/media/video/ivtv/ivtvfb.c +++ b/trunk/drivers/media/video/ivtv/ivtvfb.c @@ -504,10 +504,6 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtvfb_set_display_window(itv, &ivtv_window); - /* Pass screen size back to yuv handler */ - itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride; - itv->yuv_info.osd_full_h = ivtv_osd.lines; - /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; @@ -1057,7 +1053,7 @@ static int ivtvfb_init_card(struct ivtv *itv) } itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); - if (itv->osd_info == NULL) { + if (itv->osd_info == 0) { IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; } diff --git a/trunk/drivers/media/video/m52790.c b/trunk/drivers/media/video/m52790.c deleted file mode 100644 index d4bf14c284ef..000000000000 --- a/trunk/drivers/media/video/m52790.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * m52790 i2c ivtv driver. - * Copyright (C) 2007 Hans Verkuil - * - * A/V source switching Mitsubishi M52790SP/FP - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL"); - - -struct m52790_state { - u16 input; - u16 output; -}; - -/* ----------------------------------------------------------------------- */ - -static int m52790_write(struct i2c_client *client) -{ - struct m52790_state *state = i2c_get_clientdata(client); - u8 sw1 = (state->input | state->output) & 0xff; - u8 sw2 = (state->input | state->output) >> 8; - - return i2c_smbus_write_byte_data(client, sw1, sw2); -} - -static int m52790_command(struct i2c_client *client, unsigned int cmd, - void *arg) -{ - struct m52790_state *state = i2c_get_clientdata(client); - struct v4l2_routing *route = arg; - - /* Note: audio and video are linked and cannot be switched separately. - So audio and video routing commands are identical for this chip. - In theory the video amplifier and audio modes could be handled - separately for the output, but that seems to be overkill right now. - The same holds for implementing an audio mute control, this is now - part of the audio output routing. The normal case is that another - chip takes care of the actual muting so making it part of the - output routing seems to be the right thing to do for now. */ - switch (cmd) { - case VIDIOC_INT_G_AUDIO_ROUTING: - case VIDIOC_INT_G_VIDEO_ROUTING: - route->input = state->input; - route->output = state->output; - break; - - case VIDIOC_INT_S_AUDIO_ROUTING: - case VIDIOC_INT_S_VIDEO_ROUTING: - state->input = route->input; - state->output = route->output; - m52790_write(client); - break; - -#ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_register *reg = arg; - - if (!v4l2_chip_match_i2c_client(client, - reg->match_type, reg->match_chip)) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (reg->reg != 0) - return -EINVAL; - if (cmd == VIDIOC_DBG_G_REGISTER) - reg->val = state->input | state->output; - else { - state->input = reg->val & 0x0303; - state->output = reg->val & ~0x0303; - m52790_write(client); - } - break; - } -#endif - - case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, - V4L2_IDENT_M52790, 0); - - case VIDIOC_LOG_STATUS: - v4l_info(client, "Switch 1: %02x\n", - (state->input | state->output) & 0xff); - v4l_info(client, "Switch 2: %02x\n", - (state->input | state->output) >> 8); - break; - - default: - return -EINVAL; - } - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ - -static int m52790_probe(struct i2c_client *client) -{ - struct m52790_state *state; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - snprintf(client->name, sizeof(client->name) - 1, "m52790"); - - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); - - state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - - state->input = M52790_IN_TUNER; - state->output = M52790_OUT_STEREO; - i2c_set_clientdata(client, state); - m52790_write(client); - return 0; -} - -static int m52790_remove(struct i2c_client *client) -{ - kfree(i2c_get_clientdata(client)); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "m52790", - .driverid = I2C_DRIVERID_M52790, - .command = m52790_command, - .probe = m52790_probe, - .remove = m52790_remove, -}; - diff --git a/trunk/drivers/media/video/meye.c b/trunk/drivers/media/video/meye.c index 3d51fa0a52b6..c31163290432 100644 --- a/trunk/drivers/media/video/meye.c +++ b/trunk/drivers/media/video/meye.c @@ -2023,7 +2023,7 @@ static int __init meye_init(void) if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) gbufsize = MEYE_MAX_BUFSIZE; gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " + printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)" "for capture\n", gbuffers, gbufsize / 1024, gbuffers * gbufsize / 1024); diff --git a/trunk/drivers/media/video/msp3400-driver.c b/trunk/drivers/media/video/msp3400-driver.c index 7a11f3159e32..c0c87e06259b 100644 --- a/trunk/drivers/media/video/msp3400-driver.c +++ b/trunk/drivers/media/video/msp3400-driver.c @@ -42,8 +42,7 @@ * * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -54,7 +53,6 @@ #include #include #include -#include #include #include #include @@ -73,8 +71,7 @@ int msp_debug; /* msp_debug output */ int msp_once; /* no continous stereo monitoring */ int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ -int msp_standard = 1; /* Override auto detect of audio msp_standard, - if needed. */ +int msp_standard = 1; /* Override auto detect of audio msp_standard, if needed. */ int msp_dolby; int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual @@ -84,12 +81,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual module_param(opmode, int, 0444); /* read-write */ -module_param_named(once, msp_once, bool, 0644); -module_param_named(debug, msp_debug, int, 0644); -module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); -module_param_named(standard, msp_standard, int, 0644); -module_param_named(amsound, msp_amsound, bool, 0644); -module_param_named(dolby, msp_dolby, bool, 0644); +module_param_named(once,msp_once, bool, 0644); +module_param_named(debug,msp_debug, int, 0644); +module_param_named(stereo_threshold,msp_stereo_thresh, int, 0644); +module_param_named(standard,msp_standard, int, 0644); +module_param_named(amsound,msp_amsound, bool, 0644); +module_param_named(dolby,msp_dolby, bool, 0644); MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); MODULE_PARM_DESC(once, "No continuous stereo monitoring"); @@ -163,13 +160,12 @@ static int msp_read(struct i2c_client *client, int dev, int addr) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "resetting chip, sound will go off.\n"); + v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); msp_reset(client); return -1; } retval = read[0] << 8 | read[1]; - v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", - dev, addr, retval); + v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); return retval; } @@ -194,8 +190,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) buffer[3] = val >> 8; buffer[4] = val & 0xff; - v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", - dev, addr, val); + v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); for (err = 0; err < 3; err++) { if (i2c_master_send(client, buffer, 5) == 5) break; @@ -204,7 +199,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "resetting chip, sound will go off.\n"); + v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); msp_reset(client); return -1; } @@ -278,7 +273,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) state->acb = 0xf60; /* Mute Input and SCART 1 Output */ v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, state->acb); + scart_names[in], out, state->acb); msp_write_dsp(client, 0x13, state->acb); /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ @@ -297,8 +292,7 @@ void msp_set_audio(struct i2c_client *client) val = (state->volume * 0x7f / 65535) << 8; v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", - state->muted ? "on" : "off", - state->scan_in_progress ? "yes" : "no", + state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no", state->volume); msp_write_dsp(client, 0x0000, val); @@ -687,14 +681,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a); switch (*a) { - case 1024000: - state->i2s_mode = 0; - break; - case 2048000: - state->i2s_mode = 1; - break; - default: - return -EINVAL; + case 1024000: + state->i2s_mode = 0; + break; + case 2048000: + state->i2s_mode = 1; + break; + default: + return -EINVAL; } break; } @@ -704,22 +698,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_queryctrl *qc = arg; switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill_std(qc); - default: - break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill_std(qc); + default: + break; } if (!state->has_sound_processing) return -EINVAL; switch (qc->id) { - case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); - default: - return -EINVAL; + case V4L2_CID_AUDIO_LOUDNESS: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill_std(qc); + default: + return -EINVAL; } } @@ -741,14 +735,13 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) state->volume, state->muted ? " (muted)" : ""); if (state->has_sound_processing) { v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", - state->balance, state->bass, - state->treble, + state->balance, state->bass, state->treble, state->loudness ? "on" : "off"); } switch (state->mode) { case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; case MSP_MODE_FM_RADIO: p = "FM Radio"; break; - case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; + case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break; case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; @@ -779,8 +772,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, - (state->rev1 << 16) | state->rev2); + return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2); default: /* unknown */ @@ -791,6 +783,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) static int msp_suspend(struct i2c_client *client, pm_message_t state) { + v4l_dbg(1, msp_debug, client, "suspend\n"); msp_reset(client); return 0; @@ -798,6 +791,7 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state) static int msp_resume(struct i2c_client *client) { + v4l_dbg(1, msp_debug, client, "resume\n"); msp_wake_thread(client); return 0; @@ -805,8 +799,11 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static int msp_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int msp_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct msp_state *state; int (*thread_func)(void *data) = NULL; int msp_hard; @@ -815,16 +812,26 @@ static int msp_probe(struct i2c_client *client) int msp_product, msp_prod_hi, msp_prod_lo; int msp_rom; + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "msp3400"); if (msp_reset(client) == -1) { v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); - return -ENODEV; + kfree(client); + return 0; } state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) + if (!state) { + kfree(client); return -ENOMEM; + } i2c_set_clientdata(client, state); @@ -846,13 +853,12 @@ static int msp_probe(struct i2c_client *client) state->rev1 = msp_read_dsp(client, 0x1e); if (state->rev1 != -1) state->rev2 = msp_read_dsp(client, 0x1f); - v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", - state->rev1, state->rev2); + v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - v4l_dbg(1, msp_debug, client, - "not an msp3400 (cannot read chip version)\n"); + v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n"); kfree(state); - return -ENODEV; + kfree(client); + return 0; } msp_set_audio(client); @@ -868,55 +874,37 @@ static int msp_probe(struct i2c_client *client) msp_family, msp_product, msp_revision, msp_hard, msp_rom); /* Rev B=2, C=3, D=4, G=7 */ - state->ident = msp_family * 10000 + 4000 + msp_product * 10 + - msp_revision - '@'; + state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ - state->has_nicam = - msp_prod_hi == 1 || msp_prod_hi == 5; + state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; /* Has radio support: was added with revision G */ - state->has_radio = - msp_revision >= 'G'; + state->has_radio = msp_revision >= 'G'; /* Has headphones output: not for stripped down products */ - state->has_headphones = - msp_prod_lo < 5; + state->has_headphones = msp_prod_lo < 5; /* Has scart2 input: not in stripped down products of the '3' family */ - state->has_scart2 = - msp_family >= 4 || msp_prod_lo < 7; + state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7; /* Has scart3 input: not in stripped down products of the '3' family */ - state->has_scart3 = - msp_family >= 4 || msp_prod_lo < 5; + state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5; /* Has scart4 input: not in pre D revisions, not in stripped D revs */ - state->has_scart4 = - msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); - /* Has scart2 output: not in stripped down products of - * the '3' family */ - state->has_scart2_out = - msp_family >= 4 || msp_prod_lo < 5; + state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); + /* Has scart2 output: not in stripped down products of the '3' family */ + state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5; /* Has scart2 a volume control? Not in pre-D revisions. */ - state->has_scart2_out_volume = - msp_revision > 'C' && state->has_scart2_out; + state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out; /* Has a configurable i2s out? */ - state->has_i2s_conf = - msp_revision >= 'G' && msp_prod_lo < 7; - /* Has subwoofer output: not in pre-D revs and not in stripped down - * products */ - state->has_subwoofer = - msp_revision >= 'D' && msp_prod_lo < 5; - /* Has soundprocessing (bass/treble/balance/loudness/equalizer): - * not in stripped down products */ - state->has_sound_processing = - msp_prod_lo < 7; + state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7; + /* Has subwoofer output: not in pre-D revs and not in stripped down products */ + state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5; + /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in + stripped down products */ + state->has_sound_processing = msp_prod_lo < 7; /* Has Virtual Dolby Surround: only in msp34x1 */ - state->has_virtual_dolby_surround = - msp_revision == 'G' && msp_prod_lo == 1; + state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1; /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ - state->has_dolby_pro_logic = - msp_revision == 'G' && msp_prod_lo == 2; - /* The msp343xG supports BTSC only and cannot do Automatic Standard - * Detection. */ - state->force_btsc = - msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; + state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2; + /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */ + state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; state->opmode = opmode; if (state->opmode == OPMODE_AUTO) { @@ -931,33 +919,32 @@ static int msp_probe(struct i2c_client *client) } /* hello world :-) */ - v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, - client->addr << 1, client->adapter->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); v4l_info(client, "%s ", client->name); if (state->has_nicam && state->has_radio) - printk(KERN_CONT "supports nicam and radio, "); + printk("supports nicam and radio, "); else if (state->has_nicam) - printk(KERN_CONT "supports nicam, "); + printk("supports nicam, "); else if (state->has_radio) - printk(KERN_CONT "supports radio, "); - printk(KERN_CONT "mode is "); + printk("supports radio, "); + printk("mode is "); /* version-specific initialization */ switch (state->opmode) { case OPMODE_MANUAL: - printk(KERN_CONT "manual"); + printk("manual"); thread_func = msp3400c_thread; break; case OPMODE_AUTODETECT: - printk(KERN_CONT "autodetect"); + printk("autodetect"); thread_func = msp3410d_thread; break; case OPMODE_AUTOSELECT: - printk(KERN_CONT "autodetect and autoselect"); + printk("autodetect and autoselect"); thread_func = msp34xxg_thread; break; } - printk(KERN_CONT "\n"); + printk("\n"); /* startup control thread if needed */ if (thread_func) { @@ -967,12 +954,24 @@ static int msp_probe(struct i2c_client *client) v4l_warn(client, "kernel_thread() failed\n"); msp_wake_thread(client); } + + /* done */ + i2c_attach_client(client); + return 0; } -static int msp_remove(struct i2c_client *client) +static int msp_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, msp_attach); + return 0; +} + +static int msp_detach(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); + int err; /* shutdown control thread */ if (state->kthread) { @@ -981,22 +980,43 @@ static int msp_remove(struct i2c_client *client) } msp_reset(client); + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(state); + kfree(client); return 0; } /* ----------------------------------------------------------------------- */ -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "msp3400", - .driverid = I2C_DRIVERID_MSP3400, - .command = msp_command, - .probe = msp_probe, - .remove = msp_remove, +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .id = I2C_DRIVERID_MSP3400, + .attach_adapter = msp_probe, + .detach_client = msp_detach, .suspend = msp_suspend, - .resume = msp_resume, + .resume = msp_resume, + .command = msp_command, + .driver = { + .name = "msp3400", + }, }; +static int __init msp3400_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit msp3400_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(msp3400_init_module); +module_exit(msp3400_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/trunk/drivers/media/video/msp3400-kthreads.c b/trunk/drivers/media/video/msp3400-kthreads.c index 61ec794a737e..d5ee2629121e 100644 --- a/trunk/drivers/media/video/msp3400-kthreads.c +++ b/trunk/drivers/media/video/msp3400-kthreads.c @@ -15,8 +15,7 @@ * * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -79,37 +78,37 @@ static struct msp3400c_init_data_dem { {75, 19, 36, 35, 39, 40}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0500, 0x0020, 0x3000 - }, { /* AM (for carrier detect / msp3410) */ + },{ /* AM (for carrier detect / msp3410) */ {-1, -1, -8, 2, 59, 126}, {-1, -1, -8, 2, 59, 126}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0100, 0x0020, 0x3000 - }, { /* FM Radio */ + },{ /* FM Radio */ {-8, -8, 4, 6, 78, 107}, {-8, -8, 4, 6, 78, 107}, MSP_CARRIER(10.7), MSP_CARRIER(10.7), 0x00d0, 0x0480, 0x0020, 0x3000 - }, { /* Terrestial FM-mono + FM-stereo */ + },{ /* Terrestial FM-mono + FM-stereo */ {3, 18, 27, 48, 66, 72}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0480, 0x0030, 0x3000 - }, { /* Sat FM-mono */ + },{ /* Sat FM-mono */ { 1, 9, 14, 24, 33, 37}, { 3, 18, 27, 48, 66, 72}, MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000 - }, { /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ + },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ {-2, -8, -10, 10, 50, 86}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000 - }, { /* NICAM/FM -- I (6.0/6.552) */ + },{ /* NICAM/FM -- I (6.0/6.552) */ {2, 4, -6, -4, 40, 94}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(6.0), MSP_CARRIER(6.0), 0x00d0, 0x0040, 0x0120, 0x3000 - }, { /* NICAM/AM -- L (6.5/5.85) */ + },{ /* NICAM/AM -- L (6.5/5.85) */ {-2, -8, -10, 10, 50, 86}, {-4, -12, -9, 23, 79, 126}, MSP_CARRIER(6.5), MSP_CARRIER(6.5), @@ -225,9 +224,7 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) nor do they support stereo BTSC. */ static void msp3400c_set_audmode(struct i2c_client *client) { - static char *strmode[] = { - "mono", "stereo", "lang2", "lang1", "lang1+lang2" - }; + static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" }; struct msp_state *state = i2c_get_clientdata(client); char *modestr = (state->audmode >= 0 && state->audmode < 5) ? strmode[state->audmode] : "unknown"; @@ -301,23 +298,19 @@ static void msp3400c_set_audmode(struct i2c_client *client) case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - v4l_dbg(1, msp_debug, client, - "NICAM set_audmode: %s\n", modestr); + v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); if (state->nicam_on) src = 0x0100; /* NICAM */ break; case MSP_MODE_BTSC: - v4l_dbg(1, msp_debug, client, - "BTSC set_audmode: %s\n", modestr); + v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr); break; case MSP_MODE_EXTERN: - v4l_dbg(1, msp_debug, client, - "extern set_audmode: %s\n", modestr); + v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr); src = 0x0200; /* SCART */ break; case MSP_MODE_FM_RADIO: - v4l_dbg(1, msp_debug, client, - "FM-Radio set_audmode: %s\n", modestr); + v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr); break; default: v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); @@ -349,8 +342,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) src |= 0x0010; break; } - v4l_dbg(1, msp_debug, client, - "set_audmode final source/matrix = 0x%x\n", src); + v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src); msp_set_source(client, src); } @@ -359,26 +351,22 @@ static void msp3400c_print_mode(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - if (state->main == state->second) - v4l_dbg(1, msp_debug, client, - "mono sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); - else - v4l_dbg(1, msp_debug, client, - "main sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); + if (state->main == state->second) { + v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + } else { + v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + } if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) - v4l_dbg(1, msp_debug, client, - "NICAM/FM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second/910) % 1000); + v4l_dbg(1, msp_debug, client, "NICAM/FM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second/910) % 1000); if (state->mode == MSP_MODE_AM_NICAM) - v4l_dbg(1, msp_debug, client, - "NICAM/AM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); + v4l_dbg(1, msp_debug, client, "NICAM/AM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { - v4l_dbg(1, msp_debug, client, - "FM-stereo carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); + v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); } } @@ -397,8 +385,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client) val = msp_read_dsp(client, 0x18); if (val > 32767) val -= 65536; - v4l_dbg(2, msp_debug, client, - "stereo detect register: %d\n", val); + v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val); if (val > 8192) { rxsubchans = V4L2_TUNER_SUB_STEREO; } else if (val < -4096) { @@ -443,8 +430,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client) } if (rxsubchans != state->rxsubchans) { update = 1; - v4l_dbg(1, msp_debug, client, - "watch: rxsubchans %02x => %02x\n", + v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n", state->rxsubchans, rxsubchans); state->rxsubchans = rxsubchans; } @@ -466,8 +452,9 @@ static void watch_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - if (msp_detect_stereo(client)) + if (msp_detect_stereo(client)) { msp_set_audmode(client); + } if (msp_once) state->watch_stereo = 0; @@ -478,7 +465,7 @@ int msp3400c_thread(void *data) struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); struct msp3400c_carrier_detect *cd; - int count, max1, max2, val1, val2, val, i; + int count, max1, max2, val1, val2, val, this; v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); @@ -488,7 +475,7 @@ int msp3400c_thread(void *data) msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); -restart: + restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -496,8 +483,7 @@ int msp3400c_thread(void *data) if (state->radio || MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ - v4l_dbg(1, msp_debug, client, - "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -528,17 +514,16 @@ int msp3400c_thread(void *data) v4l_dbg(1, msp_debug, client, "AM sound override\n"); } - for (i = 0; i < count; i++) { - msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); - if (msp_sleep(state, 100)) + for (this = 0; this < count; this++) { + msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); + if (msp_sleep(state,100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val1 < val) - val1 = val, max1 = i; - v4l_dbg(1, msp_debug, client, - "carrier1 val: %5d / %s\n", val, cd[i].name); + val1 = val, max1 = this; + v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name); } /* carrier detect pass #2 -- second (stereo) carrier */ @@ -565,17 +550,16 @@ int msp3400c_thread(void *data) count = 0; max2 = 0; } - for (i = 0; i < count; i++) { - msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); - if (msp_sleep(state, 100)) + for (this = 0; this < count; this++) { + msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); + if (msp_sleep(state,100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val2 < val) - val2 = val, max2 = i; - v4l_dbg(1, msp_debug, client, - "carrier2 val: %5d / %s\n", val, cd[i].name); + val2 = val, max2 = this; + v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name); } /* program the msp3400 according to the results */ @@ -627,7 +611,7 @@ int msp3400c_thread(void *data) break; case 0: /* 4.5 */ default: -no_second: + no_second: state->second = msp3400c_carrier_detect_main[max1].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); break; @@ -648,8 +632,7 @@ int msp3400c_thread(void *data) while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; - if (count) - count--; + if (count) count--; watch_stereo(client); } } @@ -668,10 +651,10 @@ int msp3410d_thread(void *data) set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); - msp_sleep(state, -1); + msp_sleep(state,-1); v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); -restart: + restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -679,8 +662,7 @@ int msp3410d_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, - "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -691,8 +673,7 @@ int msp3410d_thread(void *data) msp_set_audio(client); /* start autodetect. Note: autodetect is not supported for - NTSC-M and radio, hence we force the standard in those - cases. */ + NTSC-M and radio, hence we force the standard in those cases. */ if (state->radio) std = 0x40; else @@ -705,9 +686,8 @@ int msp3410d_thread(void *data) goto restart; if (msp_debug) - v4l_dbg(2, msp_debug, client, - "setting standard: %s (0x%04x)\n", - msp_standard_std_name(std), std); + v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n", + msp_standard_std_name(std), std); if (std != 1) { /* programmed some specific mode */ @@ -723,8 +703,7 @@ int msp3410d_thread(void *data) val = msp_read_dem(client, 0x7e); if (val < 0x07ff) break; - v4l_dbg(2, msp_debug, client, - "detection still in progress\n"); + v4l_dbg(2, msp_debug, client, "detection still in progress\n"); } } for (i = 0; msp_stdlist[i].name != NULL; i++) @@ -737,13 +716,12 @@ int msp3410d_thread(void *data) state->std = val; state->rxsubchans = V4L2_TUNER_SUB_MONO; - if (msp_amsound && !state->radio && - (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { + if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) && + (val != 0x0009)) { /* autodetection has failed, let backup */ v4l_dbg(1, msp_debug, client, "autodetection failed," " switching to backup standard: %s (0x%04x)\n", - msp_stdlist[8].name ? - msp_stdlist[8].name : "unknown", val); + msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); state->std = val = 0x0009; msp_write_dem(client, 0x20, val); } @@ -808,8 +786,7 @@ int msp3410d_thread(void *data) while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; - if (count) - count--; + if (count) count--; watch_stereo(client); } } @@ -895,8 +872,8 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) else source = (in << 8) | matrix; - v4l_dbg(1, msp_debug, client, - "set source to %d (0x%x) for output %02x\n", in, source, reg); + v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n", + in, source, reg); msp_write_dsp(client, reg, source); } @@ -971,7 +948,7 @@ int msp34xxg_thread(void *data) msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n"); -restart: + restart: v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -979,8 +956,7 @@ int msp34xxg_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, - "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -996,8 +972,7 @@ int msp34xxg_thread(void *data) goto unmute; /* watch autodetect */ - v4l_dbg(1, msp_debug, client, - "started autodetect, waiting for result\n"); + v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n"); for (i = 0; i < 10; i++) { if (msp_sleep(state, 100)) goto restart; @@ -1008,18 +983,15 @@ int msp34xxg_thread(void *data) state->std = val; break; } - v4l_dbg(2, msp_debug, client, - "detection still in progress\n"); + v4l_dbg(2, msp_debug, client, "detection still in progress\n"); } if (state->std == 1) { - v4l_dbg(1, msp_debug, client, - "detection still in progress after 10 tries. giving up.\n"); + v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n"); continue; } -unmute: - v4l_dbg(1, msp_debug, client, - "detected standard: %s (0x%04x)\n", + unmute: + v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n", msp_standard_std_name(state->std), state->std); if (state->std == 9) { @@ -1074,11 +1046,9 @@ static int msp34xxg_detect_stereo(struct i2c_client *client) if (state->std == 0x20) state->rxsubchans |= V4L2_TUNER_SUB_SAP; else - state->rxsubchans = - V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } - v4l_dbg(1, msp_debug, client, - "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", + v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", status, is_stereo, is_bilingual, state->rxsubchans); return (oldrx != state->rxsubchans); } diff --git a/trunk/drivers/media/video/mt20xx.c b/trunk/drivers/media/video/mt20xx.c index b630c26cfe85..f49d1f4c40db 100644 --- a/trunk/drivers/media/video/mt20xx.c +++ b/trunk/drivers/media/video/mt20xx.c @@ -14,7 +14,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "mt20xx" +#define PREFIX "mt20xx " /* ---------------------------------------------------------------------- */ diff --git a/trunk/drivers/media/video/pvrusb2/Kconfig b/trunk/drivers/media/video/pvrusb2/Kconfig index 6fc1b8be1a1f..d0c2cd785430 100644 --- a/trunk/drivers/media/video/pvrusb2/Kconfig +++ b/trunk/drivers/media/video/pvrusb2/Kconfig @@ -5,10 +5,6 @@ config VIDEO_PVRUSB2 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X - select VIDEO_SAA711X - select VIDEO_CX25840 - select VIDEO_MSP3400 - select VIDEO_WM8775 ---help--- This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. @@ -16,29 +12,32 @@ config VIDEO_PVRUSB2 To compile this driver as a module, choose M here: the module will be called pvrusb2 -config VIDEO_PVRUSB2_ONAIR_CREATOR - bool "pvrusb2 driver support for OnAir Creator model" +config VIDEO_PVRUSB2_29XXX + bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series" depends on VIDEO_PVRUSB2 && EXPERIMENTAL select VIDEO_SAA711X - select VIDEO_CS53L32A + select VIDEO_MSP3400 ---help--- - - This option enables support for the OnAir Creator USB tuner - device. This is a hybrid device, however currently only - analog mode is supported. + This option enables support for WinTV-PVR USB2 devices whose + model number is of the form "29xxx" (leading prefix of "29" + followed by 3 digits). + To see if you may need this option, examine the white + sticker on the underside of your device. If you are in doubt, say Y. -config VIDEO_PVRUSB2_ONAIR_USB2 - bool "pvrusb2 driver support for OnAir USB2 model" +config VIDEO_PVRUSB2_24XXX + bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series" depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_CS53L32A + select VIDEO_CX25840 + select VIDEO_WM8775 ---help--- - - This option enables support for the OnAir USB2 tuner device - (also known as the Sasem tuner). This is a hybrid device, - however currently only analog mode is supported. + This option enables inclusion of additional logic to operate + newer WinTV-PVR USB2 devices whose model number is of the + form "24xxx" (leading prefix of "24" followed by 3 digits). + To see if you may need this option, examine the white + sticker on the underside of your device. Enabling this + option will not harm support for older devices. If you are in doubt, say Y. diff --git a/trunk/drivers/media/video/pvrusb2/Makefile b/trunk/drivers/media/video/pvrusb2/Makefile index 47284e558648..69b3e43cd0eb 100644 --- a/trunk/drivers/media/video/pvrusb2/Makefile +++ b/trunk/drivers/media/video/pvrusb2/Makefile @@ -6,7 +6,7 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ pvrusb2-encoder.o pvrusb2-video-v4l.o \ pvrusb2-eeprom.o pvrusb2-tuner.o \ pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \ - pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \ + pvrusb2-ctrl.o pvrusb2-std.o \ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \ pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y) diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-audio.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-audio.c index 9a7c8e9c3e8b..379645e481c6 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -35,58 +35,34 @@ struct pvr2_msp3400_handler { }; - -struct routing_scheme { - const int *def; - unsigned int cnt; -}; - -static const int routing_scheme0[] = { - [PVR2_CVAL_INPUT_TV] = MSP_INPUT_DEFAULT, - [PVR2_CVAL_INPUT_RADIO] = MSP_INPUT(MSP_IN_SCART2, - MSP_IN_TUNER1, - MSP_DSP_IN_SCART, - MSP_DSP_IN_SCART), - [PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1, - MSP_IN_TUNER1, - MSP_DSP_IN_SCART, - MSP_DSP_IN_SCART), - [PVR2_CVAL_INPUT_SVIDEO] = MSP_INPUT(MSP_IN_SCART1, - MSP_IN_TUNER1, - MSP_DSP_IN_SCART, - MSP_DSP_IN_SCART), -}; - -static const struct routing_scheme routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), - }, -}; - /* This function selects the correct audio input source */ static void set_stereo(struct pvr2_msp3400_handler *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; - const struct routing_scheme *sp; - unsigned int sid = hdw->hdw_desc->signal_routing_scheme; pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo"); - if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && - (hdw->input_val >= 0) && - (hdw->input_val < sp->cnt)) { - route.input = sp->def[hdw->input_val]; - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** i2c msp3400 v4l2 set_stereo:" - " Invalid routing scheme (%u) and/or input (%d)", - sid,hdw->input_val); - return; - } + route.input = MSP_INPUT_DEFAULT; route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); + switch (hdw->input_val) { + case PVR2_CVAL_INPUT_TV: + break; + case PVR2_CVAL_INPUT_RADIO: + /* Assume that msp34xx also handle FM decoding, in which case + we're still using the tuner. */ + /* HV: actually it is more likely to be the SCART2 input if + the ivtv experience is any indication. */ + route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + case PVR2_CVAL_INPUT_SVIDEO: + case PVR2_CVAL_INPUT_COMPOSITE: + /* SCART 1 input */ + route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); + break; + } pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route); } diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-context.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-context.c index 9d94aed2e12d..22719ba861ac 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -31,32 +31,52 @@ static void pvr2_context_destroy(struct pvr2_context *mp) { - pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); if (mp->hdw) pvr2_hdw_destroy(mp->hdw); + pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); + if (mp->workqueue) { + flush_workqueue(mp->workqueue); + destroy_workqueue(mp->workqueue); + } kfree(mp); } -static void pvr2_context_state_check(struct pvr2_context *mp) +static void pvr2_context_trigger_poll(struct pvr2_context *mp) { - if (mp->init_flag) return; - - switch (pvr2_hdw_get_state(mp->hdw)) { - case PVR2_STATE_WARM: break; - case PVR2_STATE_ERROR: break; - case PVR2_STATE_READY: break; - case PVR2_STATE_RUN: break; - default: return; - } + queue_work(mp->workqueue,&mp->workpoll); +} + + +static void pvr2_context_poll(struct work_struct *work) +{ + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workpoll); + pvr2_context_enter(mp); do { + pvr2_hdw_poll(mp->hdw); + } while (0); pvr2_context_exit(mp); +} + + +static void pvr2_context_setup(struct work_struct *work) +{ + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workinit); pvr2_context_enter(mp); do { - mp->init_flag = !0; + if (!pvr2_hdw_dev_ok(mp->hdw)) break; + pvr2_hdw_setup(mp->hdw); + pvr2_hdw_setup_poll_trigger( + mp->hdw, + (void (*)(void *))pvr2_context_trigger_poll, + mp); + if (!pvr2_hdw_dev_ok(mp->hdw)) break; + if (!pvr2_hdw_init_ok(mp->hdw)) break; mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); if (mp->setup_func) { mp->setup_func(mp); } } while (0); pvr2_context_exit(mp); - } +} struct pvr2_context *pvr2_context_create( @@ -76,10 +96,11 @@ struct pvr2_context *pvr2_context_create( mp = NULL; goto done; } - pvr2_hdw_set_state_callback(mp->hdw, - (void (*)(void *))pvr2_context_state_check, - mp); - pvr2_context_state_check(mp); + + mp->workqueue = create_singlethread_workqueue("pvrusb2"); + INIT_WORK(&mp->workinit, pvr2_context_setup); + INIT_WORK(&mp->workpoll, pvr2_context_poll); + queue_work(mp->workqueue,&mp->workinit); done: return mp; } diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-context.h b/trunk/drivers/media/video/pvrusb2/pvrusb2-context.h index a04187a93225..6327fa1f7e4f 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -45,11 +45,14 @@ struct pvr2_context { struct pvr2_context_stream video_stream; struct mutex mutex; int disconnect_flag; - int init_flag; /* Called after pvr2_context initialization is complete */ void (*setup_func)(struct pvr2_context *); + /* Work queue overhead for out-of-line processing */ + struct workqueue_struct *workqueue; + struct work_struct workinit; + struct work_struct workpoll; }; struct pvr2_channel { diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index ffdc45c324e5..e8a9252c7df6 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -49,89 +49,34 @@ struct pvr2_v4l_cx2584x { }; -struct routing_scheme_item { - int vid; - int aud; -}; - -struct routing_scheme { - const struct routing_scheme_item *def; - unsigned int cnt; -}; - -static const struct routing_scheme_item routing_scheme0[] = { - [PVR2_CVAL_INPUT_TV] = { - .vid = CX25840_COMPOSITE7, - .aud = CX25840_AUDIO8, - }, - [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */ - .vid = CX25840_COMPOSITE3, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_COMPOSITE] = { - .vid = CX25840_COMPOSITE3, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_SVIDEO] = { - .vid = CX25840_SVIDEO1, - .aud = CX25840_AUDIO_SERIAL, - }, -}; - -/* Specific to gotview device */ -static const struct routing_scheme_item routing_schemegv[] = { - [PVR2_CVAL_INPUT_TV] = { - .vid = CX25840_COMPOSITE2, - .aud = CX25840_AUDIO5, - }, - [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */ - .vid = CX25840_COMPOSITE1, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_COMPOSITE] = { - .vid = CX25840_COMPOSITE1, - .aud = CX25840_AUDIO_SERIAL, - }, - [PVR2_CVAL_INPUT_SVIDEO] = { - .vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4), - .aud = CX25840_AUDIO_SERIAL, - }, -}; - -static const struct routing_scheme routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), - }, - [PVR2_ROUTING_SCHEME_GOTVIEW] = { - .def = routing_schemegv, - .cnt = ARRAY_SIZE(routing_schemegv), - }, -}; - static void set_input(struct pvr2_v4l_cx2584x *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; enum cx25840_video_input vid_input; enum cx25840_audio_input aud_input; - const struct routing_scheme *sp; - unsigned int sid = hdw->hdw_desc->signal_routing_scheme; memset(&route,0,sizeof(route)); - if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && - (hdw->input_val >= 0) && - (hdw->input_val < sp->cnt)) { - vid_input = sp->def[hdw->input_val].vid; - aud_input = sp->def[hdw->input_val].aud; - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** i2c cx2584x set_input:" - " Invalid routing scheme (%u) and/or input (%d)", - sid,hdw->input_val); - return; + switch(hdw->input_val) { + case PVR2_CVAL_INPUT_TV: + vid_input = CX25840_COMPOSITE7; + aud_input = CX25840_AUDIO8; + break; + case PVR2_CVAL_INPUT_RADIO: // Treat same as composite + case PVR2_CVAL_INPUT_COMPOSITE: + vid_input = CX25840_COMPOSITE3; + aud_input = CX25840_AUDIO_SERIAL; + break; + case PVR2_CVAL_INPUT_SVIDEO: + vid_input = CX25840_SVIDEO1; + aud_input = CX25840_AUDIO_SERIAL; + break; + default: + // Just set it to be composite input for now... + vid_input = CX25840_COMPOSITE3; + aud_input = CX25840_AUDIO_SERIAL; + break; } pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x", @@ -195,7 +140,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = { static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt) { ctxt->client->handler = NULL; - pvr2_hdw_set_decoder(ctxt->hdw,NULL); + ctxt->hdw->decoder_ctrl = NULL; kfree(ctxt); } @@ -296,7 +241,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw, ctxt->client = cp; ctxt->hdw = hdw; ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1; - pvr2_hdw_set_decoder(hdw,&ctxt->ctrl); + hdw->decoder_ctrl = &ctxt->ctrl; cp->handler = &ctxt->handler; { /* diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-debug.h b/trunk/drivers/media/video/pvrusb2/pvrusb2-debug.h index fca49d8a9311..da6441b88f31 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -34,26 +34,25 @@ extern int pvrusb2_debug; #define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */ #define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */ #define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */ -#define PVR2_TRACE_STATE (1 << 8) /* Device state changes */ -#define PVR2_TRACE_STBITS (1 << 9) /* Individual bit state changes */ -#define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */ -#define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */ -#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */ -#define PVR2_TRACE_CREG (1 << 13) /* Main critical region entry / exit */ -#define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */ -#define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */ -#define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */ -#define PVR2_TRACE_I2C (1 << 17) /* I2C related stuff */ -#define PVR2_TRACE_I2C_CMD (1 << 18) /* Software commands to I2C modules */ -#define PVR2_TRACE_I2C_CORE (1 << 19) /* I2C core debugging */ -#define PVR2_TRACE_I2C_TRAF (1 << 20) /* I2C traffic through the adapter */ -#define PVR2_TRACE_V4LIOCTL (1 << 21) /* v4l ioctl details */ -#define PVR2_TRACE_ENCODER (1 << 22) /* mpeg2 encoder operation */ -#define PVR2_TRACE_BUF_POOL (1 << 23) /* Track buffer pool management */ -#define PVR2_TRACE_BUF_FLOW (1 << 24) /* Track buffer flow in system */ -#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */ -#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */ -#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */ +#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */ +#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */ +#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */ +#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */ +#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */ +#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */ +#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */ +#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */ +#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */ +#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */ +#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */ +#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */ +#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */ +#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */ +#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */ +#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */ +#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */ +#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */ +#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index b0687430fdd4..6f135f4a2497 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-debugifc.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -31,6 +31,14 @@ struct debugifc_mask_item { unsigned long msk; }; +static struct debugifc_mask_item mask_items[] = { + {"ENC_FIRMWARE",(1<name)) { + return mip->msk; + } + } + return 0; +} + + +static int debugifc_print_mask(char *buf,unsigned int sz, + unsigned long msk,unsigned long val) +{ + struct debugifc_mask_item *mip; + unsigned int idx; + int bcnt = 0; + int ccnt; + for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) { + mip = mask_items + idx; + if (!(mip->msk & msk)) continue; + ccnt = scnprintf(buf,sz,"%s%c%s", + (bcnt ? " " : ""), + ((mip->msk & val) ? '+' : '-'), + mip->name); + sz -= ccnt; + buf += ccnt; + bcnt += ccnt; + } + return bcnt; +} + +static unsigned int debugifc_parse_subsys_mask(const char *buf, + unsigned int count, + unsigned long *mskPtr, + unsigned long *valPtr) +{ + const char *wptr; + unsigned int consume_cnt = 0; + unsigned int scnt; + unsigned int wlen; + int mode; + unsigned long m1,msk,val; + + msk = 0; + val = 0; + + while (count) { + scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); + if (!scnt) break; + consume_cnt += scnt; count -= scnt; buf += scnt; + if (!wptr) break; + + mode = 0; + if (wlen) switch (wptr[0]) { + case '+': + wptr++; + wlen--; + break; + case '-': + mode = 1; + wptr++; + wlen--; + break; + } + if (!wlen) continue; + m1 = debugifc_find_mask(wptr,wlen); + if (!m1) break; + msk |= m1; + if (!mode) val |= m1; + } + *mskPtr = msk; + *valPtr = val; + return consume_cnt; +} + + int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt) { int bcnt = 0; int ccnt; - ccnt = scnprintf(buf,acnt,"Driver state info:\n"); + struct pvr2_hdw_debug_info dbg; + + pvr2_hdw_get_debug_info(hdw,&dbg); + + ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s", + (dbg.big_lock_held ? "held" : "free"), + (dbg.ctl_lock_held ? "held" : "free")); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + if (dbg.ctl_lock_held) { + ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d" + " cmd_wlen=%d cmd_rlen=%d" + " wpend=%d rpend=%d tmout=%d rstatus=%d" + " wstatus=%d", + dbg.cmd_debug_state,dbg.cmd_code, + dbg.cmd_debug_write_len, + dbg.cmd_debug_read_len, + dbg.cmd_debug_write_pend, + dbg.cmd_debug_read_pend, + dbg.cmd_debug_timeout, + dbg.cmd_debug_rstatus, + dbg.cmd_debug_wstatus); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + } + ccnt = scnprintf(buf,acnt,"\n"); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf( + buf,acnt,"driver flags: %s %s %s\n", + (dbg.flag_init_ok ? "initialized" : "uninitialized"), + (dbg.flag_ok ? "ok" : "fail"), + (dbg.flag_disconnected ? "disconnected" : "connected")); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = pvr2_hdw_state_report(hdw,buf,acnt); + ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags); bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"\n"); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"\n"); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; ccnt = pvr2_i2c_report(hdw,buf,acnt); @@ -162,6 +290,7 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, { int bcnt = 0; int ccnt; + unsigned long msk; int ret; u32 gpio_dir,gpio_in,gpio_out; @@ -182,6 +311,28 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, pvr2_hdw_get_streaming(hdw) ? "on" : "off"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; + msk = pvr2_hdw_subsys_get(hdw); + ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = debugifc_print_mask(buf,acnt,msk,msk); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"\n"); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = debugifc_print_mask(buf,acnt,~msk,msk); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"\n"); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + + msk = pvr2_hdw_subsys_stream_get(hdw); + ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: "); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = debugifc_print_mask(buf,acnt,msk,msk); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + ccnt = scnprintf(buf,acnt,"\n"); + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + return bcnt; } @@ -218,10 +369,28 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, return pvr2_upload_firmware2(hdw); } else if (debugifc_match_keyword(wptr,wlen,"decoder")) { return pvr2_hdw_cmd_decoder_reset(hdw); - } else if (debugifc_match_keyword(wptr,wlen,"worker")) { - return pvr2_hdw_untrip(hdw); } return -EINVAL; + } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) { + unsigned long msk = 0; + unsigned long val = 0; + if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { + pvr2_trace(PVR2_TRACE_DEBUGIFC, + "debugifc parse error on subsys mask"); + return -EINVAL; + } + pvr2_hdw_subsys_bit_chg(hdw,msk,val); + return 0; + } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) { + unsigned long msk = 0; + unsigned long val = 0; + if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { + pvr2_trace(PVR2_TRACE_DEBUGIFC, + "debugifc parse error on stream mask"); + return -EINVAL; + } + pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val); + return 0; } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) { scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); if (!scnt) return -EINVAL; diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-devattr.c deleted file mode 100644 index 4df6d6d936fc..000000000000 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * - * $Id$ - * - * Copyright (C) 2007 Mike Isely - * - * 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 - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - -This source file should encompass ALL per-device type information for the -driver. To define a new device, add elements to the pvr2_device_table and -pvr2_device_desc structures. - -*/ - -#include "pvrusb2-devattr.h" -#include -/* This is needed in order to pull in tuner type ids... */ -#include -#include - - - -/*------------------------------------------------------------------------*/ -/* Hauppauge PVR-USB2 Model 29xxx */ - -static const char *pvr2_client_29xxx[] = { - "msp3400", - "saa7115", - "tuner", -}; - -static const char *pvr2_fw1_names_29xxx[] = { - "v4l-pvrusb2-29xxx-01.fw", -}; - -static const struct pvr2_device_desc pvr2_device_29xxx = { - .description = "WinTV PVR USB2 Model Category 29xxxx", - .shortname = "29xxx", - .client_modules.lst = pvr2_client_29xxx, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx), - .fx2_firmware.lst = pvr2_fw1_names_29xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx), - .flag_has_hauppauge_rom = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, -}; - - - -/*------------------------------------------------------------------------*/ -/* Hauppauge PVR-USB2 Model 24xxx */ - -static const char *pvr2_client_24xxx[] = { - "cx25840", - "tuner", - "wm8775", -}; - -static const char *pvr2_fw1_names_24xxx[] = { - "v4l-pvrusb2-24xxx-01.fw", -}; - -static const struct pvr2_device_desc pvr2_device_24xxx = { - .description = "WinTV PVR USB2 Model Category 24xxxx", - .shortname = "24xxx", - .client_modules.lst = pvr2_client_24xxx, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx), - .fx2_firmware.lst = pvr2_fw1_names_24xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx), - .flag_has_cx25840 = !0, - .flag_has_wm8775 = !0, - .flag_has_hauppauge_rom = !0, - .flag_has_hauppauge_custom_ir = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, -}; - - - -/*------------------------------------------------------------------------*/ -/* GOTVIEW USB2.0 DVD2 */ - -static const char *pvr2_client_gotview_2[] = { - "cx25840", - "tuner", -}; - -static const struct pvr2_device_desc pvr2_device_gotview_2 = { - .description = "Gotview USB 2.0 DVD 2", - .shortname = "gv2", - .client_modules.lst = pvr2_client_gotview_2, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2), - .flag_has_cx25840 = !0, - .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, -}; - - - -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR -/*------------------------------------------------------------------------*/ -/* OnAir Creator */ - -static const char *pvr2_client_onair_creator[] = { - "saa7115", - "tuner", - "cs53l32a", -}; - -static const struct pvr2_device_desc pvr2_device_onair_creator = { - .description = "OnAir Creator Hybrid USB tuner", - .shortname = "oac", - .client_modules.lst = pvr2_client_onair_creator, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator), - .default_tuner_type = TUNER_LG_TDVS_H06XF, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, -}; -#endif - - - -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 -/*------------------------------------------------------------------------*/ -/* OnAir USB 2.0 */ - -static const char *pvr2_client_onair_usb2[] = { - "saa7115", - "tuner", - "cs53l32a", -}; - -static const struct pvr2_device_desc pvr2_device_onair_usb2 = { - .description = "OnAir USB2 Hybrid USB tuner", - .shortname = "oa2", - .client_modules.lst = pvr2_client_onair_usb2, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2), - .default_tuner_type = TUNER_PHILIPS_ATSC, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, -}; -#endif - - - -/*------------------------------------------------------------------------*/ -/* Hauppauge PVR-USB2 Model 75xxx */ - -static const char *pvr2_client_75xxx[] = { - "cx25840", - "tuner", -}; - -static const char *pvr2_fw1_names_75xxx[] = { - "v4l-pvrusb2-73xxx-01.fw", -}; - -static const struct pvr2_device_desc pvr2_device_75xxx = { - .description = "WinTV PVR USB2 Model Category 75xxxx", - .shortname = "75xxx", - .client_modules.lst = pvr2_client_75xxx, - .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx), - .fx2_firmware.lst = pvr2_fw1_names_75xxx, - .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx), - .flag_has_cx25840 = !0, - .flag_has_hauppauge_rom = !0, - .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, - .default_std_mask = V4L2_STD_NTSC_M, -}; - - - -/*------------------------------------------------------------------------*/ - -struct usb_device_id pvr2_device_table[] = { - { USB_DEVICE(0x2040, 0x2900), - .driver_info = (kernel_ulong_t)&pvr2_device_29xxx}, - { USB_DEVICE(0x2040, 0x2400), - .driver_info = (kernel_ulong_t)&pvr2_device_24xxx}, - { USB_DEVICE(0x1164, 0x0622), - .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2}, -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR - { USB_DEVICE(0x11ba, 0x1003), - .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator}, -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 - { USB_DEVICE(0x11ba, 0x1001), - .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, -#endif - { USB_DEVICE(0x2040, 0x7500), - .driver_info = (kernel_ulong_t)&pvr2_device_75xxx}, - { } -}; - -MODULE_DEVICE_TABLE(usb, pvr2_device_table); - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/trunk/drivers/media/video/pvrusb2/pvrusb2-devattr.h deleted file mode 100644 index 64b467f0637f..000000000000 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * $Id$ - * - * Copyright (C) 2005 Mike Isely - * - * 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 - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#ifndef __PVRUSB2_DEVATTR_H -#define __PVRUSB2_DEVATTR_H - -#include -#include - -/* - - This header defines structures used to describe attributes of a device. - -*/ - - -struct pvr2_string_table { - const char **lst; - unsigned int cnt; -}; - -#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0 -#define PVR2_ROUTING_SCHEME_GOTVIEW 1 - -/* This describes a particular hardware type (except for the USB device ID - which must live in a separate structure due to environmental - constraints). See the top of pvrusb2-hdw.c for where this is - instantiated. */ -struct pvr2_device_desc { - /* Single line text description of hardware */ - const char *description; - - /* Single token identifier for hardware */ - const char *shortname; - - /* List of additional client modules we need to load */ - struct pvr2_string_table client_modules; - - /* List of FX2 firmware file names we should search; if empty then - FX2 firmware check / load is skipped and we assume the device - was initialized from internal ROM. */ - struct pvr2_string_table fx2_firmware; - - /* Signal routing scheme used by device, contains one of - PVR2_ROUTING_SCHEME_XXX. Schemes have to be defined as we - encounter them. This is an arbitrary integer scheme id; its - meaning is contained entirely within the driver and is - interpreted by logic which must send commands to the chip-level - drivers (search for things which touch this field). */ - unsigned int signal_routing_scheme; - - /* V4L tuner type ID to use with this device (only used if the - driver could not discover the type any other way). */ - int default_tuner_type; - - /* Initial standard bits to use for this device, if not zero. - Anything set here is also implied as an available standard. - Note: This is ignored if overridden on the module load line via - the video_std module option. */ - v4l2_std_id default_std_mask; - - /* If set, we don't bother trying to load cx23416 firmware. */ - char flag_skip_cx23416_firmware; - - /* Device has a hauppauge eeprom which we can interrogate. */ - char flag_has_hauppauge_rom; - - /* Device does not require a powerup command to be issued. */ - char flag_no_powerup; - - /* Device has a cx25840 - this enables special additional logic to - handle it. */ - char flag_has_cx25840; - - /* Device has a wm8775 - this enables special additional logic to - ensure that it is found. */ - char flag_has_wm8775; - - /* Device has IR hardware that can be faked into looking like a - normal Hauppauge i2c IR receiver. This is currently very - specific to the 24xxx device, where Hauppauge had replaced their - 'standard' I2C IR receiver with a bunch of FPGA logic controlled - directly via the FX2. Turning this on tells the pvrusb2 driver - to virtualize the presence of the non-existant IR receiver chip and - implement the virtual receiver in terms of appropriate FX2 - commands. */ - char flag_has_hauppauge_custom_ir; -}; - -extern struct usb_device_id pvr2_device_table[]; - -#endif /* __PVRUSB2_HDW_INTERNAL_H */ - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 75 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-eeprom.c index 5ef005947b04..45cbca0143ca 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-eeprom.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-eeprom.c @@ -144,7 +144,6 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) trace_eeprom("serial_number=%d",tvdata.serial_number); trace_eeprom("rev_str=%s",tvdata.rev_str); hdw->tuner_type = tvdata.tuner_type; - hdw->tuner_updated = !0; hdw->serial_number = tvdata.serial_number; hdw->std_mask_eeprom = tvdata.tuner_formats; diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 64062879981e..205087a3e136 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -140,7 +140,7 @@ static int pvr2_encoder_read_words(struct pvr2_hdw *hdw, cx2341x.ko to write to our encoder (by handing it a pointer to this function). For earlier kernels this doesn't really matter. */ static int pvr2_encoder_cmd(void *ctxt, - u32 cmd, + int cmd, int arg_cnt_send, int arg_cnt_recv, u32 *argp) @@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt, LOCK_TAKE(hdw->ctl_lock); do { - if (!hdw->state_encoder_ok) { + if (!hdw->flag_encoder_ok) { ret = -EIO; break; } @@ -278,15 +278,12 @@ static int pvr2_encoder_cmd(void *ctxt, ret = -EBUSY; } if (ret) { - hdw->state_encoder_ok = 0; - pvr2_trace(PVR2_TRACE_STBITS, - "State bit %s <-- %s", - "state_encoder_ok", - (hdw->state_encoder_ok ? "true" : "false")); + hdw->flag_encoder_ok = 0; pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Giving up on command." - " This is normally recovered by the driver."); + " It is likely that" + " this is a bad idea..."); break; } wrData[0] = 0x7; @@ -369,13 +366,13 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) /* This ENC_MISC(3,encMisc3Arg) command is critical - without it there will eventually be video corruption. Also, the - saa7115 case is strange - the Windows driver is passing 1 - regardless of device type but if we have 1 for saa7115 - devices the video turns sluggish. */ - if (hdw->hdw_desc->flag_has_cx25840) { - encMisc3Arg = 1; - } else { - encMisc3Arg = 0; + 29xxx case is strange - the Windows driver is passing 1 + regardless of device type but if we have 1 for 29xxx device + the video turns sluggish. */ + switch (hdw->hdw_type) { + case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break; + case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break; + default: break; } ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3, encMisc3Arg,0,0); @@ -397,24 +394,6 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) return ret; } -int pvr2_encoder_adjust(struct pvr2_hdw *hdw) -{ - int ret; - ret = cx2341x_update(hdw,pvr2_encoder_cmd, - (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL), - &hdw->enc_ctl_state); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error from cx2341x module code=%d",ret); - } else { - memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state, - sizeof(struct cx2341x_mpeg_params)); - hdw->enc_cur_valid = !0; - } - return ret; -} - - int pvr2_encoder_configure(struct pvr2_hdw *hdw) { int ret; @@ -433,7 +412,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) /* saa7115: 0xf0 */ val = 0xf0; - if (hdw->hdw_desc->flag_has_cx25840) { + if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { /* ivtv cx25840: 0x140 */ val = 0x140; } @@ -457,10 +436,18 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) return ret; } - ret = pvr2_encoder_adjust(hdw); - if (ret) return ret; + ret = cx2341x_update(hdw,pvr2_encoder_cmd, + (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL), + &hdw->enc_ctl_state); + if (ret) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Error from cx2341x module code=%d",ret); + return ret; + } + + ret = 0; - ret = pvr2_encoder_vcmd( + if (!ret) ret = pvr2_encoder_vcmd( hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); if (ret) { @@ -469,6 +456,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) return ret; } + hdw->subsys_enabled_mask |= (1<enc_cur_state,&hdw->enc_ctl_state, + sizeof(struct cx2341x_mpeg_params)); + hdw->enc_cur_valid = !0; return 0; } @@ -487,7 +478,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw) pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1, hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0); - switch (hdw->active_stream_type) { + switch (hdw->config) { case pvr2_config_vbi: status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, 0x01,0x14); @@ -501,6 +492,9 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw) 0,0x13); break; } + if (!status) { + hdw->subsys_enabled_mask |= (1<active_stream_type) { + switch (hdw->config) { case pvr2_config_vbi: status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, 0x01,0x01,0x14); @@ -532,6 +526,9 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw) pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401); pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000); + if (!status) { + hdw->subsys_enabled_mask &= ~(1< #include -#include #include #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" #include -#include "pvrusb2-devattr.h" /* Legal values for PVR2_CID_HSM */ #define PVR2_CVAL_HSM_FAIL 0 @@ -163,6 +161,10 @@ struct pvr2_decoder_ctrl { #define FW1_STATE_RELOAD 3 #define FW1_STATE_OK 4 +/* Known major hardware variants, keyed from device ID */ +#define PVR2_HDW_TYPE_29XXX 0 +#define PVR2_HDW_TYPE_24XXX 1 + typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16); #define PVR2_I2C_FUNC_CNT 128 @@ -174,15 +176,8 @@ struct pvr2_hdw { struct usb_device *usb_dev; struct usb_interface *usb_intf; - /* Device description, anything that must adjust behavior based on - device specific info will use information held here. */ - const struct pvr2_device_desc *hdw_desc; - - /* Kernel worker thread handling */ - struct workqueue_struct *workqueue; - struct work_struct workpoll; /* Update driver state */ - struct work_struct worki2csync; /* Update i2c clients */ - struct work_struct workinit; /* Driver initialization sequence */ + /* Device type, one of PVR2_HDW_TYPE_xxxxx */ + unsigned int hdw_type; /* Video spigot */ struct pvr2_stream *vid_stream; @@ -191,6 +186,9 @@ struct pvr2_hdw { struct mutex big_lock_mutex; int big_lock_held; /* For debugging */ + void (*poll_trigger_func)(void *); + void *poll_trigger_data; + char name[32]; /* I2C stuff */ @@ -217,9 +215,9 @@ struct pvr2_hdw { struct urb *ctl_read_urb; unsigned char *ctl_write_buffer; unsigned char *ctl_read_buffer; - int ctl_write_pend_flag; - int ctl_read_pend_flag; - int ctl_timeout_flag; + volatile int ctl_write_pend_flag; + volatile int ctl_read_pend_flag; + volatile int ctl_timeout_flag; struct completion ctl_done; unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE]; int cmd_debug_state; // Low level command debugging info @@ -227,48 +225,14 @@ struct pvr2_hdw { unsigned int cmd_debug_write_len; // unsigned int cmd_debug_read_len; // - /* Bits of state that describe what is going on with various parts - of the driver. */ - int state_encoder_ok; /* Encoder is operational */ - int state_encoder_run; /* Encoder is running */ - int state_encoder_config; /* Encoder is configured */ - int state_encoder_waitok; /* Encoder pre-wait done */ - int state_decoder_run; /* Decoder is running */ - int state_usbstream_run; /* FX2 is streaming */ - int state_decoder_quiescent; /* Decoder idle for > 50msec */ - int state_pipeline_config; /* Pipeline is configured */ - int state_pipeline_req; /* Somebody wants to stream */ - int state_pipeline_pause; /* Pipeline must be paused */ - int state_pipeline_idle; /* Pipeline not running */ - - /* This is the master state of the driver. It is the combined - result of other bits of state. Examining this will indicate the - overall state of the driver. Values here are one of - PVR2_STATE_xxxx */ - unsigned int master_state; - - /* True if states must be re-evaluated */ - int state_stale; - - void (*state_func)(void *); - void *state_data; - - /* Timer for measuring decoder settling time */ - struct timer_list quiescent_timer; - - /* Timer for measuring encoder pre-wait time */ - struct timer_list encoder_wait_timer; - - /* Place to block while waiting for state changes */ - wait_queue_head_t state_wait_data; - - int flag_ok; /* device in known good state */ int flag_disconnected; /* flag_ok == 0 due to disconnect */ int flag_init_ok; /* true if structure is fully initialized */ + int flag_streaming_enabled; /* true if streaming should be on */ int fw1_state; /* current situation with fw1 */ - int flag_decoder_missed;/* We've noticed missing decoder */ - int flag_tripped; /* Indicates overall failure to start */ + int flag_encoder_ok; /* True if encoder is healthy */ + + int flag_decoder_is_tuned; struct pvr2_decoder_ctrl *decoder_ctrl; @@ -277,6 +241,12 @@ struct pvr2_hdw { unsigned int fw_size; int fw_cpu_flag; /* True if we are dealing with the CPU */ + // Which subsystem pieces have been enabled / configured + unsigned long subsys_enabled_mask; + + // Which subsystems are manipulated to enable streaming + unsigned long subsys_stream_mask; + // True if there is a request to trigger logging of state in each // module. int log_requested; @@ -326,16 +296,13 @@ struct pvr2_hdw { /* Location of eeprom or a negative number if none */ int eeprom_addr; - enum pvr2_config active_stream_type; - enum pvr2_config desired_stream_type; + enum pvr2_config config; /* Control state needed for cx2341x module */ struct cx2341x_mpeg_params enc_cur_state; struct cx2341x_mpeg_params enc_ctl_state; /* True if an encoder attribute has changed */ int enc_stale; - /* True if an unsafe encoder attribute has changed */ - int enc_unsafe_stale; /* True if enc_cur_state is valid */ int enc_cur_valid; @@ -365,7 +332,6 @@ struct pvr2_hdw { /* This function gets the current frequency */ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *); -void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *); #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 41ae980405ed..402c59488253 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -41,6 +41,47 @@ #define TV_MIN_FREQ 55250000L #define TV_MAX_FREQ 850000000L +struct usb_device_id pvr2_device_table[] = { + [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, + [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, pvr2_device_table); + +static const char *pvr2_device_names[] = { + [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx", + [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx", +}; + +struct pvr2_string_table { + const char **lst; + unsigned int cnt; +}; + +// Names of other client modules to request for 24xxx model hardware +static const char *pvr2_client_24xxx[] = { + "cx25840", + "tuner", + "wm8775", +}; + +// Names of other client modules to request for 29xxx model hardware +static const char *pvr2_client_29xxx[] = { + "msp3400", + "saa7115", + "tuner", +}; + +static struct pvr2_string_table pvr2_client_lists[] = { + [PVR2_HDW_TYPE_29XXX] = { + pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx) + }, + [PVR2_HDW_TYPE_24XXX] = { + pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx) + }, +}; + static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; static DEFINE_MUTEX(pvr2_unit_mtx); @@ -205,46 +246,32 @@ static const char *control_values_hsm[] = { }; -static const char *pvr2_state_names[] = { - [PVR2_STATE_NONE] = "none", - [PVR2_STATE_DEAD] = "dead", - [PVR2_STATE_COLD] = "cold", - [PVR2_STATE_WARM] = "warm", - [PVR2_STATE_ERROR] = "error", - [PVR2_STATE_READY] = "ready", - [PVR2_STATE_RUN] = "run", +static const char *control_values_subsystem[] = { + [PVR2_SUBSYS_B_ENC_FIRMWARE] = "enc_firmware", + [PVR2_SUBSYS_B_ENC_CFG] = "enc_config", + [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run", + [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run", + [PVR2_SUBSYS_B_ENC_RUN] = "enc_run", }; - -static void pvr2_hdw_state_sched(struct pvr2_hdw *); -static int pvr2_hdw_state_eval(struct pvr2_hdw *); static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); -static void pvr2_hdw_worker_i2c(struct work_struct *work); -static void pvr2_hdw_worker_poll(struct work_struct *work); -static void pvr2_hdw_worker_init(struct work_struct *work); -static int pvr2_hdw_wait(struct pvr2_hdw *,int state); -static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); -static void pvr2_hdw_state_log_state(struct pvr2_hdw *); static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); -static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw); +static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw); static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw); static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw); static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw); -static void pvr2_hdw_quiescent_timeout(unsigned long); -static void pvr2_hdw_encoder_wait_timeout(unsigned long); +static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw); +static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw, + unsigned long msk, + unsigned long val); +static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, + unsigned long msk, + unsigned long val); static int pvr2_send_request_ex(struct pvr2_hdw *hdw, unsigned int timeout,int probe_fl, void *write_data,unsigned int write_len, void *read_data,unsigned int read_len); - -static void trace_stbit(const char *name,int val) -{ - pvr2_trace(PVR2_TRACE_STBITS, - "State bit %s <-- %s", - name,(val ? "true" : "false")); -} - static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp) { struct pvr2_hdw *hdw = cptr->hdw; @@ -353,8 +380,8 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp) { - /* Actual minimum depends on device digitizer type. */ - if (cptr->hdw->hdw_desc->flag_has_cx25840) { + /* Actual minimum depends on device type. */ + if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { *vp = 75; } else { *vp = 17; @@ -453,7 +480,6 @@ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) { cptr->hdw->enc_stale = 0; - cptr->hdw->enc_unsafe_stale = 0; } static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) @@ -476,7 +502,6 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) { int ret; - struct pvr2_hdw *hdw = cptr->hdw; struct v4l2_ext_controls cs; struct v4l2_ext_control c1; memset(&cs,0,sizeof(cs)); @@ -485,22 +510,10 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) cs.count = 1; c1.id = cptr->info->v4l_id; c1.value = v; - ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, - hdw->state_encoder_run, &cs, + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, VIDIOC_S_EXT_CTRLS); - if (ret == -EBUSY) { - /* Oops. cx2341x is telling us it's not safe to change - this control while we're capturing. Make a note of this - fact so that the pipeline will be stopped the next time - controls are committed. Then go on ahead and store this - change anyway. */ - ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, - 0, &cs, - VIDIOC_S_EXT_CTRLS); - if (!ret) hdw->enc_unsafe_stale = !0; - } if (ret) return ret; - hdw->enc_stale = !0; + cptr->hdw->enc_stale = !0; return 0; } @@ -531,13 +544,7 @@ static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) { - *vp = cptr->hdw->state_pipeline_req; - return 0; -} - -static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->master_state; + *vp = cptr->hdw->flag_streaming_enabled; return 0; } @@ -650,6 +657,29 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp) return 0; } +static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp) +{ + *vp = cptr->hdw->subsys_enabled_mask; + return 0; +} + +static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v) +{ + pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v); + return 0; +} + +static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp) +{ + *vp = cptr->hdw->subsys_stream_mask; + return 0; +} + +static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v) +{ + pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v); + return 0; +} static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v) { @@ -884,11 +914,6 @@ static const struct pvr2_ctl_info control_defs[] = { .name = "usb_speed", .get_value = ctrl_hsm_get, DEFENUM(control_values_hsm), - },{ - .desc = "Master State", - .name = "master_state", - .get_value = ctrl_masterstate_get, - DEFENUM(pvr2_state_names), },{ .desc = "Signal Present", .name = "signal_present", @@ -929,6 +954,20 @@ static const struct pvr2_ctl_info control_defs[] = { .val_to_sym = ctrl_std_val_to_sym, .sym_to_val = ctrl_std_sym_to_val, .type = pvr2_ctl_bitmask, + },{ + .desc = "Subsystem enabled mask", + .name = "debug_subsys_mask", + .skip_init = !0, + .get_value = ctrl_subsys_get, + .set_value = ctrl_subsys_set, + DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), + },{ + .desc = "Subsystem stream mask", + .name = "debug_subsys_stream_mask", + .skip_init = !0, + .get_value = ctrl_subsys_stream_get, + .set_value = ctrl_subsys_stream_set, + DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), },{ .desc = "Video Standard Name", .name = "video_standard", @@ -1090,13 +1129,25 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) unsigned int pipe; int ret; u16 address; + static const char *fw_files_29xxx[] = { + "v4l-pvrusb2-29xxx-01.fw", + }; + static const char *fw_files_24xxx[] = { + "v4l-pvrusb2-24xxx-01.fw", + }; + static const struct pvr2_string_table fw_file_defs[] = { + [PVR2_HDW_TYPE_29XXX] = { + fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx) + }, + [PVR2_HDW_TYPE_24XXX] = { + fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx) + }, + }; - if (!hdw->hdw_desc->fx2_firmware.cnt) { + if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) || + (!fw_file_defs[hdw->hdw_type].lst)) { hdw->fw1_state = FW1_STATE_OK; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Connected device type defines" - " no firmware to upload; ignoring firmware"); - return -ENOTTY; + return 0; } hdw->fw1_state = FW1_STATE_FAILED; // default result @@ -1104,8 +1155,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) trace_firmware("pvr2_upload_firmware1"); ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", - hdw->hdw_desc->fx2_firmware.cnt, - hdw->hdw_desc->fx2_firmware.lst); + fw_file_defs[hdw->hdw_type].cnt, + fw_file_defs[hdw->hdw_type].lst); if (ret < 0) { if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; return ret; @@ -1180,7 +1231,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) CX2341X_FIRM_ENC_FILENAME, }; - if (hdw->hdw_desc->flag_skip_cx23416_firmware) { + if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) && + (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) { return 0; } @@ -1196,6 +1248,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) time we configure the encoder, then we'll fully configure it. */ hdw->enc_cur_valid = 0; + hdw->flag_encoder_ok = 0; + /* First prepare firmware loading */ ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/ @@ -1293,129 +1347,293 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (ret) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "firmware2 upload post-proc failure"); + } else { + hdw->flag_encoder_ok = !0; + hdw->subsys_enabled_mask |= (1<decoder_ctrl) { - if (!hdw->flag_decoder_missed) { +/* + + This single function is key to pretty much everything. The pvrusb2 + device can logically be viewed as a series of subsystems which can be + stopped / started or unconfigured / configured. To get things streaming, + one must configure everything and start everything, but there may be + various reasons over time to deconfigure something or stop something. + This function handles all of this activity. Everything EVERYWHERE that + must affect a subsystem eventually comes here to do the work. + + The current state of all subsystems is represented by a single bit mask, + known as subsys_enabled_mask. The bit positions are defined by the + PVR2_SUBSYS_xxxx macros, with one subsystem per bit position. At any + time the set of configured or active subsystems can be queried just by + looking at that mask. To change bits in that mask, this function here + must be called. The "msk" argument indicates which bit positions to + change, and the "val" argument defines the new values for the positions + defined by "msk". + + There is a priority ordering of starting / stopping things, and for + multiple requested changes, this function implements that ordering. + (Thus we will act on a request to load encoder firmware before we + configure the encoder.) In addition to priority ordering, there is a + recovery strategy implemented here. If a particular step fails and we + detect that failure, this function will clear the affected subsystem bits + and restart. Thus we have a means for recovering from a dead encoder: + Clear all bits that correspond to subsystems that we need to restart / + reconfigure and start over. + +*/ +static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw, + unsigned long msk, + unsigned long val) +{ + unsigned long nmsk; + unsigned long vmsk; + int ret; + unsigned int tryCount = 0; + + if (!hdw->flag_ok) return; + + msk &= PVR2_SUBSYS_ALL; + nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk); + nmsk &= PVR2_SUBSYS_ALL; + + for (;;) { + tryCount++; + if (!((nmsk ^ hdw->subsys_enabled_mask) & + PVR2_SUBSYS_ALL)) break; + if (tryCount > 4) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: No decoder present"); - hdw->flag_decoder_missed = !0; - trace_stbit("flag_decoder_missed", - hdw->flag_decoder_missed); + "Too many retries when configuring device;" + " giving up"); + pvr2_hdw_render_useless(hdw); + break; + } + if (tryCount > 1) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Retrying device reconfiguration"); + } + pvr2_trace(PVR2_TRACE_INIT, + "subsys mask changing 0x%lx:0x%lx" + " from 0x%lx to 0x%lx", + msk,val,hdw->subsys_enabled_mask,nmsk); + + vmsk = (nmsk ^ hdw->subsys_enabled_mask) & + hdw->subsys_enabled_mask; + if (vmsk) { + if (vmsk & (1<subsys_enabled_mask &= + ~FIRMWARE_RECOVERY_BITS; + continue; + } + } + if (vmsk & (1<decoder_ctrl) { + hdw->decoder_ctrl->enable( + hdw->decoder_ctrl->ctxt,0); + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "WARNING:" + " No decoder present"); + } + hdw->subsys_enabled_mask &= + ~(1<subsys_enabled_mask &= + ~(vmsk & PVR2_SUBSYS_CFG_ALL); + } + } + vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk; + if (vmsk) { + if (vmsk & (1<subsys_enabled_mask &= + ~FIRMWARE_RECOVERY_BITS; + continue; + } + } + if (vmsk & (1<decoder_ctrl) { + hdw->decoder_ctrl->enable( + hdw->decoder_ctrl->ctxt,!0); + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "WARNING:" + " No decoder present"); + } + hdw->subsys_enabled_mask |= + (1<subsys_enabled_mask &= + ~FIRMWARE_RECOVERY_BITS; + continue; + } + } } - return -EIO; } - hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl); - return 0; } -void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr) +void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, + unsigned long msk,unsigned long val) { - if (hdw->decoder_ctrl == ptr) return; - hdw->decoder_ctrl = ptr; - if (hdw->decoder_ctrl && hdw->flag_decoder_missed) { - hdw->flag_decoder_missed = 0; - trace_stbit("flag_decoder_missed", - hdw->flag_decoder_missed); - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Decoder has appeared"); - pvr2_hdw_state_sched(hdw); - } + LOCK_TAKE(hdw->big_lock); do { + pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val); + } while (0); LOCK_GIVE(hdw->big_lock); } -int pvr2_hdw_get_state(struct pvr2_hdw *hdw) +unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw) { - return hdw->master_state; + return hdw->subsys_enabled_mask; } -static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw) +unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw) { - if (!hdw->flag_tripped) return 0; - hdw->flag_tripped = 0; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Clearing driver error statuss"); - return !0; + return hdw->subsys_stream_mask; } -int pvr2_hdw_untrip(struct pvr2_hdw *hdw) +static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, + unsigned long msk, + unsigned long val) +{ + unsigned long val2; + msk &= PVR2_SUBSYS_ALL; + val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk)); + pvr2_trace(PVR2_TRACE_INIT, + "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx", + msk,val,hdw->subsys_stream_mask,val2); + hdw->subsys_stream_mask = val2; +} + + +void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, + unsigned long msk, + unsigned long val) { - int fl; LOCK_TAKE(hdw->big_lock); do { - fl = pvr2_hdw_untrip_unlocked(hdw); + pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val); } while (0); LOCK_GIVE(hdw->big_lock); - if (fl) pvr2_hdw_state_sched(hdw); - return 0; } -const char *pvr2_hdw_get_state_name(unsigned int id) +static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl) { - if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL; - return pvr2_state_names[id]; + if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0; + if (enableFl) { + pvr2_trace(PVR2_TRACE_START_STOP, + "/*--TRACE_STREAM--*/ enable"); + pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0); + } else { + pvr2_trace(PVR2_TRACE_START_STOP, + "/*--TRACE_STREAM--*/ disable"); + pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); + } + if (!hdw->flag_ok) return -EIO; + hdw->flag_streaming_enabled = enableFl != 0; + return 0; } int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) { - return hdw->state_pipeline_req != 0; + return hdw->flag_streaming_enabled != 0; } int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) { - int ret,st; + int ret; LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_untrip_unlocked(hdw); - if ((!enable_flag) != !(hdw->state_pipeline_req)) { - hdw->state_pipeline_req = enable_flag != 0; - pvr2_trace(PVR2_TRACE_START_STOP, - "/*--TRACE_STREAM--*/ %s", - enable_flag ? "enable" : "disable"); - } - pvr2_hdw_state_sched(hdw); + ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag); } while (0); LOCK_GIVE(hdw->big_lock); - if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret; - if (enable_flag) { - while ((st = hdw->master_state) != PVR2_STATE_RUN) { - if (st != PVR2_STATE_READY) return -EIO; - if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret; - } - } + return ret; +} + + +static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw, + enum pvr2_config config) +{ + unsigned long sm = hdw->subsys_enabled_mask; + if (!hdw->flag_ok) return -EIO; + pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); + hdw->config = config; + pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm); return 0; } int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config) { - int fl; + int ret; + if (!hdw->flag_ok) return -EIO; LOCK_TAKE(hdw->big_lock); - if ((fl = (hdw->desired_stream_type != config)) != 0) { - hdw->desired_stream_type = config; - hdw->state_pipeline_config = 0; - trace_stbit("state_pipeline_config", - hdw->state_pipeline_config); - pvr2_hdw_state_sched(hdw); - } + ret = pvr2_hdw_set_stream_type_no_lock(hdw,config); LOCK_GIVE(hdw->big_lock); - if (fl) return 0; - return pvr2_hdw_wait(hdw,0); + return ret; } @@ -1428,7 +1646,6 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw) } if (tp < 0) return -EINVAL; hdw->tuner_type = tp; - hdw->tuner_updated = !0; return 0; } @@ -1439,9 +1656,8 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) int tp = 0; if ((unit_number >= 0) && (unit_number < PVR_NUM)) { tp = video_std[unit_number]; - if (tp) return tp; } - return 0; + return tp; } @@ -1515,7 +1731,7 @@ const static struct pvr2_std_hack std_eeprom_maps[] = { }, { /* PAL(D/D1/K) */ .pat = V4L2_STD_DK, - .std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K, + .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K, }, }; @@ -1523,20 +1739,18 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) { char buf[40]; unsigned int bcnt; - v4l2_std_id std1,std2,std3; + v4l2_std_id std1,std2; std1 = get_default_standard(hdw); - std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask; bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); pvr2_trace(PVR2_TRACE_STD, - "Supported video standard(s) reported available" - " in hardware: %.*s", + "Supported video standard(s) reported by eeprom: %.*s", bcnt,buf); hdw->std_mask_avail = hdw->std_mask_eeprom; - std2 = (std1|std3) & ~hdw->std_mask_avail; + std2 = std1 & ~hdw->std_mask_avail; if (std2) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); pvr2_trace(PVR2_TRACE_STD, @@ -1558,16 +1772,6 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) pvr2_hdw_internal_find_stdenum(hdw); return; } - if (std3) { - bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3); - pvr2_trace(PVR2_TRACE_STD, - "Initial video standard" - " (determined by device type): %.*s",bcnt,buf); - hdw->std_mask_cur = std3; - hdw->std_dirty = !0; - pvr2_hdw_internal_find_stdenum(hdw); - return; - } { unsigned int idx; @@ -1612,7 +1816,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) unsigned int idx; struct pvr2_ctrl *cptr; int reloadFl = 0; - if (hdw->hdw_desc->fx2_firmware.cnt) { + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { if (!reloadFl) { reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints @@ -1648,13 +1853,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } if (!pvr2_hdw_dev_ok(hdw)) return; - for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) { - request_module(hdw->hdw_desc->client_modules.lst[idx]); + if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) { + for (idx = 0; + idx < pvr2_client_lists[hdw->hdw_type].cnt; + idx++) { + request_module( + pvr2_client_lists[hdw->hdw_type].lst[idx]); + } } - if (!hdw->hdw_desc->flag_no_powerup) { + if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || + (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { pvr2_hdw_cmd_powerup(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; + + if (pvr2_upload_firmware2(hdw)){ + pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); + pvr2_hdw_render_useless(hdw); + return; + } } // This step MUST happen after the earlier powerup step. @@ -1682,22 +1899,15 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) // thread-safe against the normal pvr2_send_request() mechanism. // (We should make it thread safe). - if (hdw->hdw_desc->flag_has_hauppauge_rom) { - ret = pvr2_hdw_get_eeprom_addr(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Unable to determine location of eeprom," - " skipping"); - } else { - hdw->eeprom_addr = ret; - pvr2_eeprom_analyze(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - } + ret = pvr2_hdw_get_eeprom_addr(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; + if (ret < 0) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Unable to determine location of eeprom, skipping"); } else { - hdw->tuner_type = hdw->hdw_desc->default_tuner_type; - hdw->tuner_updated = !0; - hdw->std_mask_eeprom = V4L2_STD_ALL; + hdw->eeprom_addr = ret; + pvr2_eeprom_analyze(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; } pvr2_hdw_setup_std(hdw); @@ -1708,12 +1918,14 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) hdw->tuner_type); } + hdw->tuner_updated = !0; pvr2_i2c_core_check_stale(hdw); hdw->tuner_updated = 0; if (!pvr2_hdw_dev_ok(hdw)) return; - pvr2_hdw_commit_setup(hdw); + pvr2_hdw_commit_ctl_internal(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; hdw->vid_stream = pvr2_stream_create(); if (!pvr2_hdw_dev_ok(hdw)) return; @@ -1733,25 +1945,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) if (!pvr2_hdw_dev_ok(hdw)) return; - hdw->flag_init_ok = !0; + /* Make sure everything is up to date */ + pvr2_i2c_core_sync(hdw); + + if (!pvr2_hdw_dev_ok(hdw)) return; - pvr2_hdw_state_sched(hdw); + hdw->flag_init_ok = !0; } -/* Set up the structure and attempt to put the device into a usable state. - This can be a time-consuming operation, which is why it is not done - internally as part of the create() step. */ -static void pvr2_hdw_setup(struct pvr2_hdw *hdw) +int pvr2_hdw_setup(struct pvr2_hdw *hdw) { pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); - do { + LOCK_TAKE(hdw->big_lock); do { pvr2_hdw_setup_low(hdw); pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", - hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok); + hdw,hdw->flag_ok,hdw->flag_init_ok); if (pvr2_hdw_dev_ok(hdw)) { - if (hdw->flag_init_ok) { + if (pvr2_hdw_init_ok(hdw)) { pvr2_trace( PVR2_TRACE_INFO, "Device initialization" @@ -1801,8 +2013,9 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw) " the pvrusb2 device" " in order to recover."); } - } while (0); + } while (0); LOCK_GIVE(hdw->big_lock); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); + return hdw->flag_init_ok; } @@ -1813,32 +2026,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, { unsigned int idx,cnt1,cnt2; struct pvr2_hdw *hdw; + unsigned int hdw_type; int valid_std_mask; struct pvr2_ctrl *cptr; - const struct pvr2_device_desc *hdw_desc; __u8 ifnum; struct v4l2_queryctrl qctrl; struct pvr2_ctl_info *ciptr; - hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); + hdw_type = devid - pvr2_device_table; + if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Bogus device type of %u reported",hdw_type); + return NULL; + } hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", - hdw,hdw_desc->description); + hdw,pvr2_device_names[hdw_type]); if (!hdw) goto fail; - - init_timer(&hdw->quiescent_timer); - hdw->quiescent_timer.data = (unsigned long)hdw; - hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout; - - init_timer(&hdw->encoder_wait_timer); - hdw->encoder_wait_timer.data = (unsigned long)hdw; - hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout; - - hdw->master_state = PVR2_STATE_DEAD; - - init_waitqueue_head(&hdw->state_wait_data); - hdw->tuner_signal_stale = !0; cx2341x_fill_defaults(&hdw->enc_ctl_state); @@ -1847,7 +2052,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, GFP_KERNEL); if (!hdw->controls) goto fail; - hdw->hdw_desc = hdw_desc; + hdw->hdw_type = hdw_type; for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; cptr->hdw = hdw; @@ -1979,16 +2184,18 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; hdw->name[cnt1] = 0; - hdw->workqueue = create_singlethread_workqueue(hdw->name); - INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); - INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c); - INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init); - pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", hdw->unit_number,hdw->name); hdw->tuner_type = -1; hdw->flag_ok = !0; + /* Initialize the mask of subsystems that we will shut down when we + stop streaming. */ + hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL; + hdw->subsys_stream_mask |= (1<subsys_stream_mask); hdw->usb_intf = intf; hdw->usb_dev = interface_to_usbdev(intf); @@ -2004,25 +2211,15 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, mutex_init(&hdw->ctl_lock_mutex); mutex_init(&hdw->big_lock_mutex); - queue_work(hdw->workqueue,&hdw->workinit); return hdw; fail: if (hdw) { - del_timer_sync(&hdw->quiescent_timer); - del_timer_sync(&hdw->encoder_wait_timer); - if (hdw->workqueue) { - flush_workqueue(hdw->workqueue); - destroy_workqueue(hdw->workqueue); - hdw->workqueue = NULL; - } usb_free_urb(hdw->ctl_read_urb); usb_free_urb(hdw->ctl_write_urb); kfree(hdw->ctl_read_buffer); kfree(hdw->ctl_write_buffer); kfree(hdw->controls); kfree(hdw->mpeg_ctrl_info); - kfree(hdw->std_defs); - kfree(hdw->std_enum_names); kfree(hdw); } return NULL; @@ -2053,10 +2250,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) kfree(hdw->ctl_write_buffer); hdw->ctl_write_buffer = NULL; } + pvr2_hdw_render_useless_unlocked(hdw); hdw->flag_disconnected = !0; hdw->usb_dev = NULL; hdw->usb_intf = NULL; - pvr2_hdw_render_useless(hdw); } @@ -2065,13 +2262,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) { if (!hdw) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); - del_timer_sync(&hdw->quiescent_timer); - del_timer_sync(&hdw->encoder_wait_timer); - if (hdw->workqueue) { - flush_workqueue(hdw->workqueue); - destroy_workqueue(hdw->workqueue); - hdw->workqueue = NULL; - } if (hdw->fw_buffer) { kfree(hdw->fw_buffer); hdw->fw_buffer = NULL; @@ -2100,6 +2290,12 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) } +int pvr2_hdw_init_ok(struct pvr2_hdw *hdw) +{ + return hdw->flag_init_ok; +} + + int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw) { return (hdw && hdw->flag_ok); @@ -2277,11 +2473,17 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp) } -/* Figure out if we need to commit control changes. If so, mark internal - state flags to indicate this fact and return true. Otherwise do nothing - else and return false. */ -static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) +/* Commit all control changes made up to this point. Subsystems can be + indirectly affected by these changes. For a given set of things being + committed, we'll clear the affected subsystem bits and then once we're + done committing everything we'll make a request to restore the subsystem + state(s) back to their previous value before this function was called. + Thus we can automatically reconfigure affected pieces of the driver as + controls are changed. */ +static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) { + unsigned long saved_subsys_mask = hdw->subsys_enabled_mask; + unsigned long stale_subsys_mask = 0; unsigned int idx; struct pvr2_ctrl *cptr; int value; @@ -2316,25 +2518,6 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) return 0; } - hdw->state_pipeline_config = 0; - trace_stbit("state_pipeline_config",hdw->state_pipeline_config); - pvr2_hdw_state_sched(hdw); - - return !0; -} - - -/* Perform all operations needed to commit all control changes. This must - be performed in synchronization with the pipeline state and is thus - expected to be called as part of the driver's worker thread. Return - true if commit successful, otherwise return false to indicate that - commit isn't possible at this time. */ -static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) -{ - unsigned int idx; - struct pvr2_ctrl *cptr; - int disruptive_change; - /* When video standard changes, reset the hres and vres values - but if the user has pending changes there, then let the changes take priority. */ @@ -2353,26 +2536,24 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) } } - /* If any of the below has changed, then we can't do the update - while the pipeline is running. Pipeline must be paused first - and decoder -> encoder connection be made quiescent before we - can proceed. */ - disruptive_change = - (hdw->std_dirty || - hdw->enc_unsafe_stale || - hdw->srate_dirty || - hdw->res_ver_dirty || - hdw->res_hor_dirty || - hdw->input_dirty || - (hdw->active_stream_type != hdw->desired_stream_type)); - if (disruptive_change && !hdw->state_pipeline_idle) { - /* Pipeline is not idle; we can't proceed. Arrange to - cause pipeline to stop so that we can try this again - later.... */ - hdw->state_pipeline_pause = !0; - return 0; + if (hdw->std_dirty || + hdw->enc_stale || + hdw->srate_dirty || + hdw->res_ver_dirty || + hdw->res_hor_dirty || + 0) { + /* If any of this changes, then the encoder needs to be + reconfigured, and we need to reset the stream. */ + stale_subsys_mask |= (1<input_dirty) { + /* pk: If input changes to or from radio, then the encoder + needs to be restarted (for ENC_MUTE_VIDEO to work) */ + stale_subsys_mask |= (1<srate_dirty) { /* Write new sample rate into control structure since * the master copy is stale. We must track srate @@ -2401,88 +2582,51 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) cptr->info->clear_dirty(cptr); } - if (hdw->active_stream_type != hdw->desired_stream_type) { - /* Handle any side effects of stream config here */ - hdw->active_stream_type = hdw->desired_stream_type; - } - /* Now execute i2c core update */ pvr2_i2c_core_sync(hdw); - if (hdw->state_encoder_run) { - /* If encoder isn't running, then this will get worked out - later when we start the encoder. */ - if (pvr2_encoder_adjust(hdw) < 0) return !0; - } + pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0); + pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask); - hdw->state_pipeline_config = !0; - trace_stbit("state_pipeline_config",hdw->state_pipeline_config); - return !0; + return 0; } int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw) { - int fl; - LOCK_TAKE(hdw->big_lock); - fl = pvr2_hdw_commit_setup(hdw); - LOCK_GIVE(hdw->big_lock); - if (!fl) return 0; - return pvr2_hdw_wait(hdw,0); -} - - -static void pvr2_hdw_worker_i2c(struct work_struct *work) -{ - struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync); LOCK_TAKE(hdw->big_lock); do { - pvr2_i2c_core_sync(hdw); + pvr2_hdw_commit_ctl_internal(hdw); } while (0); LOCK_GIVE(hdw->big_lock); + return 0; } -static void pvr2_hdw_worker_poll(struct work_struct *work) +void pvr2_hdw_poll(struct pvr2_hdw *hdw) { - int fl = 0; - struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll); LOCK_TAKE(hdw->big_lock); do { - fl = pvr2_hdw_state_eval(hdw); + pvr2_i2c_core_sync(hdw); } while (0); LOCK_GIVE(hdw->big_lock); - if (fl && hdw->state_func) { - hdw->state_func(hdw->state_data); - } } -static void pvr2_hdw_worker_init(struct work_struct *work) +void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw, + void (*func)(void *), + void *data) { - struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit); LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_setup(hdw); + hdw->poll_trigger_func = func; + hdw->poll_trigger_data = data; } while (0); LOCK_GIVE(hdw->big_lock); } -static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) -{ - return wait_event_interruptible( - hdw->state_wait_data, - (hdw->state_stale == 0) && - (!state || (hdw->master_state != state))); -} - - -void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw, - void (*callback_func)(void *), - void *callback_data) +void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw) { - LOCK_TAKE(hdw->big_lock); do { - hdw->state_data = callback_data; - hdw->state_func = callback_func; - } while (0); LOCK_GIVE(hdw->big_lock); + if (hdw->poll_trigger_func) { + hdw->poll_trigger_func(hdw->poll_trigger_data); + } } - /* Return name for this driver instance */ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) { @@ -2490,18 +2634,6 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) } -const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw) -{ - return hdw->hdw_desc->description; -} - - -const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw) -{ - return hdw->hdw_desc->shortname; -} - - int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw) { int result; @@ -2557,7 +2689,6 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) pvr2_i2c_core_sync(hdw); pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); - pvr2_hdw_state_log_state(hdw); printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); } while (0); LOCK_GIVE(hdw->big_lock); } @@ -2828,7 +2959,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, " without lock!!"); return -EDEADLK; } - if (!hdw->flag_ok && !probe_fl) { + if ((!hdw->flag_ok) && !probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Attempted to execute control transfer" " when device not ok"); @@ -3036,7 +3167,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, hdw->cmd_debug_state = 0; if ((status < 0) && (!probe_fl)) { - pvr2_hdw_render_useless(hdw); + pvr2_hdw_render_useless_unlocked(hdw); } return status; } @@ -3096,17 +3227,24 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data) } -void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) +static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw) { if (!hdw->flag_ok) return; - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Device being rendered inoperable"); + pvr2_trace(PVR2_TRACE_INIT,"render_useless"); + hdw->flag_ok = 0; if (hdw->vid_stream) { pvr2_stream_setup(hdw->vid_stream,NULL,0,0); } - hdw->flag_ok = 0; - trace_stbit("flag_ok",hdw->flag_ok); - pvr2_hdw_state_sched(hdw); + hdw->flag_streaming_enabled = 0; + hdw->subsys_enabled_mask = 0; +} + + +void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) +{ + LOCK_TAKE(hdw->ctl_lock); + pvr2_hdw_render_useless_unlocked(hdw); + LOCK_GIVE(hdw->ctl_lock); } @@ -3161,6 +3299,7 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw) int status; LOCK_TAKE(hdw->ctl_lock); do { pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset"); + hdw->flag_ok = !0; hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET; status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0); } while (0); LOCK_GIVE(hdw->ctl_lock); @@ -3210,473 +3349,26 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF); status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0); } while (0); LOCK_GIVE(hdw->ctl_lock); - return status; -} - - -/* Evaluate whether or not state_encoder_ok can change */ -static int state_eval_encoder_ok(struct pvr2_hdw *hdw) -{ - if (hdw->state_encoder_ok) return 0; - if (hdw->flag_tripped) return 0; - if (hdw->state_encoder_run) return 0; - if (hdw->state_encoder_config) return 0; - if (hdw->state_decoder_run) return 0; - if (hdw->state_usbstream_run) return 0; - if (pvr2_upload_firmware2(hdw) < 0) { - hdw->flag_tripped = !0; - trace_stbit("flag_tripped",hdw->flag_tripped); - return !0; - } - hdw->state_encoder_ok = !0; - trace_stbit("state_encoder_ok",hdw->state_encoder_ok); - return !0; -} - - -/* Evaluate whether or not state_encoder_config can change */ -static int state_eval_encoder_config(struct pvr2_hdw *hdw) -{ - if (hdw->state_encoder_config) { - if (hdw->state_encoder_ok) { - if (hdw->state_pipeline_req && - !hdw->state_pipeline_pause) return 0; - } - hdw->state_encoder_config = 0; - hdw->state_encoder_waitok = 0; - trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); - /* paranoia - solve race if timer just completed */ - del_timer_sync(&hdw->encoder_wait_timer); - } else { - if (!hdw->state_encoder_ok || - !hdw->state_pipeline_idle || - hdw->state_pipeline_pause || - !hdw->state_pipeline_req || - !hdw->state_pipeline_config) { - /* We must reset the enforced wait interval if - anything has happened that might have disturbed - the encoder. This should be a rare case. */ - if (timer_pending(&hdw->encoder_wait_timer)) { - del_timer_sync(&hdw->encoder_wait_timer); - } - if (hdw->state_encoder_waitok) { - /* Must clear the state - therefore we did - something to a state bit and must also - return true. */ - hdw->state_encoder_waitok = 0; - trace_stbit("state_encoder_waitok", - hdw->state_encoder_waitok); - return !0; - } - return 0; - } - if (!hdw->state_encoder_waitok) { - if (!timer_pending(&hdw->encoder_wait_timer)) { - /* waitok flag wasn't set and timer isn't - running. Check flag once more to avoid - a race then start the timer. This is - the point when we measure out a minimal - quiet interval before doing something to - the encoder. */ - if (!hdw->state_encoder_waitok) { - hdw->encoder_wait_timer.expires = - jiffies + (HZ*50/1000); - add_timer(&hdw->encoder_wait_timer); - } - } - /* We can't continue until we know we have been - quiet for the interval measured by this - timer. */ - return 0; - } - pvr2_encoder_configure(hdw); - if (hdw->state_encoder_ok) hdw->state_encoder_config = !0; - } - trace_stbit("state_encoder_config",hdw->state_encoder_config); - return !0; -} - - -/* Evaluate whether or not state_encoder_run can change */ -static int state_eval_encoder_run(struct pvr2_hdw *hdw) -{ - if (hdw->state_encoder_run) { - if (hdw->state_encoder_ok) { - if (hdw->state_decoder_run) return 0; - if (pvr2_encoder_stop(hdw) < 0) return !0; - } - hdw->state_encoder_run = 0; - } else { - if (!hdw->state_encoder_ok) return 0; - if (!hdw->state_decoder_run) return 0; - if (pvr2_encoder_start(hdw) < 0) return !0; - hdw->state_encoder_run = !0; - } - trace_stbit("state_encoder_run",hdw->state_encoder_run); - return !0; -} - - -/* Timeout function for quiescent timer. */ -static void pvr2_hdw_quiescent_timeout(unsigned long data) -{ - struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; - hdw->state_decoder_quiescent = !0; - trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); - hdw->state_stale = !0; - queue_work(hdw->workqueue,&hdw->workpoll); -} - - -/* Timeout function for encoder wait timer. */ -static void pvr2_hdw_encoder_wait_timeout(unsigned long data) -{ - struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; - hdw->state_encoder_waitok = !0; - trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); - hdw->state_stale = !0; - queue_work(hdw->workqueue,&hdw->workpoll); -} - - -/* Evaluate whether or not state_decoder_run can change */ -static int state_eval_decoder_run(struct pvr2_hdw *hdw) -{ - if (hdw->state_decoder_run) { - if (hdw->state_encoder_ok) { - if (hdw->state_pipeline_req && - !hdw->state_pipeline_pause) return 0; - } - if (!hdw->flag_decoder_missed) { - pvr2_decoder_enable(hdw,0); - } - hdw->state_decoder_quiescent = 0; - hdw->state_decoder_run = 0; - /* paranoia - solve race if timer just completed */ - del_timer_sync(&hdw->quiescent_timer); - } else { - if (!hdw->state_decoder_quiescent) { - if (!timer_pending(&hdw->quiescent_timer)) { - /* We don't do something about the - quiescent timer until right here because - we also want to catch cases where the - decoder was already not running (like - after initialization) as opposed to - knowing that we had just stopped it. - The second flag check is here to cover a - race - the timer could have run and set - this flag just after the previous check - but before we did the pending check. */ - if (!hdw->state_decoder_quiescent) { - hdw->quiescent_timer.expires = - jiffies + (HZ*50/1000); - add_timer(&hdw->quiescent_timer); - } - } - /* Don't allow decoder to start again until it has - been quiesced first. This little detail should - hopefully further stabilize the encoder. */ - return 0; - } - if (!hdw->state_pipeline_req || - hdw->state_pipeline_pause || - !hdw->state_pipeline_config || - !hdw->state_encoder_config || - !hdw->state_encoder_ok) return 0; - del_timer_sync(&hdw->quiescent_timer); - if (hdw->flag_decoder_missed) return 0; - if (pvr2_decoder_enable(hdw,!0) < 0) return 0; - hdw->state_decoder_quiescent = 0; - hdw->state_decoder_run = !0; - } - trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); - trace_stbit("state_decoder_run",hdw->state_decoder_run); - return !0; -} - - -/* Evaluate whether or not state_usbstream_run can change */ -static int state_eval_usbstream_run(struct pvr2_hdw *hdw) -{ - if (hdw->state_usbstream_run) { - if (hdw->state_encoder_ok) { - if (hdw->state_encoder_run) return 0; - } - pvr2_hdw_cmd_usbstream(hdw,0); - hdw->state_usbstream_run = 0; - } else { - if (!hdw->state_encoder_ok || - !hdw->state_encoder_run || - !hdw->state_pipeline_req || - hdw->state_pipeline_pause) return 0; - if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0; - hdw->state_usbstream_run = !0; - } - trace_stbit("state_usbstream_run",hdw->state_usbstream_run); - return !0; -} - - -/* Attempt to configure pipeline, if needed */ -static int state_eval_pipeline_config(struct pvr2_hdw *hdw) -{ - if (hdw->state_pipeline_config || - hdw->state_pipeline_pause) return 0; - pvr2_hdw_commit_execute(hdw); - return !0; -} - - -/* Update pipeline idle and pipeline pause tracking states based on other - inputs. This must be called whenever the other relevant inputs have - changed. */ -static int state_update_pipeline_state(struct pvr2_hdw *hdw) -{ - unsigned int st; - int updatedFl = 0; - /* Update pipeline state */ - st = !(hdw->state_encoder_run || - hdw->state_decoder_run || - hdw->state_usbstream_run || - (!hdw->state_decoder_quiescent)); - if (!st != !hdw->state_pipeline_idle) { - hdw->state_pipeline_idle = st; - updatedFl = !0; - } - if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) { - hdw->state_pipeline_pause = 0; - updatedFl = !0; + if (!status) { + hdw->subsys_enabled_mask = + ((hdw->subsys_enabled_mask & + ~(1<state_stale) return 0; - if ((hdw->fw1_state != FW1_STATE_OK) || - !hdw->flag_ok) { - hdw->state_stale = 0; - return !0; - } - /* This loop is the heart of the entire driver. It keeps trying to - evaluate various bits of driver state until nothing changes for - one full iteration. Each "bit of state" tracks some global - aspect of the driver, e.g. whether decoder should run, if - pipeline is configured, usb streaming is on, etc. We separately - evaluate each of those questions based on other driver state to - arrive at the correct running configuration. */ - do { - check_flag = 0; - state_update_pipeline_state(hdw); - /* Iterate over each bit of state */ - for (i = 0; (iflag_ok; i++) { - if ((*eval_funcs[i])(hdw)) { - check_flag = !0; - state_updated = !0; - state_update_pipeline_state(hdw); - } - } - } while (check_flag && hdw->flag_ok); - hdw->state_stale = 0; - trace_stbit("state_stale",hdw->state_stale); - return state_updated; -} - - -static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, - char *buf,unsigned int acnt) -{ - switch (which) { - case 0: - return scnprintf( - buf,acnt, - "driver:%s%s%s%s%s", - (hdw->flag_ok ? " " : " "), - (hdw->flag_init_ok ? " " : " "), - (hdw->flag_disconnected ? " " : - " "), - (hdw->flag_tripped ? " " : ""), - (hdw->flag_decoder_missed ? " " : "")); - case 1: - return scnprintf( - buf,acnt, - "pipeline:%s%s%s%s", - (hdw->state_pipeline_idle ? " " : ""), - (hdw->state_pipeline_config ? - " " : " "), - (hdw->state_pipeline_req ? " " : ""), - (hdw->state_pipeline_pause ? " " : "")); - case 2: - return scnprintf( - buf,acnt, - "worker:%s%s%s%s%s%s", - (hdw->state_decoder_run ? - " " : - (hdw->state_decoder_quiescent ? - "" : " ")), - (hdw->state_decoder_quiescent ? - " " : ""), - (hdw->state_encoder_ok ? - "" : " "), - (hdw->state_encoder_run ? - " " : " "), - (hdw->state_encoder_config ? - " " : - (hdw->state_encoder_waitok ? - "" : " ")), - (hdw->state_usbstream_run ? - " " : " ")); - break; - case 3: - return scnprintf( - buf,acnt, - "state: %s", - pvr2_get_state_name(hdw->master_state)); - break; - default: break; - } - return 0; -} - - -unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, - char *buf,unsigned int acnt) -{ - unsigned int bcnt,ccnt,idx; - bcnt = 0; - LOCK_TAKE(hdw->big_lock); - for (idx = 0; ; idx++) { - ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt); - if (!ccnt) break; - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - if (!acnt) break; - buf[0] = '\n'; ccnt = 1; - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - } - LOCK_GIVE(hdw->big_lock); - return bcnt; -} - - -static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw) -{ - char buf[128]; - unsigned int idx,ccnt; - - for (idx = 0; ; idx++) { - ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf)); - if (!ccnt) break; - printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf); - } -} - - -/* Evaluate and update the driver's current state, taking various actions - as appropriate for the update. */ -static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw) -{ - unsigned int st; - int state_updated = 0; - int callback_flag = 0; - - pvr2_trace(PVR2_TRACE_STBITS, - "Drive state check START"); - if (pvrusb2_debug & PVR2_TRACE_STBITS) { - pvr2_hdw_state_log_state(hdw); - } - - /* Process all state and get back over disposition */ - state_updated = pvr2_hdw_state_update(hdw); - - /* Update master state based upon all other states. */ - if (!hdw->flag_ok) { - st = PVR2_STATE_DEAD; - } else if (hdw->fw1_state != FW1_STATE_OK) { - st = PVR2_STATE_COLD; - } else if (!hdw->state_encoder_ok) { - st = PVR2_STATE_WARM; - } else if (hdw->flag_tripped || hdw->flag_decoder_missed) { - st = PVR2_STATE_ERROR; - } else if (hdw->state_encoder_run && - hdw->state_decoder_run && - hdw->state_usbstream_run) { - st = PVR2_STATE_RUN; - } else { - st = PVR2_STATE_READY; - } - if (hdw->master_state != st) { - pvr2_trace(PVR2_TRACE_STATE, - "Device state change from %s to %s", - pvr2_get_state_name(hdw->master_state), - pvr2_get_state_name(st)); - hdw->master_state = st; - state_updated = !0; - callback_flag = !0; - } - if (state_updated) { - /* Trigger anyone waiting on any state changes here. */ - wake_up(&hdw->state_wait_data); - } - - if (pvrusb2_debug & PVR2_TRACE_STBITS) { - pvr2_hdw_state_log_state(hdw); - } - pvr2_trace(PVR2_TRACE_STBITS, - "Drive state check DONE callback=%d",callback_flag); - - return callback_flag; -} - - -/* Cause kernel thread to check / update driver state */ -static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) -{ - if (hdw->state_stale) return; - hdw->state_stale = !0; - trace_stbit("state_stale",hdw->state_stale); - queue_work(hdw->workqueue,&hdw->workpoll); + return status; } -void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *ptr) +void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *ptr) { ptr->big_lock_held = hdw->big_lock_held; ptr->ctl_lock_held = hdw->ctl_lock_held; + ptr->flag_ok = hdw->flag_ok; ptr->flag_disconnected = hdw->flag_disconnected; ptr->flag_init_ok = hdw->flag_init_ok; - ptr->flag_ok = hdw->flag_ok; - ptr->fw1_state = hdw->fw1_state; - ptr->flag_decoder_missed = hdw->flag_decoder_missed; - ptr->flag_tripped = hdw->flag_tripped; - ptr->state_encoder_ok = hdw->state_encoder_ok; - ptr->state_encoder_run = hdw->state_encoder_run; - ptr->state_decoder_run = hdw->state_decoder_run; - ptr->state_usbstream_run = hdw->state_usbstream_run; - ptr->state_decoder_quiescent = hdw->state_decoder_quiescent; - ptr->state_pipeline_config = hdw->state_pipeline_config; - ptr->state_pipeline_req = hdw->state_pipeline_req; - ptr->state_pipeline_pause = hdw->state_pipeline_pause; - ptr->state_pipeline_idle = hdw->state_pipeline_idle; + ptr->flag_streaming_enabled = hdw->flag_streaming_enabled; + ptr->subsys_flags = hdw->subsys_enabled_mask; ptr->cmd_debug_state = hdw->cmd_debug_state; ptr->cmd_code = hdw->cmd_debug_code; ptr->cmd_debug_write_len = hdw->cmd_debug_write_len; @@ -3689,15 +3381,6 @@ void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, } -void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *ptr) -{ - LOCK_TAKE(hdw->ctl_lock); do { - pvr2_hdw_get_debug_info_unlocked(hdw,ptr); - } while(0); LOCK_GIVE(hdw->ctl_lock); -} - - int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) { return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp); diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 3ad7a13d6c39..e2f9d5e4cb65 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -44,6 +44,27 @@ #define PVR2_CVAL_INPUT_COMPOSITE 2 #define PVR2_CVAL_INPUT_RADIO 3 +/* Subsystem definitions - these are various pieces that can be + independently stopped / started. Usually you don't want to mess with + this directly (let the driver handle things itself), but it is useful + for debugging. */ +#define PVR2_SUBSYS_B_ENC_FIRMWARE 0 +#define PVR2_SUBSYS_B_ENC_CFG 1 +#define PVR2_SUBSYS_B_DIGITIZER_RUN 2 +#define PVR2_SUBSYS_B_USBSTREAM_RUN 3 +#define PVR2_SUBSYS_B_ENC_RUN 4 + +#define PVR2_SUBSYS_CFG_ALL ( \ + (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \ + (1 << PVR2_SUBSYS_B_ENC_CFG) ) +#define PVR2_SUBSYS_RUN_ALL ( \ + (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \ + (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \ + (1 << PVR2_SUBSYS_B_ENC_RUN) ) +#define PVR2_SUBSYS_ALL ( \ + PVR2_SUBSYS_CFG_ALL | \ + PVR2_SUBSYS_RUN_ALL ) + enum pvr2_config { pvr2_config_empty, /* No configuration */ pvr2_config_mpeg, /* Encoded / compressed video */ @@ -58,41 +79,8 @@ enum pvr2_v4l_type { pvr2_v4l_type_radio, }; -/* Major states that we can be in: - * - * DEAD - Device is in an unusable state and cannot be recovered. This - * can happen if we completely lose the ability to communicate with it - * (but it might still on the bus). In this state there's nothing we can - * do; it must be replugged in order to recover. - * - * COLD - Device is in an unusuable state, needs microcontroller firmware. - * - * WARM - We can communicate with the device and the proper - * microcontroller firmware is running, but other device initialization is - * still needed (e.g. encoder firmware). - * - * ERROR - A problem prevents capture operation (e.g. encoder firmware - * missing). - * - * READY - Device is operational, but not streaming. - * - * RUN - Device is streaming. - * - */ -#define PVR2_STATE_NONE 0 -#define PVR2_STATE_DEAD 1 -#define PVR2_STATE_COLD 2 -#define PVR2_STATE_WARM 3 -#define PVR2_STATE_ERROR 4 -#define PVR2_STATE_READY 5 -#define PVR2_STATE_RUN 6 - -/* Translate configuration enum to a string label */ const char *pvr2_config_get_name(enum pvr2_config); -/* Translate a master state enum to a string label */ -const char *pvr2_hdw_get_state_name(unsigned int); - struct pvr2_hdw; /* Create and return a structure for interacting with the underlying @@ -100,13 +88,28 @@ struct pvr2_hdw; struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, const struct usb_device_id *devid); +/* Poll for background activity (if any) */ +void pvr2_hdw_poll(struct pvr2_hdw *); + +/* Trigger a poll to take place later at a convenient time */ +void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *); + +/* Register a callback used to trigger a future poll */ +void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *, + void (*func)(void *), + void *data); + /* Destroy hardware interaction structure */ void pvr2_hdw_destroy(struct pvr2_hdw *); -/* Register a function to be called whenever the master state changes. */ -void pvr2_hdw_set_state_callback(struct pvr2_hdw *, - void (*callback_func)(void *), - void *callback_data); +/* Set up the structure and attempt to put the device into a usable state. + This can be a time-consuming operation, which is why it is not done + internally as part of the create() step. Return value is exactly the + same as pvr2_hdw_init_ok(). */ +int pvr2_hdw_setup(struct pvr2_hdw *); + +/* Initialization succeeded */ +int pvr2_hdw_init_ok(struct pvr2_hdw *); /* Return true if in the ready (normal) state */ int pvr2_hdw_dev_ok(struct pvr2_hdw *); @@ -158,21 +161,12 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *); /* Query device and see if it thinks it is on a high-speed USB link */ int pvr2_hdw_is_hsm(struct pvr2_hdw *); -/* Return a string token representative of the hardware type */ -const char *pvr2_hdw_get_type(struct pvr2_hdw *); - -/* Return a single line description of the hardware type */ -const char *pvr2_hdw_get_desc(struct pvr2_hdw *); - /* Turn streaming on/off */ int pvr2_hdw_set_streaming(struct pvr2_hdw *,int); /* Find out if streaming is on */ int pvr2_hdw_get_streaming(struct pvr2_hdw *); -/* Retrieve driver overall state */ -int pvr2_hdw_get_state(struct pvr2_hdw *); - /* Configure the type of stream to generate */ int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config); @@ -183,6 +177,26 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std, unsigned int idx); +/* Enable / disable various pieces of hardware. Items to change are + identified by bit positions within msk, and new state for each item is + identified by corresponding bit positions within val. */ +void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, + unsigned long msk,unsigned long val); + +/* Retrieve mask indicating which pieces of hardware are currently enabled + / configured. */ +unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *); + +/* Adjust mask of what get shut down when streaming is stopped. This is a + debugging aid. */ +void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, + unsigned long msk,unsigned long val); + +/* Retrieve mask indicating which pieces of hardware are disabled when + streaming is turned off. */ +unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); + + /* Enable / disable retrieval of CPU firmware or prom contents. This must be enabled before pvr2_hdw_cpufw_get() will function. Note that doing this may prevent the device from running (and leaving this mode may @@ -239,9 +253,6 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int); /* Execute a USB-commanded device reset */ void pvr2_hdw_device_reset(struct pvr2_hdw *); -/* Reset worker's error trapping circuit breaker */ -int pvr2_hdw_untrip(struct pvr2_hdw *); - /* Execute hard reset command (after this point it's likely that the encoder will have to be reconfigured). This also clears the "useless" state. */ @@ -264,21 +275,11 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val); struct pvr2_hdw_debug_info { int big_lock_held; int ctl_lock_held; + int flag_ok; int flag_disconnected; int flag_init_ok; - int flag_ok; - int fw1_state; - int flag_decoder_missed; - int flag_tripped; - int state_encoder_ok; - int state_encoder_run; - int state_decoder_run; - int state_usbstream_run; - int state_decoder_quiescent; - int state_pipeline_config; - int state_pipeline_req; - int state_pipeline_pause; - int state_pipeline_idle; + int flag_streaming_enabled; + unsigned long subsys_flags; int cmd_debug_state; int cmd_debug_write_len; int cmd_debug_read_len; @@ -294,20 +295,8 @@ struct pvr2_hdw_debug_info { diagnosing lockups. Note that this operation is completed without any kind of locking and so it is not atomic and may yield inconsistent results. This is *purely* a debugging aid. */ -void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *); - -/* Intrusively retrieve internal state info - this is useful for - diagnosing overall driver state. This operation synchronizes against - the overall driver mutex - so if there are locking problems this will - likely hang! This is *purely* a debugging aid. */ -void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *); - -/* Report out several lines of text that describes driver internal state. - Results are written into the passed-in buffer. */ -unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, - char *buf_ptr,unsigned int buf_size); +void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *); /* Cause modules to log their state once */ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); @@ -317,6 +306,9 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); a debugging aid. */ int pvr2_upload_firmware2(struct pvr2_hdw *hdw); +/* List of device types that we can match */ +extern struct usb_device_id pvr2_device_table[]; + #endif /* __PVRUSB2_HDW_H */ /* diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 62867fa3517a..c817c864e6a0 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client) list_add_tail(&cp->list,&hdw->i2c_clients); hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT; } while (0); mutex_unlock(&hdw->i2c_list_lock); - if (fl) queue_work(hdw->workqueue,&hdw->worki2csync); + if (fl) pvr2_hdw_poll_trigger_unlocked(hdw); return 0; } @@ -980,15 +980,13 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: IR disabled\n",hdw->name); hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) { + if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { hdw->i2c_func[0x18] = i2c_24xxx_ir; } } - if (hdw->hdw_desc->flag_has_cx25840) { - hdw->i2c_func[0x44] = i2c_hack_cx25840; - } - if (hdw->hdw_desc->flag_has_wm8775) { + if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { hdw->i2c_func[0x1b] = i2c_hack_wm8775; + hdw->i2c_func[0x44] = i2c_hack_cx25840; } // Configure the adapter and set up everything else related to it. diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c index b63b2265503a..11b3b2e84b90 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -28,7 +28,6 @@ #include #include "pvrusb2-hdw.h" -#include "pvrusb2-devattr.h" #include "pvrusb2-context.h" #include "pvrusb2-debug.h" #include "pvrusb2-v4l2.h" @@ -149,6 +148,11 @@ static void __exit pvr_exit(void) module_init(pvr_init); module_exit(pvr_exit); +/* Mike Isely 11-Mar-2006: See pvrusb2-hdw.c for + MODULE_DEVICE_TABLE(). We have to declare that attribute there + because that's where the device table actually is now and it seems + that certain gcc configurations get angry if MODULE_DEVICE_TABLE() + is used on what ends up being an external symbol. */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-std.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-std.c index da309288daa4..63e55bb59fcb 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -50,10 +50,6 @@ struct std_name { V4L2_STD_NTSC_M_KR| \ V4L2_STD_NTSC_443) -#define CSTD_ATSC \ - (V4L2_STD_ATSC_8_VSB| \ - V4L2_STD_ATSC_16_VSB) - #define CSTD_SECAM \ (V4L2_STD_SECAM_B| \ V4L2_STD_SECAM_D| \ @@ -86,7 +82,6 @@ static const struct std_name std_groups[] = { {"PAL",CSTD_PAL}, {"NTSC",CSTD_NTSC}, {"SECAM",CSTD_SECAM}, - {"ATSC",CSTD_ATSC}, }; /* Mapping of standard bits to modulation system */ @@ -109,8 +104,6 @@ static const struct std_name std_items[] = { {"N",TSTD_N}, {"Nc",TSTD_Nc}, {"60",TSTD_60}, - {"8VSB",V4L2_STD_ATSC_8_VSB}, - {"16VSB",V4L2_STD_ATSC_16_VSB}, }; diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 7a1cd878e31a..3c57a7d8200b 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -43,14 +43,10 @@ struct pvr2_sysfs { struct device_attribute attr_v4l_radio_minor_number; struct device_attribute attr_unit_number; struct device_attribute attr_bus_info; - struct device_attribute attr_hdw_name; - struct device_attribute attr_hdw_desc; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; int bus_info_created_ok; - int hdw_name_created_ok; - int hdw_desc_created_ok; }; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC @@ -716,14 +712,6 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) pvr2_sysfs_tear_down_debugifc(sfp); #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); - if (sfp->hdw_desc_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_hdw_desc); - } - if (sfp->hdw_name_created_ok) { - device_remove_file(sfp->class_dev, - &sfp->attr_hdw_name); - } if (sfp->bus_info_created_ok) { device_remove_file(sfp->class_dev, &sfp->attr_bus_info); @@ -770,28 +758,6 @@ static ssize_t bus_info_show(struct device *class_dev, } -static ssize_t hdw_name_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", - pvr2_hdw_get_type(sfp->channel.hdw)); -} - - -static ssize_t hdw_desc_show(struct device *class_dev, - struct device_attribute *attr, char *buf) -{ - struct pvr2_sysfs *sfp; - sfp = (struct pvr2_sysfs *)class_dev->driver_data; - if (!sfp) return -EINVAL; - return scnprintf(buf,PAGE_SIZE,"%s\n", - pvr2_hdw_get_desc(sfp->channel.hdw)); -} - - static ssize_t v4l_radio_minor_number_show(struct device *class_dev, struct device_attribute *attr, char *buf) @@ -905,32 +871,6 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->bus_info_created_ok = !0; } - sfp->attr_hdw_name.attr.name = "device_hardware_type"; - sfp->attr_hdw_name.attr.mode = S_IRUGO; - sfp->attr_hdw_name.show = hdw_name_show; - sfp->attr_hdw_name.store = NULL; - ret = device_create_file(sfp->class_dev, - &sfp->attr_hdw_name); - if (ret < 0) { - printk(KERN_WARNING "%s: device_create_file error: %d\n", - __FUNCTION__, ret); - } else { - sfp->hdw_name_created_ok = !0; - } - - sfp->attr_hdw_desc.attr.name = "device_hardware_description"; - sfp->attr_hdw_desc.attr.mode = S_IRUGO; - sfp->attr_hdw_desc.show = hdw_desc_show; - sfp->attr_hdw_desc.store = NULL; - ret = device_create_file(sfp->class_dev, - &sfp->attr_hdw_desc); - if (ret < 0) { - printk(KERN_WARNING "%s: device_create_file error: %d\n", - __FUNCTION__, ret); - } else { - sfp->hdw_desc_created_ok = !0; - } - pvr2_sysfs_add_controls(sfp); #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC pvr2_sysfs_add_debugifc(sfp); diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 8f0587ebd4bd..7a596ea7cfe6 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -205,7 +205,6 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), sizeof(cap->bus_info)); - strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card)); ret = 0; break; @@ -1016,8 +1015,10 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) sp = fh->dev_info->stream->stream; pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh); pvr2_hdw_set_stream_type(hdw,fh->dev_info->config); - if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret; - return pvr2_ioread_set_enabled(fh->rhp,!0); + pvr2_hdw_set_streaming(hdw,!0); + ret = pvr2_ioread_set_enabled(fh->rhp,!0); + + return ret; } diff --git a/trunk/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/trunk/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 7c47345501b6..61efa6f02200 100644 --- a/trunk/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/trunk/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -49,50 +49,29 @@ struct pvr2_v4l_decoder { }; -struct routing_scheme { - const int *def; - unsigned int cnt; -}; - - -static const int routing_scheme0[] = { - [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4, - /* In radio mode, we mute the video, but point at one - spot just to stay consistent */ - [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5, - [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5, - [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, -}; - -static const struct routing_scheme routing_schemes[] = { - [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { - .def = routing_scheme0, - .cnt = ARRAY_SIZE(routing_scheme0), - }, -}; - static void set_input(struct pvr2_v4l_decoder *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; - const struct routing_scheme *sp; - unsigned int sid = hdw->hdw_desc->signal_routing_scheme; pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val); - - if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes + sid) != 0) && - (hdw->input_val >= 0) && - (hdw->input_val < sp->cnt)) { - route.input = sp->def[hdw->input_val]; - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** i2c v4l2 set_input:" - " Invalid routing scheme (%u) and/or input (%d)", - sid,hdw->input_val); + switch(hdw->input_val) { + case PVR2_CVAL_INPUT_TV: + route.input = SAA7115_COMPOSITE4; + break; + case PVR2_CVAL_INPUT_COMPOSITE: + route.input = SAA7115_COMPOSITE5; + break; + case PVR2_CVAL_INPUT_SVIDEO: + route.input = SAA7115_SVIDEO2; + break; + case PVR2_CVAL_INPUT_RADIO: + // In radio mode, we mute the video, but point at one + // spot just to stay consistent + route.input = SAA7115_COMPOSITE5; + default: return; } - route.output = 0; pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route); } @@ -150,7 +129,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = { static void decoder_detach(struct pvr2_v4l_decoder *ctxt) { ctxt->client->handler = NULL; - pvr2_hdw_set_decoder(ctxt->hdw,NULL); + ctxt->hdw->decoder_ctrl = NULL; kfree(ctxt); } @@ -238,7 +217,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw, ctxt->client = cp; ctxt->hdw = hdw; ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1; - pvr2_hdw_set_decoder(hdw,&ctxt->ctrl); + hdw->decoder_ctrl = &ctxt->ctrl; cp->handler = &ctxt->handler; pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up", cp->client->addr); diff --git a/trunk/drivers/media/video/saa7115.c b/trunk/drivers/media/video/saa7115.c index 41e5e518a47e..2d18f0069821 100644 --- a/trunk/drivers/media/video/saa7115.c +++ b/trunk/drivers/media/video/saa7115.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include @@ -1231,7 +1230,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client, /* ============ SAA7115 AUDIO settings (end) ============= */ -static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct saa711x_state *state = i2c_get_clientdata(client); @@ -1450,17 +1449,26 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar /* ----------------------------------------------------------------------- */ -static int saa7115_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver_saa711x; + +static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct saa711x_state *state; int i; char name[17]; u8 chip_id; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver_saa711x; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); for (i = 0; i < 0x0f; i++) { @@ -1477,16 +1485,18 @@ static int saa7115_probe(struct i2c_client *client) /* Check whether this chip is part of the saa711x series */ if (memcmp(name, "1f711", 5)) { v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", - client->addr << 1, name); - return -ENODEV; + address << 1, name); + kfree(client); + return 0; } snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); - v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name); + v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name); state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); i2c_set_clientdata(client, state); if (state == NULL) { + kfree(client); return -ENOMEM; } state->input = -1; @@ -1539,25 +1549,59 @@ static int saa7115_probe(struct i2c_client *client) saa711x_writeregs(client, saa7115_init_misc); saa711x_set_v4lstd(client, V4L2_STD_NTSC); + i2c_attach_client(client); + v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n", saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC)); + return 0; } -/* ----------------------------------------------------------------------- */ +static int saa711x_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL) + return i2c_probe(adapter, &addr_data, &saa711x_attach); + return 0; +} -static int saa7115_remove(struct i2c_client *client) +static int saa711x_detach(struct i2c_client *client) { - kfree(i2c_get_clientdata(client)); + struct saa711x_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + + kfree(state); + kfree(client); return 0; } -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "saa7115", - .driverid = I2C_DRIVERID_SAA711X, - .command = saa7115_command, - .probe = saa7115_probe, - .remove = saa7115_remove, - .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver_saa711x = { + .driver = { + .name = "saa7115", + }, + .id = I2C_DRIVERID_SAA711X, + .attach_adapter = saa711x_probe, + .detach_client = saa711x_detach, + .command = saa711x_command, }; + +static int __init saa711x_init_module(void) +{ + return i2c_add_driver(&i2c_driver_saa711x); +} + +static void __exit saa711x_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver_saa711x); +} + +module_init(saa711x_init_module); +module_exit(saa711x_cleanup_module); diff --git a/trunk/drivers/media/video/saa7127.c b/trunk/drivers/media/video/saa7127.c index 06c88db656b4..e35ef321ec71 100644 --- a/trunk/drivers/media/video/saa7127.c +++ b/trunk/drivers/media/video/saa7127.c @@ -55,11 +55,10 @@ #include #include #include -#include #include -static int debug; -static int test_image; +static int debug = 0; +static int test_image = 0; MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver"); MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); @@ -69,6 +68,10 @@ module_param(test_image, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_PARM_DESC(test_image, "test_image (0-1)"); +static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; /* * SAA7127 registers @@ -357,10 +360,9 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data if (enable && (data->field != 0 || data->line != 21)) return -EINVAL; if (state->cc_enable != enable) { - v4l_dbg(1, debug, client, - "Turn CC %s\n", enable ? "on" : "off"); + v4l_dbg(1, debug, client, "Turn CC %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, - (state->xds_enable << 7) | (enable << 6) | 0x11); + (state->xds_enable << 7) | (enable << 6) | 0x11); state->cc_enable = enable; } if (!enable) @@ -418,8 +420,7 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat saa7127_write(client, 0x26, data->data[0]); saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f)); - v4l_dbg(1, debug, client, - "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); + v4l_dbg(1, debug, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; return 0; } @@ -506,8 +507,7 @@ static int saa7127_set_output_type(struct i2c_client *client, int output) default: return -EINVAL; } - v4l_dbg(1, debug, client, - "Selecting %s output type\n", output_strs[output]); + v4l_dbg(1, debug, client, "Selecting %s output type\n", output_strs[output]); /* Configure Encoder */ saa7127_write(client, 0x2d, state->reg_2d); @@ -569,10 +569,12 @@ static int saa7127_command(struct i2c_client *client, { int rc = 0; - if (state->input_type != route->input) + if (state->input_type != route->input) { rc = saa7127_set_input_type(client, route->input); - if (rc == 0 && state->output_type != route->output) + } + if (rc == 0 && state->output_type != route->output) { rc = saa7127_set_output_type(client, route->output); + } return rc; } @@ -618,8 +620,7 @@ static int saa7127_command(struct i2c_client *client, { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, - reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -636,16 +637,16 @@ static int saa7127_command(struct i2c_client *client, struct v4l2_sliced_vbi_data *data = arg; switch (data->id) { - case V4L2_SLICED_WSS_625: - return saa7127_set_wss(client, data); - case V4L2_SLICED_VPS: - return saa7127_set_vps(client, data); - case V4L2_SLICED_CAPTION_525: - if (data->field == 0) - return saa7127_set_cc(client, data); - return saa7127_set_xds(client, data); - default: - return -EINVAL; + case V4L2_SLICED_WSS_625: + return saa7127_set_wss(client, data); + case V4L2_SLICED_VPS: + return saa7127_set_vps(client, data); + case V4L2_SLICED_CAPTION_525: + if (data->field == 0) + return saa7127_set_cc(client, data); + return saa7127_set_xds(client, data); + default: + return -EINVAL; } break; } @@ -661,20 +662,31 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -static int saa7127_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver_saa7127; + +/* ----------------------------------------------------------------------- */ + +static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ int read_result = 0; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver_saa7127; snprintf(client->name, sizeof(client->name) - 1, "saa7127"); - v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", - client->addr << 1); + v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1); /* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0. @@ -684,12 +696,15 @@ static int saa7127_probe(struct i2c_client *client) if ((saa7127_read(client, 0) & 0xe4) != 0 || (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { v4l_dbg(1, debug, client, "saa7127 not found\n"); - return -ENODEV; + kfree(client); + return 0; } state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; + if (state == NULL) { + kfree(client); + return (-ENOMEM); + } i2c_set_clientdata(client, state); @@ -703,48 +718,91 @@ static int saa7127_probe(struct i2c_client *client) saa7127_set_wss(client, &vbi); saa7127_set_cc(client, &vbi); saa7127_set_xds(client, &vbi); - if (test_image == 1) + if (test_image == 1) { /* The Encoder has an internal Colorbar generator */ /* This can be used for debugging */ saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE); - else + } else { saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL); + } saa7127_set_video_enable(client, 1); /* Detect if it's an saa7129 */ read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - v4l_info(client, "saa7129 found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); saa7127_write_inittab(client, saa7129_init_config_extra); state->ident = V4L2_IDENT_SAA7129; } else { - v4l_info(client, "saa7127 found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name); state->ident = V4L2_IDENT_SAA7127; } + + i2c_attach_client(client); + return 0; } /* ----------------------------------------------------------------------- */ -static int saa7127_remove(struct i2c_client *client) +static int saa7127_probe(struct i2c_adapter *adapter) { + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, saa7127_attach); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int saa7127_detach(struct i2c_client *client) +{ + struct saa7127_state *state = i2c_get_clientdata(client); + int err; + /* Turn off TV output */ saa7127_set_video_enable(client, 0); - kfree(i2c_get_clientdata(client)); + + err = i2c_detach_client(client); + + if (err) { + return err; + } + + kfree(state); + kfree(client); return 0; } /* ----------------------------------------------------------------------- */ -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "saa7127", - .driverid = I2C_DRIVERID_SAA7127, +static struct i2c_driver i2c_driver_saa7127 = { + .driver = { + .name = "saa7127", + }, + .id = I2C_DRIVERID_SAA7127, + .attach_adapter = saa7127_probe, + .detach_client = saa7127_detach, .command = saa7127_command, - .probe = saa7127_probe, - .remove = saa7127_remove, }; + +/* ----------------------------------------------------------------------- */ + +static int __init saa7127_init_module(void) +{ + return i2c_add_driver(&i2c_driver_saa7127); +} + +/* ----------------------------------------------------------------------- */ + +static void __exit saa7127_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver_saa7127); +} + +/* ----------------------------------------------------------------------- */ + +module_init(saa7127_init_module); +module_exit(saa7127_cleanup_module); diff --git a/trunk/drivers/media/video/saa7134/Kconfig b/trunk/drivers/media/video/saa7134/Kconfig index 96bc3b1298a2..3aa8cb2b860a 100644 --- a/trunk/drivers/media/video/saa7134/Kconfig +++ b/trunk/drivers/media/video/saa7134/Kconfig @@ -4,7 +4,6 @@ config VIDEO_SAA7134 select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER - select VIDEO_TVEEPROM select CRC32 ---help--- This is a video4linux driver for Philips SAA713x based @@ -24,6 +23,18 @@ config VIDEO_SAA7134_ALSA To compile this driver as a module, choose M here: the module will be called saa7134-alsa. +config VIDEO_SAA7134_OSS + tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)" + depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA + ---help--- + This is a video4linux driver for direct (DMA) audio in + Philips SAA713x based TV cards using OSS + + This is deprecated in favor of the ALSA module + + To compile this driver as a module, choose M here: the + module will be called saa7134-oss. + config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE diff --git a/trunk/drivers/media/video/saa7134/Makefile b/trunk/drivers/media/video/saa7134/Makefile index 9aff937ba7a5..c85c8a8ec361 100644 --- a/trunk/drivers/media/video/saa7134/Makefile +++ b/trunk/drivers/media/video/saa7134/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ saa6752hs.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o +obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o diff --git a/trunk/drivers/media/video/saa7134/saa7134-alsa.c b/trunk/drivers/media/video/saa7134/saa7134-alsa.c index ba2531034a91..4878f3067787 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-alsa.c +++ b/trunk/drivers/media/video/saa7134/saa7134-alsa.c @@ -1077,14 +1077,24 @@ static int saa7134_alsa_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; - saa7134_dmasound_init = alsa_device_init; - saa7134_dmasound_exit = alsa_device_exit; + if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { + saa7134_dmasound_init = alsa_device_init; + saa7134_dmasound_exit = alsa_device_exit; + } else { + printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n"); + return -EBUSY; + } printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); - alsa_device_init(dev); + if (dev->dmasound.priv_data == NULL) { + alsa_device_init(dev); + } else { + printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name); + return -EBUSY; + } } if (dev == NULL) diff --git a/trunk/drivers/media/video/saa7134/saa7134-cards.c b/trunk/drivers/media/video/saa7134/saa7134-cards.c index 7d7f383b404f..98c1b084a716 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-cards.c +++ b/trunk/drivers/media/video/saa7134/saa7134-cards.c @@ -26,7 +26,6 @@ #include "saa7134-reg.h" #include "saa7134.h" #include -#include /* commly used strings */ static char name_mute[] = "mute"; @@ -350,10 +349,6 @@ struct saa7134_board saa7134_boards[] = { .name = name_radio, .amux = LINE2, }, - .mute = { - .name = name_mute, - .amux = TV, - }, }, [SAA7134_BOARD_TVSTATION_RDS] = { /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ @@ -570,10 +565,6 @@ struct saa7134_board saa7134_boards[] = { .radio = { .name = name_radio, .amux = LINE2, - }, - .mute = { - .name = name_mute, - .amux = TV, }, }, [SAA7134_BOARD_TYPHOON_90031] = { @@ -3562,356 +3553,6 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, }}, }, - [SAA7134_BOARD_BEHOLD_401] = { - .name = "Beholder BeholdTV 401", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - }, - [SAA7134_BOARD_BEHOLD_403] = { - .name = "Beholder BeholdTV 403", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_BEHOLD_403FM] = { - .name = "Beholder BeholdTV 403 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FQ1216ME, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_405] = { - .name = "Beholder BeholdTV 405", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - }, - [SAA7134_BOARD_BEHOLD_405FM] = { - /* Sergey */ - .name = "Beholder BeholdTV 405 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - },{ - .name = name_comp1, - .vmux = 3, - .amux = LINE1, - },{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_407] = { - .name = "Beholder BeholdTV 407", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0xc0c000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - .gpio = 0xc0c000, - }}, - }, - [SAA7134_BOARD_BEHOLD_407FM] = { - .name = "Beholder BeholdTV 407 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .gpiomask = 0xc0c000, - .inputs = {{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - .gpio = 0xc0c000, - },{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - .gpio = 0xc0c000, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - .gpio = 0xc0c000, - }, - }, - [SAA7134_BOARD_BEHOLD_409] = { - .name = "Beholder BeholdTV 409", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - }, - [SAA7134_BOARD_BEHOLD_505FM] = { - .name = "Beholder BeholdTV 505 FM/RDS", - .audio_clock = 0x00200000, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = LINE2, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .mute = { - .name = name_mute, - .amux = LINE1, - }, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_507_9FM] = { - .name = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = { - .name = "Beholder BeholdTV Columbus TVFM", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_ALPS_TSBE5_PAL, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_607_9FM] = { - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV 607 / BeholdTV 609", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - }, - [SAA7134_BOARD_BEHOLD_M6] = { - /* Igor Kuznetsov */ - /* Andrey Melnikoff */ - .name = "Beholder BeholdTV M6 / BeholdTV M6 Extra", - .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .tda9887_conf = TDA9887_PRESENT, - .inputs = {{ - .name = name_tv, - .vmux = 3, - .amux = TV, - .tv = 1, - },{ - .name = name_comp1, - .vmux = 1, - .amux = LINE1, - },{ - .name = name_svideo, - .vmux = 8, - .amux = LINE1, - }}, - .radio = { - .name = name_radio, - .amux = LINE2, - }, - .mpeg = SAA7134_MPEG_EMPRESS, - }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4392,13 +4033,7 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1462, - .subdevice = 0x6231, /* tda8275a, ks003 IR */ - .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, - .subdevice = 0x8624, /* tda8275, ks003 IR */ + .subdevice = 0x6231, .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4568,42 +4203,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1043, .subdevice = 0x4876, .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6700, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6701, .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6702, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6703, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6704, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6705, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -4682,162 +4287,6 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4016, - .driver_data = SAA7134_BOARD_BEHOLD_401, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4036, - .driver_data = SAA7134_BOARD_BEHOLD_403, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4037, - .driver_data = SAA7134_BOARD_BEHOLD_403FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4050, - .driver_data = SAA7134_BOARD_BEHOLD_405, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4051, - .driver_data = SAA7134_BOARD_BEHOLD_405FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4070, - .driver_data = SAA7134_BOARD_BEHOLD_407, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4071, - .driver_data = SAA7134_BOARD_BEHOLD_407FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x4090, - .driver_data = SAA7134_BOARD_BEHOLD_409, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x5051, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x505B, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5ace, - .subdevice = 0x5050, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5071, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x507B, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x5070, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x5090, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5201, - .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6070, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6071, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6072, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6073, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6090, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6091, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6092, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6093, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6190, - .driver_data = SAA7134_BOARD_BEHOLD_M6, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6193, - .driver_data = SAA7134_BOARD_BEHOLD_M6, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -4902,34 +4351,6 @@ static void board_flyvideo(struct saa7134_dev *dev) /* ----------------------------------------------------------- */ -static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) -{ - struct tveeprom tv; - - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); - - /* Make sure we support the board model */ - switch (tv.model) { - case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ - case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ - case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ - case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */ - case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ - case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ - case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ - break; - default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", dev->name, tv.model); - break; - } - - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", - dev->name, tv.model); -} - -/* ----------------------------------------------------------- */ - int saa7134_board_init1(struct saa7134_dev *dev) { /* Always print gpio, often manufacturers encode tuner type and other info. */ @@ -4985,16 +4406,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_ENCORE_ENLTV: case SAA7134_BOARD_ENCORE_ENLTV_FM: case SAA7134_BOARD_10MOONSTVMASTER3: - case SAA7134_BOARD_BEHOLD_401: - case SAA7134_BOARD_BEHOLD_403: - case SAA7134_BOARD_BEHOLD_403FM: - case SAA7134_BOARD_BEHOLD_405: - case SAA7134_BOARD_BEHOLD_405FM: - case SAA7134_BOARD_BEHOLD_407: - case SAA7134_BOARD_BEHOLD_407FM: - case SAA7134_BOARD_BEHOLD_409: - case SAA7134_BOARD_BEHOLD_505FM: - case SAA7134_BOARD_BEHOLD_507_9FM: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: @@ -5034,7 +4445,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000); break; case SAA7134_BOARD_AVERMEDIA_CARDBUS: - case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); @@ -5056,8 +4466,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_UPMOST_PURPLE_TV: case SAA7134_BOARD_HAUPPAUGE_HVR1110: - case SAA7134_BOARD_BEHOLD_607_9FM: - case SAA7134_BOARD_BEHOLD_M6: dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: @@ -5069,7 +4477,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_AVERMEDIA_M102: /* enable tuner */ - dev->has_remote = SAA7134_REMOTE_GPIO; saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); break; @@ -5163,17 +4570,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - dev->tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); + dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE; + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf); } tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; @@ -5203,6 +4601,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: + case SAA7134_BOARD_AVERMEDIA_SUPER_007: { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; @@ -5223,16 +4622,13 @@ int saa7134_board_init2(struct saa7134_dev *dev) i2c_transfer(&dev->i2c_adap, &msg, 1); } break; - case SAA7134_BOARD_HAUPPAUGE_HVR1110: - hauppauge_eeprom(dev, dev->eedata+0x80); - /* break intentionally omitted */ case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_KWORLD_DVBT_210: case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: - case SAA7134_BOARD_AVERMEDIA_SUPER_007: + case SAA7134_BOARD_HAUPPAUGE_HVR1110: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ diff --git a/trunk/drivers/media/video/saa7134/saa7134-core.c b/trunk/drivers/media/video/saa7134/saa7134-core.c index 52baa4f7f7dd..4f0a9157ecb1 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-core.c +++ b/trunk/drivers/media/video/saa7134/saa7134-core.c @@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + buf->vb.state = STATE_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, buf->activate(dev,buf,NULL); } else if (list_empty(&q->queue)) { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = VIDEOBUF_QUEUED; + buf->vb.state = STATE_QUEUED; } else { next = list_entry(q->queue.next,struct saa7134_buf, vb.queue); @@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, } } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = VIDEOBUF_QUEUED; + buf->vb.state = STATE_QUEUED; } return 0; } @@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data) try to start over with the next one. */ if (q->curr) { dprintk("timeout on %p\n",q->curr); - saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR); + saa7134_buffer_finish(dev,q,STATE_ERROR); } saa7134_buffer_next(dev,q); spin_unlock_irqrestore(&dev->slock,flags); @@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data) /* resends a current buffer in queue after resume */ -static int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q) +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) { struct saa7134_buf *buf, *next; @@ -834,7 +834,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, vfd->minor = -1; vfd->dev = &dev->pci->dev; vfd->release = video_device_release; - vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, saa7134_boards[dev->board].name); return vfd; @@ -1053,9 +1052,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, printk(KERN_INFO "%s: registered device video%d [v4l2]\n", dev->name,dev->video_dev->minor & 0x1f); - dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); - dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT; - + dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi"); err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) @@ -1184,13 +1181,8 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) saa_writel(SAA7134_IRQ2, 0); saa_writel(SAA7134_MAIN_CTRL, 0); - dev->insuspend = 1; synchronize_irq(pci_dev->irq); - - /* ACK interrupts once more, just in case, - since the IRQ handler won't ack them anymore*/ - - saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT)); + dev->insuspend = 1; /* Disable timeout timers - if we have active buffers, we will fill them on resume*/ @@ -1202,10 +1194,10 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) if (dev->remote) saa7134_ir_stop(dev); - pci_save_state(pci_dev); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + pci_save_state(pci_dev); - return 0; + return 0; } static int saa7134_resume(struct pci_dev *pci_dev) @@ -1213,8 +1205,8 @@ static int saa7134_resume(struct pci_dev *pci_dev) struct saa7134_dev *dev = pci_get_drvdata(pci_dev); unsigned long flags; - pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); + pci_set_power_state(pci_dev, PCI_D0); /* Do things that are done in saa7134_initdev , except of initializing memory structures.*/ @@ -1230,7 +1222,6 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_ir_start(dev, dev->remote); saa7134_hw_enable1(dev); - msleep(100); saa7134_board_init2(dev); @@ -1238,13 +1229,10 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_set_tvnorm_hw(dev); saa7134_tvaudio_setmute(dev); saa7134_tvaudio_setvolume(dev, dev->ctl_volume); - saa7134_tvaudio_init(dev); saa7134_tvaudio_do_scan(dev); saa7134_enable_i2s(dev); saa7134_hw_enable2(dev); - saa7134_irq_video_signalchange(dev); - /*resume unfinished buffer(s)*/ spin_lock_irqsave(&dev->slock, flags); saa7134_buffer_requeue(dev, &dev->video_q); @@ -1258,7 +1246,6 @@ static int saa7134_resume(struct pci_dev *pci_dev) /* start DMA now*/ dev->insuspend = 0; - smp_wmb(); saa7134_set_dmabits(dev); spin_unlock_irqrestore(&dev->slock, flags); diff --git a/trunk/drivers/media/video/saa7134/saa7134-dvb.c b/trunk/drivers/media/video/saa7134/saa7134-dvb.c index a9ca5730826f..e1ab099ec4c6 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-dvb.c +++ b/trunk/drivers/media/video/saa7134/saa7134-dvb.c @@ -1073,21 +1073,14 @@ static int dvb_init(struct saa7134_dev *dev) static int dvb_fini(struct saa7134_dev *dev) { - /* FIXME: I suspect that this code is bogus, since the entry for - Pinnacle 300I DVB-T PAL already defines the proper init to allow - the detection of mt2032 (TDA9887_PORT2_INACTIVE) - */ - if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) { - struct v4l2_priv_tun_config tda9887_cfg; - static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &on; + static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + switch (dev->board) { + case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: /* otherwise we don't detect the tuner on next insmod */ - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg); - } - + saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); + break; + }; videobuf_dvb_unregister(&dev->dvb); return 0; } diff --git a/trunk/drivers/media/video/saa7134/saa7134-empress.c b/trunk/drivers/media/video/saa7134/saa7134-empress.c index b1b01fa86720..9322f44865b8 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-empress.c +++ b/trunk/drivers/media/video/saa7134/saa7134-empress.c @@ -161,176 +161,152 @@ ts_mmap(struct file *file, struct vm_area_struct * vma) * video_generic_ioctl (and maybe others). userspace * copying is done already, arg is a kernel pointer. */ - -static int empress_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - return 0; -} - -static int empress_enum_input(struct file *file, void *priv, - struct v4l2_input *i) +static int ts_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { - if (i->index != 0) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, "CCIR656"); - - return 0; -} - -static int empress_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int empress_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - - return 0; -} - -static int empress_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index != 0) - return -EINVAL; - - strlcpy(f->description, "MPEG TS", sizeof(f->description)); - f->pixelformat = V4L2_PIX_FMT_MPEG; - - return 0; -} - -static int empress_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f); - - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - - return 0; -} - -static int empress_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f); + struct saa7134_dev *dev = file->private_data; + struct v4l2_ext_controls *ctrls = arg; + + if (debug > 1) + v4l_print_ioctl(dev->name,cmd); + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + return 0; + } - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; + /* --- input switching --------------------------------------- */ + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; - return 0; -} + if (i->index != 0) + return -EINVAL; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name,"CCIR656"); + return 0; + } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = 0; + return 0; + } + case VIDIOC_S_INPUT: + { + int *i = arg; + if (*i != 0) + return -EINVAL; + return 0; + } + /* --- capture ioctls ---------------------------------------- */ + + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + int index; + + index = f->index; + if (index != 0) + return -EINVAL; + + memset(f,0,sizeof(*f)); + f->index = index; + strlcpy(f->description, "MPEG TS", sizeof(f->description)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->pixelformat = V4L2_PIX_FMT_MPEG; + return 0; + } -static int empress_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; - return videobuf_reqbufs(&dev->empress_tsq, p); -} + memset(f,0,sizeof(*f)); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; -static int empress_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + saa7134_i2c_call_clients(dev, cmd, arg); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; + return 0; + } - return videobuf_querybuf(&dev->empress_tsq, b); -} + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; -static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; - return videobuf_qbuf(&dev->empress_tsq, b); -} + saa7134_i2c_call_clients(dev, cmd, arg); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE* dev->ts.nr_packets; + return 0; + } -static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + case VIDIOC_REQBUFS: + return videobuf_reqbufs(&dev->empress_tsq,arg); - return videobuf_dqbuf(&dev->empress_tsq, b, - file->f_flags & O_NONBLOCK); -} + case VIDIOC_QUERYBUF: + return videobuf_querybuf(&dev->empress_tsq,arg); -static int empress_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + case VIDIOC_QBUF: + return videobuf_qbuf(&dev->empress_tsq,arg); - return videobuf_streamon(&dev->empress_tsq); -} + case VIDIOC_DQBUF: + return videobuf_dqbuf(&dev->empress_tsq,arg, + file->f_flags & O_NONBLOCK); -static int empress_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + case VIDIOC_STREAMON: + return videobuf_streamon(&dev->empress_tsq); - return videobuf_streamoff(&dev->empress_tsq); -} + case VIDIOC_STREAMOFF: + return videobuf_streamoff(&dev->empress_tsq); -static int empress_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + case VIDIOC_QUERYCTRL: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: + return saa7134_common_ioctl(dev, cmd, arg); - /* count == 0 is abused in saa6752hs.c, so that special - case is handled here explicitly. */ - if (ctrls->count == 0) + case VIDIOC_S_EXT_CTRLS: + /* count == 0 is abused in saa6752hs.c, so that special + case is handled here explicitly. */ + if (ctrls->count == 0) + return 0; + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg); + ts_init_encoder(dev); + return 0; + case VIDIOC_G_EXT_CTRLS: + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg); return 0; - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls); - ts_init_encoder(dev); - + default: + return -ENOIOCTLCMD; + } return 0; } -static int empress_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) +static int ts_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls); - - return 0; + return video_usercopy(inode, file, cmd, arg, ts_do_ioctl); } static const struct file_operations ts_fops = @@ -341,7 +317,7 @@ static const struct file_operations ts_fops = .read = ts_read, .poll = ts_poll, .mmap = ts_mmap, - .ioctl = video_ioctl2, + .ioctl = ts_ioctl, .llseek = no_llseek, }; @@ -354,29 +330,6 @@ static struct video_device saa7134_empress_template = .type2 = 0 /* FIXME */, .fops = &ts_fops, .minor = -1, - - .vidioc_querycap = empress_querycap, - .vidioc_enum_fmt_cap = empress_enum_fmt_cap, - .vidioc_s_fmt_cap = empress_s_fmt_cap, - .vidioc_g_fmt_cap = empress_g_fmt_cap, - .vidioc_reqbufs = empress_reqbufs, - .vidioc_querybuf = empress_querybuf, - .vidioc_qbuf = empress_qbuf, - .vidioc_dqbuf = empress_dqbuf, - .vidioc_streamon = empress_streamon, - .vidioc_streamoff = empress_streamoff, - .vidioc_s_ext_ctrls = empress_s_ext_ctrls, - .vidioc_g_ext_ctrls = empress_g_ext_ctrls, - .vidioc_enum_input = empress_enum_input, - .vidioc_g_input = empress_g_input, - .vidioc_s_input = empress_s_input, - - .vidioc_queryctrl = saa7134_queryctrl, - .vidioc_g_ctrl = saa7134_g_ctrl, - .vidioc_s_ctrl = saa7134_s_ctrl, - - .tvnorms = SAA7134_NORMS, - .current_norm = V4L2_STD_PAL, }; static void empress_signal_update(struct work_struct *work) diff --git a/trunk/drivers/media/video/saa7134/saa7134-i2c.c b/trunk/drivers/media/video/saa7134/saa7134-i2c.c index d3322c3018f2..6deaad1a5480 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-i2c.c +++ b/trunk/drivers/media/video/saa7134/saa7134-i2c.c @@ -323,6 +323,7 @@ static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; + int conf = dev->tda9887_conf; struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", @@ -334,7 +335,6 @@ static int attach_inform(struct i2c_client *client) case 0x7a: case 0x47: case 0x71: - case 0x2d: { struct IR_i2c *ir = i2c_get_clientdata(client); d1printk("%s i2c IR detected (%s).\n", @@ -360,6 +360,7 @@ static int attach_inform(struct i2c_client *client) } if (tuner != UNSET) { + tun_setup.type = tuner; tun_setup.addr = saa7134_boards[dev->board].tuner_addr; tun_setup.config = saa7134_boards[dev->board].tuner_config; @@ -371,18 +372,9 @@ static int attach_inform(struct i2c_client *client) client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); } - - if (tuner == TUNER_TDA9887) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, - &tda9887_cfg); - } } + client->driver->command(client, TDA9887_SET_CONFIG, &conf); return 0; } @@ -440,7 +432,6 @@ static char *i2c_devs[128] = { [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", [ 0x86 >> 1 ] = "tda9887", - [ 0x5a >> 1 ] = "remote control", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/trunk/drivers/media/video/saa7134/saa7134-input.c b/trunk/drivers/media/video/saa7134/saa7134-input.c index 0db955c2d9b9..3abaa1b8ac9d 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-input.c +++ b/trunk/drivers/media/video/saa7134/saa7134-input.c @@ -49,14 +49,9 @@ module_param(repeat_delay, int, 0644); MODULE_PARM_DESC(repeat_delay, "delay before key repeat started"); static int repeat_period = 33; module_param(repeat_period, int, 0644); -MODULE_PARM_DESC(repeat_period, "repeat period between " +MODULE_PARM_DESC(repeat_period, "repeat period between" "keypresses when key is down"); -static unsigned int disable_other_ir; -module_param(disable_other_ir, int, 0644); -MODULE_PARM_DESC(disable_other_ir, "disable full codes of " - "alternative remotes from other manufacturers"); - #define dprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) #define i2cdprintk(fmt, arg...) if (ir_debug) \ @@ -159,45 +154,6 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } - -static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char data[12]; - u32 gpio; - - struct saa7134_dev *dev = ir->c.adapter->algo_data; - - /* rising SAA7134_GPIO_GPRESCAN reads the status */ - saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); - - gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - - if (0x400000 & ~gpio) - return 0; /* No button press */ - - ir->c.addr = 0x5a >> 1; - - if (12 != i2c_master_recv(&ir->c, data, 12)) { - i2cdprintk("read error\n"); - return -EIO; - } - /* IR of this card normally decode signals NEC-standard from - * - Sven IHOO MT 5.1R remote. xxyye718 - * - Sven DVD HD-10xx remote. xxyyf708 - * - BBK ... - * - mayby others - * So, skip not our, if disable full codes mode. - */ - if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir) - return 0; - - *ir_key = data[9]; - *ir_raw = data[9]; - - return 1; -} - void saa7134_input_irq(struct saa7134_dev *dev) { struct card_ir *ir = dev->remote; @@ -304,7 +260,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_507: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: - case SAA7134_BOARD_AVERMEDIA_M102: ir_codes = ir_codes_avermedia; mask_keycode = 0x0007C8; mask_keydown = 0x000010; @@ -332,16 +287,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_BEHOLD_409FM: - case SAA7134_BOARD_BEHOLD_401: - case SAA7134_BOARD_BEHOLD_403: - case SAA7134_BOARD_BEHOLD_403FM: - case SAA7134_BOARD_BEHOLD_405: - case SAA7134_BOARD_BEHOLD_405FM: - case SAA7134_BOARD_BEHOLD_407: - case SAA7134_BOARD_BEHOLD_407FM: - case SAA7134_BOARD_BEHOLD_409: - case SAA7134_BOARD_BEHOLD_505FM: - case SAA7134_BOARD_BEHOLD_507_9FM: ir_codes = ir_codes_manli; mask_keycode = 0x001f00; mask_keyup = 0x004000; @@ -512,12 +457,6 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) ir->get_key = get_key_hvr1110; ir->ir_codes = ir_codes_hauppauge_new; break; - case SAA7134_BOARD_BEHOLD_607_9FM: - case SAA7134_BOARD_BEHOLD_M6: - snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); - ir->get_key = get_key_beholdm6xx; - ir->ir_codes = ir_codes_behold; - break; default: dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); break; diff --git a/trunk/drivers/media/video/saa7134/saa7134-oss.c b/trunk/drivers/media/video/saa7134/saa7134-oss.c new file mode 100644 index 000000000000..aedf04653e0e --- /dev/null +++ b/trunk/drivers/media/video/saa7134/saa7134-oss.c @@ -0,0 +1,1046 @@ +/* + * + * device driver for philips saa7134 based TV cards + * oss dsp interface + * + * (c) 2001,02 Gerd Knorr [SuSE Labs] + * 2005 conversion to standalone module: + * Ricardo Cerqueira + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "saa7134-reg.h" +#include "saa7134.h" + +/* ------------------------------------------------------------------ */ + +static unsigned int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug,"enable debug messages [oss]"); + +static unsigned int rate = 0; +module_param(rate, int, 0444); +MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)"); + +static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; +MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s)."); +module_param_array(dsp_nr, int, NULL, 0444); + +static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; +MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s)."); +module_param_array(mixer_nr, int, NULL, 0444); + +#define dprintk(fmt, arg...) if (debug) \ + printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) + + +/* ------------------------------------------------------------------ */ + +static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) +{ + if (blksize < 0x100) + blksize = 0x100; + if (blksize > 0x10000) + blksize = 0x10000; + + if (blocks < 2) + blocks = 2; + if ((blksize * blocks) > 1024*1024) + blocks = 1024*1024 / blksize; + + dev->dmasound.blocks = blocks; + dev->dmasound.blksize = blksize; + dev->dmasound.bufsize = blksize * blocks; + + dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", + blocks,blksize,blksize * blocks / 1024); + return 0; +} + +static int dsp_buffer_init(struct saa7134_dev *dev) +{ + int err; + + BUG_ON(!dev->dmasound.bufsize); + videobuf_dma_init(&dev->dmasound.dma); + err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, + (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); + if (0 != err) + return err; + return 0; +} + +static int dsp_buffer_free(struct saa7134_dev *dev) +{ + BUG_ON(!dev->dmasound.blksize); + videobuf_dma_free(&dev->dmasound.dma); + dev->dmasound.blocks = 0; + dev->dmasound.blksize = 0; + dev->dmasound.bufsize = 0; + return 0; +} + +static void dsp_dma_start(struct saa7134_dev *dev) +{ + dev->dmasound.dma_blk = 0; + dev->dmasound.dma_running = 1; + saa7134_set_dmabits(dev); +} + +static void dsp_dma_stop(struct saa7134_dev *dev) +{ + dev->dmasound.dma_blk = -1; + dev->dmasound.dma_running = 0; + saa7134_set_dmabits(dev); +} + +static int dsp_rec_start(struct saa7134_dev *dev) +{ + int err, bswap, sign; + u32 fmt, control; + unsigned long flags; + + /* prepare buffer */ + if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma))) + return err; + if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) + goto fail1; + if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, + dev->dmasound.dma.sglist, + dev->dmasound.dma.sglen, + 0))) + goto fail2; + + /* sample format */ + switch (dev->dmasound.afmt) { + case AFMT_U8: + case AFMT_S8: fmt = 0x00; break; + case AFMT_U16_LE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_S16_BE: fmt = 0x01; break; + default: + err = -EINVAL; + goto fail2; + } + + switch (dev->dmasound.afmt) { + case AFMT_S8: + case AFMT_S16_LE: + case AFMT_S16_BE: sign = 1; break; + default: sign = 0; break; + } + + switch (dev->dmasound.afmt) { + case AFMT_U16_BE: + case AFMT_S16_BE: bswap = 1; break; + default: bswap = 0; break; + } + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + if (1 == dev->dmasound.channels) + fmt |= (1 << 3); + if (2 == dev->dmasound.channels) + fmt |= (3 << 3); + if (sign) + fmt |= 0x04; + fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80; + + saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff)); + saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8); + saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16); + saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); + + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + if (1 == dev->dmasound.channels) + fmt |= (1 << 4); + if (2 == dev->dmasound.channels) + fmt |= (2 << 4); + if (!sign) + fmt |= 0x04; + saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4); + saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); + break; + } + dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", + dev->dmasound.afmt, dev->dmasound.channels, fmt, + bswap ? 'b' : '-'); + + /* dma: setup channel 6 (= AUDIO) */ + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (dev->dmasound.pt.dma >> 12); + if (bswap) + control |= SAA7134_RS_CONTROL_BSWAP; + saa_writel(SAA7134_RS_BA1(6),0); + saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); + saa_writel(SAA7134_RS_PITCH(6),0); + saa_writel(SAA7134_RS_CONTROL(6),control); + + /* start dma */ + dev->dmasound.recording_on = 1; + spin_lock_irqsave(&dev->slock,flags); + dsp_dma_start(dev); + spin_unlock_irqrestore(&dev->slock,flags); + return 0; + + fail2: + saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); + fail1: + videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma); + return err; +} + +static int dsp_rec_stop(struct saa7134_dev *dev) +{ + unsigned long flags; + + dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk); + + /* stop dma */ + dev->dmasound.recording_on = 0; + spin_lock_irqsave(&dev->slock,flags); + dsp_dma_stop(dev); + spin_unlock_irqrestore(&dev->slock,flags); + + /* unlock buffer */ + saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); + videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int dsp_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + struct saa7134_dev *dev; + int err; + + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_dsp == minor) + goto found; + return -ENODEV; + found: + + mutex_lock(&dev->dmasound.lock); + err = -EBUSY; + if (dev->dmasound.users_dsp) + goto fail1; + dev->dmasound.users_dsp++; + file->private_data = dev; + + dev->dmasound.afmt = AFMT_U8; + dev->dmasound.channels = 1; + dev->dmasound.read_count = 0; + dev->dmasound.read_offset = 0; + dsp_buffer_conf(dev,PAGE_SIZE,64); + err = dsp_buffer_init(dev); + if (0 != err) + goto fail2; + + mutex_unlock(&dev->dmasound.lock); + return 0; + + fail2: + dev->dmasound.users_dsp--; + fail1: + mutex_unlock(&dev->dmasound.lock); + return err; +} + +static int dsp_release(struct inode *inode, struct file *file) +{ + struct saa7134_dev *dev = file->private_data; + + mutex_lock(&dev->dmasound.lock); + if (dev->dmasound.recording_on) + dsp_rec_stop(dev); + dsp_buffer_free(dev); + dev->dmasound.users_dsp--; + file->private_data = NULL; + mutex_unlock(&dev->dmasound.lock); + return 0; +} + +static ssize_t dsp_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct saa7134_dev *dev = file->private_data; + DECLARE_WAITQUEUE(wait, current); + unsigned int bytes; + unsigned long flags; + int err,ret = 0; + + add_wait_queue(&dev->dmasound.wq, &wait); + mutex_lock(&dev->dmasound.lock); + while (count > 0) { + /* wait for data if needed */ + if (0 == dev->dmasound.read_count) { + if (!dev->dmasound.recording_on) { + err = dsp_rec_start(dev); + if (err < 0) { + if (0 == ret) + ret = err; + break; + } + } + if (dev->dmasound.recording_on && + !dev->dmasound.dma_running) { + /* recover from overruns */ + spin_lock_irqsave(&dev->slock,flags); + dsp_dma_start(dev); + spin_unlock_irqrestore(&dev->slock,flags); + } + if (file->f_flags & O_NONBLOCK) { + if (0 == ret) + ret = -EAGAIN; + break; + } + mutex_unlock(&dev->dmasound.lock); + set_current_state(TASK_INTERRUPTIBLE); + if (0 == dev->dmasound.read_count) + schedule(); + set_current_state(TASK_RUNNING); + mutex_lock(&dev->dmasound.lock); + if (signal_pending(current)) { + if (0 == ret) + ret = -EINTR; + break; + } + } + + /* copy data to userspace */ + bytes = count; + if (bytes > dev->dmasound.read_count) + bytes = dev->dmasound.read_count; + if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset) + bytes = dev->dmasound.bufsize - dev->dmasound.read_offset; + if (copy_to_user(buffer + ret, + dev->dmasound.dma.vmalloc + dev->dmasound.read_offset, + bytes)) { + if (0 == ret) + ret = -EFAULT; + break; + } + + ret += bytes; + count -= bytes; + dev->dmasound.read_count -= bytes; + dev->dmasound.read_offset += bytes; + if (dev->dmasound.read_offset == dev->dmasound.bufsize) + dev->dmasound.read_offset = 0; + } + mutex_unlock(&dev->dmasound.lock); + remove_wait_queue(&dev->dmasound.wq, &wait); + return ret; +} + +static ssize_t dsp_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +static const char *osspcm_ioctls[] = { + "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", + "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", + "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", + "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", + "SETDUPLEX", "GETODELAY" +}; +#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls) + +static void saa7134_oss_print_ioctl(char *name, unsigned int cmd) +{ + char *dir; + + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "??"; break; + } + switch (_IOC_TYPE(cmd)) { + case 'P': + printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", + name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? + osspcm_ioctls[_IOC_NR(cmd)] : "???"); + break; + case 'M': + printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", + name, cmd, dir, _IOC_NR(cmd)); + break; + default: + printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", + name, cmd, dir, _IOC_NR(cmd)); + } +} + +static int dsp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct saa7134_dev *dev = file->private_data; + void __user *argp = (void __user *) arg; + int __user *p = argp; + int val = 0; + + if (debug > 1) + saa7134_oss_print_ioctl(dev->name,cmd); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, p); + case SNDCTL_DSP_GETCAPS: + return 0; + + case SNDCTL_DSP_SPEED: + if (get_user(val, p)) + return -EFAULT; + /* fall through */ + case SOUND_PCM_READ_RATE: + return put_user(dev->dmasound.rate, p); + + case SNDCTL_DSP_STEREO: + if (get_user(val, p)) + return -EFAULT; + mutex_lock(&dev->dmasound.lock); + dev->dmasound.channels = val ? 2 : 1; + if (dev->dmasound.recording_on) { + dsp_rec_stop(dev); + dsp_rec_start(dev); + } + mutex_unlock(&dev->dmasound.lock); + return put_user(dev->dmasound.channels-1, p); + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, p)) + return -EFAULT; + if (val != 1 && val != 2) + return -EINVAL; + mutex_lock(&dev->dmasound.lock); + dev->dmasound.channels = val; + if (dev->dmasound.recording_on) { + dsp_rec_stop(dev); + dsp_rec_start(dev); + } + mutex_unlock(&dev->dmasound.lock); + /* fall through */ + case SOUND_PCM_READ_CHANNELS: + return put_user(dev->dmasound.channels, p); + + case SNDCTL_DSP_GETFMTS: /* Returns a mask */ + return put_user(AFMT_U8 | AFMT_S8 | + AFMT_U16_LE | AFMT_U16_BE | + AFMT_S16_LE | AFMT_S16_BE, p); + + case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ + if (get_user(val, p)) + return -EFAULT; + switch (val) { + case AFMT_QUERY: + /* nothing to do */ + break; + case AFMT_U8: + case AFMT_S8: + case AFMT_U16_LE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_S16_BE: + mutex_lock(&dev->dmasound.lock); + dev->dmasound.afmt = val; + if (dev->dmasound.recording_on) { + dsp_rec_stop(dev); + dsp_rec_start(dev); + } + mutex_unlock(&dev->dmasound.lock); + return put_user(dev->dmasound.afmt, p); + default: + return -EINVAL; + } + + case SOUND_PCM_READ_BITS: + switch (dev->dmasound.afmt) { + case AFMT_U8: + case AFMT_S8: + return put_user(8, p); + case AFMT_U16_LE: + case AFMT_U16_BE: + case AFMT_S16_LE: + case AFMT_S16_BE: + return put_user(16, p); + default: + return -EINVAL; + } + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_RESET: + mutex_lock(&dev->dmasound.lock); + if (dev->dmasound.recording_on) + dsp_rec_stop(dev); + mutex_unlock(&dev->dmasound.lock); + return 0; + case SNDCTL_DSP_GETBLKSIZE: + return put_user(dev->dmasound.blksize, p); + + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, p)) + return -EFAULT; + if (dev->dmasound.recording_on) + return -EBUSY; + dsp_buffer_free(dev); + /* used to be arg >> 16 instead of val >> 16; fixed */ + dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff); + dsp_buffer_init(dev); + return 0; + + case SNDCTL_DSP_SYNC: + /* NOP */ + return 0; + + case SNDCTL_DSP_GETISPACE: + { + audio_buf_info info; + info.fragsize = dev->dmasound.blksize; + info.fragstotal = dev->dmasound.blocks; + info.bytes = dev->dmasound.read_count; + info.fragments = info.bytes / info.fragsize; + if (copy_to_user(argp, &info, sizeof(info))) + return -EFAULT; + return 0; + } + default: + return -EINVAL; + } +} + +static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait) +{ + struct saa7134_dev *dev = file->private_data; + unsigned int mask = 0; + + poll_wait(file, &dev->dmasound.wq, wait); + + if (0 == dev->dmasound.read_count) { + mutex_lock(&dev->dmasound.lock); + if (!dev->dmasound.recording_on) + dsp_rec_start(dev); + mutex_unlock(&dev->dmasound.lock); + } else + mask |= (POLLIN | POLLRDNORM); + return mask; +} + +const struct file_operations saa7134_dsp_fops = { + .owner = THIS_MODULE, + .open = dsp_open, + .release = dsp_release, + .read = dsp_read, + .write = dsp_write, + .ioctl = dsp_ioctl, + .poll = dsp_poll, + .llseek = no_llseek, +}; + +/* ------------------------------------------------------------------ */ + +static int +mixer_recsrc_7134(struct saa7134_dev *dev) +{ + int analog_io,rate; + + switch (dev->dmasound.input) { + case TV: + saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0); + saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); + break; + case LINE1: + case LINE2: + case LINE2_LEFT: + analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08; + rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03; + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); + saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80); + saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); + break; + } + return 0; +} + +static int +mixer_recsrc_7133(struct saa7134_dev *dev) +{ + u32 anabar, xbarin; + + xbarin = 0x03; // adc + anabar = 0; + switch (dev->dmasound.input) { + case TV: + xbarin = 0; // Demodulator + anabar = 2; // DACs + break; + case LINE1: + anabar = 0; // aux1, aux1 + break; + case LINE2: + case LINE2_LEFT: + anabar = 9; // aux2, aux2 + break; + } + /* output xbar always main channel */ + saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10); + saa_dsp_writel(dev, 0x464 >> 2, xbarin); + saa_writel(0x594 >> 2, anabar); + + return 0; +} + +static int +mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src) +{ + static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" }; + + dev->dmasound.count++; + dev->dmasound.input = src; + dprintk("mixer input = %s\n",iname[dev->dmasound.input]); + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + mixer_recsrc_7134(dev); + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + mixer_recsrc_7133(dev); + break; + } + return 0; +} + +static int +mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) +{ + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + switch (src) { + case TV: + /* nothing */ + break; + case LINE1: + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, + (100 == level) ? 0x00 : 0x10); + break; + case LINE2: + case LINE2_LEFT: + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, + (100 == level) ? 0x00 : 0x20); + break; + } + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + /* nothing */ + break; + } + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int mixer_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + struct saa7134_dev *dev; + + list_for_each_entry(dev, &saa7134_devlist, devlist) + if (dev->dmasound.minor_mixer == minor) { + file->private_data = dev; + return 0; + } + return -ENODEV; +} + +static int mixer_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + return 0; +} + +static int mixer_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct saa7134_dev *dev = file->private_data; + enum saa7134_audio_in input; + int val,ret; + void __user *argp = (void __user *) arg; + int __user *p = argp; + + if (debug > 1) + saa7134_oss_print_ioctl(dev->name,cmd); + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, p); + case SOUND_MIXER_INFO: + { + mixer_info info; + memset(&info,0,sizeof(info)); + strlcpy(info.id, "TV audio", sizeof(info.id)); + strlcpy(info.name, dev->name, sizeof(info.name)); + info.modify_counter = dev->dmasound.count; + if (copy_to_user(argp, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case SOUND_OLD_MIXER_INFO: + { + _old_mixer_info info; + memset(&info,0,sizeof(info)); + strlcpy(info.id, "TV audio", sizeof(info.id)); + strlcpy(info.name, dev->name, sizeof(info.name)); + if (copy_to_user(argp, &info, sizeof(info))) + return -EFAULT; + return 0; + } + case MIXER_READ(SOUND_MIXER_CAPS): + return put_user(SOUND_CAP_EXCL_INPUT, p); + case MIXER_READ(SOUND_MIXER_STEREODEVS): + return put_user(0, p); + case MIXER_READ(SOUND_MIXER_RECMASK): + case MIXER_READ(SOUND_MIXER_DEVMASK): + val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2; + if (32000 == dev->dmasound.rate) + val |= SOUND_MASK_VIDEO; + return put_user(val, p); + + case MIXER_WRITE(SOUND_MIXER_RECSRC): + if (get_user(val, p)) + return -EFAULT; + input = dev->dmasound.input; + if (32000 == dev->dmasound.rate && + val & SOUND_MASK_VIDEO && dev->dmasound.input != TV) + input = TV; + if (val & SOUND_MASK_LINE1 && dev->dmasound.input != LINE1) + input = LINE1; + if (val & SOUND_MASK_LINE2 && dev->dmasound.input != LINE2) + input = LINE2; + if (input != dev->dmasound.input) + mixer_recsrc(dev,input); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_RECSRC): + switch (dev->dmasound.input) { + case TV: ret = SOUND_MASK_VIDEO; break; + case LINE1: ret = SOUND_MASK_LINE1; break; + case LINE2: ret = SOUND_MASK_LINE2; break; + default: ret = 0; + } + return put_user(ret, p); + + case MIXER_WRITE(SOUND_MIXER_VIDEO): + case MIXER_READ(SOUND_MIXER_VIDEO): + if (32000 != dev->dmasound.rate) + return -EINVAL; + return put_user(100 | 100 << 8, p); + + case MIXER_WRITE(SOUND_MIXER_LINE1): + if (get_user(val, p)) + return -EFAULT; + val &= 0xff; + val = (val <= 50) ? 50 : 100; + dev->dmasound.line1 = val; + mixer_level(dev,LINE1,dev->dmasound.line1); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_LINE1): + return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p); + + case MIXER_WRITE(SOUND_MIXER_LINE2): + if (get_user(val, p)) + return -EFAULT; + val &= 0xff; + val = (val <= 50) ? 50 : 100; + dev->dmasound.line2 = val; + mixer_level(dev,LINE2,dev->dmasound.line2); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_LINE2): + return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p); + + default: + return -EINVAL; + } +} + +const struct file_operations saa7134_mixer_fops = { + .owner = THIS_MODULE, + .open = mixer_open, + .release = mixer_release, + .ioctl = mixer_ioctl, + .llseek = no_llseek, +}; + +/* ------------------------------------------------------------------ */ + +static irqreturn_t saa7134_oss_irq(int irq, void *dev_id) +{ + struct saa7134_dmasound *dmasound = dev_id; + struct saa7134_dev *dev = dmasound->priv_data; + unsigned long report, status; + int loop, handled = 0; + + for (loop = 0; loop < 10; loop++) { + report = saa_readl(SAA7134_IRQ_REPORT); + status = saa_readl(SAA7134_IRQ_STATUS); + + if (report & SAA7134_IRQ_REPORT_DONE_RA3) { + handled = 1; + saa_writel(SAA7134_IRQ_REPORT,report); + saa7134_irq_oss_done(dev, status); + } else { + goto out; + } + } + + if (loop == 10) { + dprintk("error! looping IRQ!"); + } +out: + return IRQ_RETVAL(handled); +} + +int saa7134_oss_init1(struct saa7134_dev *dev) +{ + + if ((request_irq(dev->pci->irq, saa7134_oss_irq, + IRQF_SHARED | IRQF_DISABLED, dev->name, + (void*) &dev->dmasound)) < 0) + return -1; + + /* general */ + mutex_init(&dev->dmasound.lock); + init_waitqueue_head(&dev->dmasound.wq); + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + saa_writel(0x588 >> 2, 0x00000fff); + saa_writel(0x58c >> 2, 0x00543210); + saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb); + break; + } + + /* dsp */ + dev->dmasound.rate = 32000; + if (rate) + dev->dmasound.rate = rate; + dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000; + + /* mixer */ + dev->dmasound.line1 = 50; + dev->dmasound.line2 = 50; + mixer_level(dev,LINE1,dev->dmasound.line1); + mixer_level(dev,LINE2,dev->dmasound.line2); + mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2); + + return 0; +} + +int saa7134_oss_fini(struct saa7134_dev *dev) +{ + /* nothing */ + return 0; +} + +void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) +{ + int next_blk, reg = 0; + + spin_lock(&dev->slock); + if (UNSET == dev->dmasound.dma_blk) { + dprintk("irq: recording stopped\n"); + goto done; + } + if (0 != (status & 0x0f000000)) + dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); + if (0 == (status & 0x10000000)) { + /* odd */ + if (0 == (dev->dmasound.dma_blk & 0x01)) + reg = SAA7134_RS_BA1(6); + } else { + /* even */ + if (1 == (dev->dmasound.dma_blk & 0x01)) + reg = SAA7134_RS_BA2(6); + } + if (0 == reg) { + dprintk("irq: field oops [%s]\n", + (status & 0x10000000) ? "even" : "odd"); + goto done; + } + if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { + dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count, + dev->dmasound.bufsize); + dsp_dma_stop(dev); + goto done; + } + + /* next block addr */ + next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; + saa_writel(reg,next_blk * dev->dmasound.blksize); + if (debug > 2) + dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", + (status & 0x10000000) ? "even" : "odd ", next_blk, + next_blk * dev->dmasound.blksize); + + /* update status & wake waiting readers */ + dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; + dev->dmasound.read_count += dev->dmasound.blksize; + wake_up(&dev->dmasound.wq); + + done: + spin_unlock(&dev->slock); +} + +static int saa7134_dsp_create(struct saa7134_dev *dev) +{ + int err; + + err = dev->dmasound.minor_dsp = + register_sound_dsp(&saa7134_dsp_fops, + dsp_nr[dev->nr]); + if (err < 0) { + goto fail; + } + printk(KERN_INFO "%s: registered device dsp%d\n", + dev->name,dev->dmasound.minor_dsp >> 4); + + err = dev->dmasound.minor_mixer = + register_sound_mixer(&saa7134_mixer_fops, + mixer_nr[dev->nr]); + if (err < 0) + goto fail; + printk(KERN_INFO "%s: registered device mixer%d\n", + dev->name,dev->dmasound.minor_mixer >> 4); + + return 0; + +fail: + unregister_sound_dsp(dev->dmasound.minor_dsp); + return 0; + + +} + +static int oss_device_init(struct saa7134_dev *dev) +{ + dev->dmasound.priv_data = dev; + saa7134_oss_init1(dev); + saa7134_dsp_create(dev); + return 1; +} + +static int oss_device_exit(struct saa7134_dev *dev) +{ + + unregister_sound_mixer(dev->dmasound.minor_mixer); + unregister_sound_dsp(dev->dmasound.minor_dsp); + + saa7134_oss_fini(dev); + + if (dev->pci->irq > 0) { + synchronize_irq(dev->pci->irq); + free_irq(dev->pci->irq,&dev->dmasound); + } + + dev->dmasound.priv_data = NULL; + return 1; +} + +static int saa7134_oss_init(void) +{ + struct saa7134_dev *dev = NULL; + struct list_head *list; + + if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { + saa7134_dmasound_init = oss_device_init; + saa7134_dmasound_exit = oss_device_exit; + } else { + printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n"); + return -EBUSY; + } + + printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n"); + + + list_for_each(list,&saa7134_devlist) { + dev = list_entry(list, struct saa7134_dev, devlist); + if (dev->dmasound.priv_data == NULL) { + oss_device_init(dev); + } else { + printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name); + return -EBUSY; + } + } + + if (dev == NULL) + printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n"); + + return 0; + +} + +static void saa7134_oss_exit(void) +{ + struct saa7134_dev *dev; + + list_for_each_entry(dev, &saa7134_devlist, devlist) { + /* Device isn't registered by OSS, probably ALSA's */ + if (!dev->dmasound.minor_dsp) + continue; + + oss_device_exit(dev); + } + + saa7134_dmasound_init = NULL; + saa7134_dmasound_exit = NULL; + + printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n"); + + return; +} + +/* We initialize this late, to make sure the sound system is up and running */ +late_initcall(saa7134_oss_init); +module_exit(saa7134_oss_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); + +/* ----------------------------------------------------------- */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/trunk/drivers/media/video/saa7134/saa7134-ts.c b/trunk/drivers/media/video/saa7134/saa7134-ts.c index f1b8fcaeb43a..4b63ad3e8466 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-ts.c +++ b/trunk/drivers/media/video/saa7134/saa7134-ts.c @@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev, { dprintk("buffer_activate [%p]",buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->top_seen = 0; if (NULL == next) @@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa7134_dma_free(q,buf); } - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); saa_writel(SAA7134_RS_CONTROL(5),control); - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) if ((status & 0x100000) != 0x100000) goto done; } - saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE); + saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); } saa7134_buffer_next(dev,&dev->ts_q); diff --git a/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c b/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c index 4e9810469ae3..f8e304c76232 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/trunk/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -163,6 +163,32 @@ static struct saa7134_tvaudio tvaudio[] = { /* ------------------------------------------------------------------ */ +static void tvaudio_init(struct saa7134_dev *dev) +{ + int clock = saa7134_boards[dev->board].audio_clock; + + if (UNSET != audio_clock_override) + clock = audio_clock_override; + + /* init all audio registers */ + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); + if (need_resched()) + schedule(); + else + udelay(10); + + saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); + /* frame locked audio is mandatory for NICAM */ + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); + + saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); + saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); + saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); + saa_writeb(SAA7134_FM_DEMATRIX, 0x80); +} + static u32 tvaudio_carr2reg(u32 carrier) { u64 a = carrier; @@ -491,13 +517,9 @@ static int tvaudio_thread(void *data) dev->thread.scan1 = dev->thread.scan2; dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); dev->tvaudio = NULL; - - saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); - saa_writeb(SAA7134_FM_DEMATRIX, 0x80); - + tvaudio_init(dev); if (dev->ctl_automute) dev->automute = 1; - mute_input_7134(dev); /* give the tuner some time */ @@ -762,15 +784,27 @@ static int mute_input_7133(struct saa7134_dev *dev) static int tvaudio_thread_ddep(void *data) { struct saa7134_dev *dev = data; - u32 value, norms; + u32 value, norms, clock; set_freezable(); + + clock = saa7134_boards[dev->board].audio_clock; + if (UNSET != audio_clock_override) + clock = audio_clock_override; + saa_writel(0x598 >> 2, clock); + + /* unmute */ + saa_dsp_writel(dev, 0x474 >> 2, 0x00); + saa_dsp_writel(dev, 0x450 >> 2, 0x00); + for (;;) { tvaudio_sleep(dev,-1); if (kthread_should_stop()) goto done; + restart: + try_to_freeze(); dev->thread.scan1 = dev->thread.scan2; @@ -944,38 +978,6 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev) return retval; } -void saa7134_tvaudio_init(struct saa7134_dev *dev) -{ - int clock = saa7134_boards[dev->board].audio_clock; - - if (UNSET != audio_clock_override) - clock = audio_clock_override; - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - /* init all audio registers */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); - if (need_resched()) - schedule(); - else - udelay(10); - - saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); - /* frame locked audio is mandatory for NICAM */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); - saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); - saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa_writel(0x598 >> 2, clock); - saa_dsp_writel(dev, 0x474 >> 2, 0x00); - saa_dsp_writel(dev, 0x450 >> 2, 0x00); - } -} - int saa7134_tvaudio_init2(struct saa7134_dev *dev) { int (*my_thread)(void *data) = NULL; @@ -992,7 +994,6 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) dev->thread.thread = NULL; if (my_thread) { - saa7134_tvaudio_init(dev); /* start tvaudio thread */ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name); if (IS_ERR(dev->thread.thread)) { diff --git a/trunk/drivers/media/video/saa7134/saa7134-vbi.c b/trunk/drivers/media/video/saa7134/saa7134-vbi.c index f0d5ed9c2b06..81a2aedeff5c 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-vbi.c +++ b/trunk/drivers/media/video/saa7134/saa7134-vbi.c @@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long control,base; dprintk("buffer_activate [%p]\n",buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->top_seen = 0; task_init(dev,buf,TASK_A); @@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (buf->vb.size != size) saa7134_dma_free(q,buf); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) goto done; dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount; - saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE); + saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE); } saa7134_buffer_next(dev,&dev->vbi_q); diff --git a/trunk/drivers/media/video/saa7134/saa7134-video.c b/trunk/drivers/media/video/saa7134/saa7134-video.c index 1184d359e848..6396d9b5c063 100644 --- a/trunk/drivers/media/video/saa7134/saa7134-video.c +++ b/trunk/drivers/media/video/saa7134/saa7134-video.c @@ -38,7 +38,7 @@ /* ------------------------------------------------------------------ */ -unsigned int video_debug; +static unsigned int video_debug = 0; static unsigned int gbuffers = 8; static unsigned int noninterlaced = 0; static unsigned int gbufsize = 720*576*4; @@ -54,7 +54,7 @@ module_param_string(secam, secam, sizeof(secam), 0644); MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); -#define dprintk(fmt, arg...) if (video_debug&0x04) \ +#define dprintk(fmt, arg...) if (video_debug) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ @@ -540,8 +540,9 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) /* ------------------------------------------------------------------ */ -static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { + dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; @@ -560,6 +561,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) dev->crop_current = dev->crop_defrect; saa7134_set_tvnorm_hw(dev); + } static void video_mux(struct saa7134_dev *dev, int input) @@ -943,7 +945,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ dprintk("buffer_activate buf=%p\n",buf); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; buf->top_seen = 0; set_size(dev,TASK_A,buf->vb.width,buf->vb.height, @@ -1052,7 +1054,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); } - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + if (STATE_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = fh->width; @@ -1072,7 +1074,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; return 0; @@ -1117,10 +1119,8 @@ static struct videobuf_queue_ops video_qops = { /* ------------------------------------------------------------------ */ -int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) { - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; const struct v4l2_queryctrl* ctrl; ctrl = ctrl_by_id(c->id); @@ -1165,27 +1165,17 @@ int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) } return 0; } -EXPORT_SYMBOL_GPL(saa7134_g_ctrl); -int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) +static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_control *c) { const struct v4l2_queryctrl* ctrl; - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; unsigned long flags; int restart_overlay = 0; - int err = -EINVAL; - - err = v4l2_prio_check(&dev->prio, &fh->prio); - if (0 != err) - return err; - - mutex_lock(&dev->lock); ctrl = ctrl_by_id(c->id); if (NULL == ctrl) - goto error; - + return -EINVAL; dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); switch (ctrl->type) { case V4L2_CTRL_TYPE_BOOLEAN: @@ -1246,26 +1236,18 @@ int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) restart_overlay = 1; break; case V4L2_CID_PRIVATE_AUTOMUTE: - { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - dev->ctl_automute = c->value; if (dev->tda9887_conf) { if (dev->ctl_automute) dev->tda9887_conf |= TDA9887_AUTOMUTE; else dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); + saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, + &dev->tda9887_conf); } break; - } default: - goto error; + return -EINVAL; } if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); @@ -1273,13 +1255,8 @@ int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } - err = 0; - -error: - mutex_unlock(&dev->lock); - return err; + return 0; } -EXPORT_SYMBOL_GPL(saa7134_s_ctrl); /* ------------------------------------------------------------------ */ @@ -1436,8 +1413,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) + if (buf->state == STATE_DONE || + buf->state == STATE_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -1501,11 +1478,8 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) /* ------------------------------------------------------------------ */ -static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv, - struct v4l2_format *f) +static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) { - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; struct saa7134_tvnorm *norm = dev->tvnorm; f->fmt.vbi.sampling_rate = 6750000 * 4; @@ -1518,805 +1492,837 @@ static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv, f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ - return 0; } -static int saa7134_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) { - struct saa7134_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + f->fmt.win = fh->win; + return 0; + case V4L2_BUF_TYPE_VBI_CAPTURE: + saa7134_vbi_fmt(dev,f); + return 0; + default: + return -EINVAL; + } } -static int saa7134_g_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) +static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) { - struct saa7134_fh *fh = priv; + int err; - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - f->fmt.win = fh->win; + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + struct saa7134_format *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; - return 0; -} + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; -static int saa7134_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - struct saa7134_format *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; + field = f->fmt.pix.field; + maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); + maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } - field = f->fmt.pix.field; - maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); - maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); + f->fmt.pix.field = field; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; + return 0; } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + err = verify_preview(dev,&f->fmt.win); + if (0 != err) + return err; + return 0; + case V4L2_BUF_TYPE_VBI_CAPTURE: + saa7134_vbi_fmt(dev,f); + return 0; default: return -EINVAL; } - - f->fmt.pix.field = field; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; } -static int saa7134_try_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) +static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, + struct v4l2_format *f) { - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + unsigned long flags; + int err; - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + err = saa7134_try_fmt(dev,fh,f); + if (0 != err) + return err; + + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->cap.field = f->fmt.pix.field; + return 0; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + err = verify_preview(dev,&f->fmt.win); + if (0 != err) + return err; + + mutex_lock(&dev->lock); + fh->win = f->fmt.win; + fh->nclips = f->fmt.win.clipcount; + if (fh->nclips > 8) + fh->nclips = 8; + if (copy_from_user(fh->clips,f->fmt.win.clips, + sizeof(struct v4l2_clip)*fh->nclips)) { + mutex_unlock(&dev->lock); + return -EFAULT; + } + + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + start_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + } + mutex_unlock(&dev->lock); + return 0; + case V4L2_BUF_TYPE_VBI_CAPTURE: + saa7134_vbi_fmt(dev,f); + return 0; + default: return -EINVAL; } - - return verify_preview(dev, &f->fmt.win); } -static int saa7134_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) +int saa7134_common_ioctl(struct saa7134_dev *dev, + unsigned int cmd, void *arg) { - struct saa7134_fh *fh = priv; int err; - err = saa7134_try_fmt_cap(file, priv, f); - if (0 != err) - return err; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->cap.field = f->fmt.pix.field; - return 0; -} - -static int saa7134_s_fmt_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int err; - unsigned int flags; + switch (cmd) { + case VIDIOC_QUERYCTRL: + { + const struct v4l2_queryctrl *ctrl; + struct v4l2_queryctrl *c = arg; - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + ctrl = ctrl_by_id(c->id); + *c = (NULL != ctrl) ? *ctrl : no_ctrl; + return 0; } - err = verify_preview(dev, &f->fmt.win); - if (0 != err) + case VIDIOC_G_CTRL: + return get_control(dev,arg); + case VIDIOC_S_CTRL: + { + mutex_lock(&dev->lock); + err = set_control(dev,NULL,arg); + mutex_unlock(&dev->lock); return err; + } + /* --- input switching --------------------------------------- */ + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; + unsigned int n; - mutex_lock(&dev->lock); - - fh->win = f->fmt.win; - fh->nclips = f->fmt.win.clipcount; - - if (fh->nclips > 8) - fh->nclips = 8; + n = i->index; + if (n >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev,i->index).name) + return -EINVAL; + memset(i,0,sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name,card_in(dev,n).name); + if (card_in(dev,n).tv) + i->type = V4L2_INPUT_TYPE_TUNER; + i->audioset = 1; + if (n == dev->ctl_input) { + int v1 = saa_readb(SAA7134_STATUS_VIDEO1); + int v2 = saa_readb(SAA7134_STATUS_VIDEO2); + + if (0 != (v1 & 0x40)) + i->status |= V4L2_IN_ST_NO_H_LOCK; + if (0 != (v2 & 0x40)) + i->status |= V4L2_IN_ST_NO_SYNC; + if (0 != (v2 & 0x0e)) + i->status |= V4L2_IN_ST_MACROVISION; + } + for (n = 0; n < TVNORMS; n++) + i->std |= tvnorms[n].id; + return 0; + } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = dev->ctl_input; + return 0; + } + case VIDIOC_S_INPUT: + { + int *i = arg; - if (copy_from_user(fh->clips, f->fmt.win.clips, - sizeof(struct v4l2_clip)*fh->nclips)) { + if (*i < 0 || *i >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev,*i).name) + return -EINVAL; + mutex_lock(&dev->lock); + video_mux(dev,*i); mutex_unlock(&dev->lock); - return -EFAULT; + return 0; } - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock, flags); - stop_preview(dev, fh); - start_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); } - - mutex_unlock(&dev->lock); - return 0; -} - -int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - ctrl = ctrl_by_id(c->id); - *c = (NULL != ctrl) ? *ctrl : no_ctrl; return 0; } -EXPORT_SYMBOL_GPL(saa7134_queryctrl); - -static int saa7134_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - unsigned int n; +EXPORT_SYMBOL(saa7134_common_ioctl); - n = i->index; - if (n >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev, i->index).name) - return -EINVAL; - memset(i, 0, sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, card_in(dev, n).name); - if (card_in(dev, n).tv) - i->type = V4L2_INPUT_TYPE_TUNER; - i->audioset = 1; - if (n == dev->ctl_input) { - int v1 = saa_readb(SAA7134_STATUS_VIDEO1); - int v2 = saa_readb(SAA7134_STATUS_VIDEO2); - - if (0 != (v1 & 0x40)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - if (0 != (v2 & 0x40)) - i->status |= V4L2_IN_ST_NO_SYNC; - if (0 != (v2 & 0x0e)) - i->status |= V4L2_IN_ST_MACROVISION; - } - i->std = SAA7134_NORMS; - return 0; -} - -static int saa7134_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - *i = dev->ctl_input; - return 0; -} - -static int saa7134_s_input(struct file *file, void *priv, unsigned int i) +/* + * This function is _not_ called directly, but from + * video_generic_ioctl (and maybe others). userspace + * copying is done already, arg is a kernel pointer. + */ +static int video_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { - struct saa7134_fh *fh = priv; + struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; + unsigned long flags; int err; - err = v4l2_prio_check(&dev->prio, &fh->prio); - if (0 != err) - return err; + if (video_debug > 1) + v4l_print_ioctl(dev->name,cmd); + + switch (cmd) { + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + err = v4l2_prio_check(&dev->prio,&fh->prio); + if (0 != err) + return err; + } - if (i < 0 || i >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev, i).name) - return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev, i); - mutex_unlock(&dev->lock); - return 0; -} + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + unsigned int tuner_type = dev->tuner_type; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + if (saa7134_no_overlay <= 0) { + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + } -static int saa7134_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) + cap->capabilities &= ~V4L2_CAP_TUNER; - unsigned int tuner_type = dev->tuner_type; - - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; - if (saa7134_no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - - if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) - cap->capabilities &= ~V4L2_CAP_TUNER; return 0; -} + } -static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - unsigned long flags; - unsigned int i; - v4l2_std_id fixup; - int err; + /* --- tv standards ------------------------------------------ */ + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *e = arg; + unsigned int i; - err = v4l2_prio_check(&dev->prio, &fh->prio); - if (0 != err) - return err; + i = e->index; + if (i >= TVNORMS) + return -EINVAL; + err = v4l2_video_std_construct(e, tvnorms[e->index].id, + tvnorms[e->index].name); + e->index = i; + if (err < 0) + return err; + return 0; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; - for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) - break; + *id = dev->tvnorm->id; + return 0; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + unsigned int i; + v4l2_std_id fixup; - if (i == TVNORMS) for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) + if (*id == tvnorms[i].id) break; - if (i == TVNORMS) - return -EINVAL; - - if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { - if (secam[0] == 'L' || secam[0] == 'l') { - if (secam[1] == 'C' || secam[1] == 'c') - fixup = V4L2_STD_SECAM_LC; - else - fixup = V4L2_STD_SECAM_L; - } else { - if (secam[0] == 'D' || secam[0] == 'd') - fixup = V4L2_STD_SECAM_DK; - else - fixup = V4L2_STD_SECAM; + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) + if (*id & tvnorms[i].id) + break; + if (i == TVNORMS) + return -EINVAL; + if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if (secam[0] == 'L' || secam[0] == 'l') { + if (secam[1] == 'C' || secam[1] == 'c') + fixup = V4L2_STD_SECAM_LC; + else + fixup = V4L2_STD_SECAM_L; + } else { + if (secam[0] == 'D' || secam[0] == 'd') + fixup = V4L2_STD_SECAM_DK; + else + fixup = V4L2_STD_SECAM; + } + for (i = 0; i < TVNORMS; i++) + if (fixup == tvnorms[i].id) + break; } - for (i = 0; i < TVNORMS; i++) - if (fixup == tvnorms[i].id) - break; + mutex_lock(&dev->lock); + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock, flags); + + set_tvnorm(dev,&tvnorms[i]); + + spin_lock_irqsave(&dev->slock, flags); + start_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + } else + set_tvnorm(dev,&tvnorms[i]); + saa7134_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; } - *id = tvnorms[i].id; - - mutex_lock(&dev->lock); - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock, flags); - stop_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - - set_tvnorm(dev, &tvnorms[i]); - - spin_lock_irqsave(&dev->slock, flags); - start_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - } else - set_tvnorm(dev, &tvnorms[i]); - - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; -} - -static int saa7134_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cap) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *cap = arg; - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - cap->bounds = dev->crop_bounds; - cap->defrect = dev->crop_defrect; - cap->pixelaspect.numerator = 1; - cap->pixelaspect.denominator = 1; - if (dev->tvnorm->id & V4L2_STD_525_60) { - cap->pixelaspect.numerator = 11; - cap->pixelaspect.denominator = 10; - } - if (dev->tvnorm->id & V4L2_STD_625_50) { - cap->pixelaspect.numerator = 54; - cap->pixelaspect.denominator = 59; + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + cap->bounds = dev->crop_bounds; + cap->defrect = dev->crop_defrect; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + if (dev->tvnorm->id & V4L2_STD_525_60) { + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + } + if (dev->tvnorm->id & V4L2_STD_625_50) { + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; + } + return 0; } - return 0; -} -static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - crop->c = dev->crop_current; - return 0; -} - -static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - struct v4l2_rect *b = &dev->crop_bounds; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - if (crop->c.height < 0) - return -EINVAL; - if (crop->c.width < 0) - return -EINVAL; - - if (res_locked(fh->dev, RESOURCE_OVERLAY)) - return -EBUSY; - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dev->crop_current = crop->c; - return 0; -} - -static int saa7134_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int n; - - if (0 != t->index) - return -EINVAL; - memset(t, 0, sizeof(*t)); - for (n = 0; n < SAA7134_INPUT_MAX; n++) - if (card_in(dev, n).tv) - break; - if (NULL != card_in(dev, n).name) { - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = saa7134_tvaudio_getstereo(dev); - t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); - } - if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) - t->signal = 0xffff; - return 0; -} - -static int saa7134_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int rx, mode, err; - - err = v4l2_prio_check(&dev->prio, &fh->prio); - if (0 != err) - return err; + case VIDIOC_G_CROP: + { + struct v4l2_crop * crop = arg; - mode = dev->thread.mode; - if (UNSET == mode) { - rx = saa7134_tvaudio_getstereo(dev); - mode = saa7134_tvaudio_rx2mode(t->rxsubchans); + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + crop->c = dev->crop_current; + return 0; } - if (mode != t->audmode) - dev->thread.mode = t->audmode; - - return 0; -} - -static int saa7134_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - - return 0; -} - -static int saa7134_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int err; - - err = v4l2_prio_check(&dev->prio, &fh->prio); - if (0 != err) - return err; - - if (0 != f->tuner) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; - - saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; -} - -static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - strcpy(a->name, "audio"); - return 0; -} - -static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - return 0; -} - -static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - *p = v4l2_prio_max(&dev->prio); - return 0; -} + case VIDIOC_S_CROP: + { + struct v4l2_crop *crop = arg; + struct v4l2_rect *b = &dev->crop_bounds; -static int saa7134_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + if (crop->c.height < 0) + return -EINVAL; + if (crop->c.width < 0) + return -EINVAL; - return v4l2_prio_change(&dev->prio, &fh->prio, prio); -} + if (res_locked(fh->dev,RESOURCE_OVERLAY)) + return -EBUSY; + if (res_locked(fh->dev,RESOURCE_VIDEO)) + return -EBUSY; -static int saa7134_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index >= FORMATS) - return -EINVAL; + if (crop->c.top < b->top) + crop->c.top = b->top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height; + if (crop->c.height > b->top - crop->c.top + b->height) + crop->c.height = b->top - crop->c.top + b->height; + + if (crop->c.left < b->left) + crop->c.left = b->left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = b->left - crop->c.left + b->width; + + dev->crop_current = crop->c; + return 0; + } - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); + /* --- tuner ioctls ------------------------------------------ */ + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + int n; - f->pixelformat = formats[f->index].fourcc; + if (0 != t->index) + return -EINVAL; + memset(t,0,sizeof(*t)); + for (n = 0; n < SAA7134_INPUT_MAX; n++) + if (card_in(dev,n).tv) + break; + if (NULL != card_in(dev,n).name) { + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2; + t->rangehigh = 0xffffffffUL; + t->rxsubchans = saa7134_tvaudio_getstereo(dev); + t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); + } + if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) + t->signal = 0xffff; + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; + int rx,mode; - return 0; -} + mode = dev->thread.mode; + if (UNSET == mode) { + rx = saa7134_tvaudio_getstereo(dev); + mode = saa7134_tvaudio_rx2mode(t->rxsubchans); + } + if (mode != t->audmode) { + dev->thread.mode = t->audmode; + } + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; -static int saa7134_enum_fmt_overlay(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; + memset(f,0,sizeof(*f)); + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + return 0; } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; - if ((f->index >= FORMATS) || formats[f->index].planar) - return -EINVAL; + if (0 != f->tuner) + return -EINVAL; + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) + return -EINVAL; + mutex_lock(&dev->lock); + dev->ctl_freq = f->frequency; - strlcpy(f->description, formats[f->index].name, - sizeof(f->description)); + saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f); - f->pixelformat = formats[f->index].fourcc; + saa7134_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; + } - return 0; -} + /* --- control ioctls ---------------------------------------- */ + case VIDIOC_ENUMINPUT: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + case VIDIOC_QUERYCTRL: + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: + return saa7134_common_ioctl(dev, cmd, arg); -static int saa7134_enum_fmt_vbi(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (0 != f->index) - return -EINVAL; + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description, "vbi data"); + memset(a,0,sizeof(*a)); + strcpy(a->name,"audio"); + return 0; + } + case VIDIOC_S_AUDIO: + return 0; + case VIDIOC_G_PARM: + { + struct v4l2_captureparm *parm = arg; + memset(parm,0,sizeof(*parm)); + return 0; + } - return 0; -} + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; -static int saa7134_g_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; + *p = v4l2_prio_max(&dev->prio); + return 0; + } + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *prio = arg; - *fb = dev->ovbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + return v4l2_prio_change(&dev->prio, &fh->prio, *prio); + } - return 0; -} + /* --- preview ioctls ---------------------------------------- */ + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *f = arg; + enum v4l2_buf_type type; + unsigned int index; + + index = f->index; + type = f->type; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + if (index >= FORMATS) + return -EINVAL; + if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && + formats[index].planar) + return -EINVAL; + memset(f,0,sizeof(*f)); + f->index = index; + f->type = type; + strlcpy(f->description,formats[index].name,sizeof(f->description)); + f->pixelformat = formats[index].fourcc; + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (0 != index) + return -EINVAL; + memset(f,0,sizeof(*f)); + f->index = index; + f->type = type; + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description,"vbi data"); + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_G_FBUF: + { + struct v4l2_framebuffer *fb = arg; -static int saa7134_s_fbuf(struct file *file, void *f, - struct v4l2_framebuffer *fb) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - struct saa7134_format *fmt; + *fb = dev->ovbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + return 0; + } + case VIDIOC_S_FBUF: + { + struct v4l2_framebuffer *fb = arg; + struct saa7134_format *fmt; - if (!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; - /* ok, accept it */ - dev->ovbuf = *fb; - dev->ovfmt = fmt; - if (0 == dev->ovbuf.fmt.bytesperline) - dev->ovbuf.fmt.bytesperline = - dev->ovbuf.fmt.width*fmt->depth/8; - return 0; -} + /* ok, accept it */ + dev->ovbuf = *fb; + dev->ovfmt = fmt; + if (0 == dev->ovbuf.fmt.bytesperline) + dev->ovbuf.fmt.bytesperline = + dev->ovbuf.fmt.width*fmt->depth/8; + return 0; + } + case VIDIOC_OVERLAY: + { + int *on = arg; -static int saa7134_overlay(struct file *file, void *f, unsigned int on) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - unsigned long flags; + if (*on) { + if (saa7134_no_overlay > 0) { + printk ("no_overlay\n"); + return -EINVAL; + } - if (on) { - if (saa7134_no_overlay > 0) { - dprintk("no_overlay\n"); - return -EINVAL; + if (!res_get(dev,fh,RESOURCE_OVERLAY)) + return -EBUSY; + spin_lock_irqsave(&dev->slock,flags); + start_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); } + if (!*on) { + if (!res_check(fh, RESOURCE_OVERLAY)) + return -EINVAL; + spin_lock_irqsave(&dev->slock,flags); + stop_preview(dev,fh); + spin_unlock_irqrestore(&dev->slock,flags); + res_free(dev,fh,RESOURCE_OVERLAY); + } + return 0; + } - if (!res_get(dev, fh, RESOURCE_OVERLAY)) - return -EBUSY; - spin_lock_irqsave(&dev->slock, flags); - start_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); + /* --- capture ioctls ---------------------------------------- */ + case VIDIOC_G_FMT: + { + struct v4l2_format *f = arg; + return saa7134_g_fmt(dev,fh,f); } - if (!on) { - if (!res_check(fh, RESOURCE_OVERLAY)) - return -EINVAL; - spin_lock_irqsave(&dev->slock, flags); - stop_preview(dev, fh); - spin_unlock_irqrestore(&dev->slock, flags); - res_free(dev, fh, RESOURCE_OVERLAY); + case VIDIOC_S_FMT: + { + struct v4l2_format *f = arg; + return saa7134_s_fmt(dev,fh,f); + } + case VIDIOC_TRY_FMT: + { + struct v4l2_format *f = arg; + return saa7134_try_fmt(dev,fh,f); } - return 0; -} - #ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) -{ - struct saa7134_fh *fh = file->private_data; - return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8); -} + case VIDIOCGMBUF: + return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers); #endif + case VIDIOC_REQBUFS: + return videobuf_reqbufs(saa7134_queue(fh),arg); -static int saa7134_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct saa7134_fh *fh = priv; - return videobuf_reqbufs(saa7134_queue(fh), p); -} - -static int saa7134_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_querybuf(saa7134_queue(fh), b); -} - -static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_qbuf(saa7134_queue(fh), b); -} + case VIDIOC_QUERYBUF: + return videobuf_querybuf(saa7134_queue(fh),arg); -static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_fh *fh = priv; - return videobuf_dqbuf(saa7134_queue(fh), b, - file->f_flags & O_NONBLOCK); -} + case VIDIOC_QBUF: + return videobuf_qbuf(saa7134_queue(fh),arg); -static int saa7134_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int res = saa7134_resource(fh); + case VIDIOC_DQBUF: + return videobuf_dqbuf(saa7134_queue(fh),arg, + file->f_flags & O_NONBLOCK); - if (!res_get(dev, fh, res)) - return -EBUSY; + case VIDIOC_STREAMON: + { + int res = saa7134_resource(fh); - return videobuf_streamon(saa7134_queue(fh)); -} + if (!res_get(dev,fh,res)) + return -EBUSY; + return videobuf_streamon(saa7134_queue(fh)); + } + case VIDIOC_STREAMOFF: + { + int res = saa7134_resource(fh); -static int saa7134_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - int err; - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; - int res = saa7134_resource(fh); + err = videobuf_streamoff(saa7134_queue(fh)); + if (err < 0) + return err; + res_free(dev,fh,res); + return 0; + } - err = videobuf_streamoff(saa7134_queue(fh)); - if (err < 0) - return err; - res_free(dev, fh, res); + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + video_do_ioctl); + } return 0; } -static int saa7134_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) +static int video_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - return 0; + return video_usercopy(inode, file, cmd, arg, video_do_ioctl); } -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) +static int radio_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) { struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; + if (video_debug > 1) + v4l_print_ioctl(dev->name,cmd); + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = arg; + + memset(cap,0,sizeof(*cap)); + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; - if (0 != t->index) - return -EINVAL; + if (0 != t->index) + return -EINVAL; - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; + memset(t,0,sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; - saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - if (dev->input->amux == TV) { - t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); - t->rxsubchans = (saa_readb(0x529) & 0x08) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + if (dev->input->amux == TV) { + t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); + t->rxsubchans = (saa_readb(0x529) & 0x08) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } + return 0; } - return 0; -} -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - - if (0 != t->index) - return -EINVAL; + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *t = arg; - saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t); - return 0; -} + if (0 != t->index) + return -EINVAL; -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; + saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t); - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; + return 0; + } + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *i = arg; - return 0; -} + if (i->index != 0) + return -EINVAL; + strcpy(i->name,"Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + return 0; + } + case VIDIOC_G_INPUT: + { + int *i = arg; + *i = 0; + return 0; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} + memset(a,0,sizeof(*a)); + strcpy(a->name,"Radio"); + return 0; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; + *id = 0; + return 0; + } + case VIDIOC_S_AUDIO: + case VIDIOC_S_INPUT: + case VIDIOC_S_STD: + return 0; -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - memset(a, 0, sizeof(*a)); - strcpy(a->name, "Radio"); - return 0; -} + case VIDIOC_QUERYCTRL: + { + const struct v4l2_queryctrl *ctrl; + struct v4l2_queryctrl *c = arg; -static int radio_s_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - return 0; -} + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctrl; + return 0; + } -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - return 0; -} + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + return video_do_ioctl(inode,file,cmd,arg); -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ + default: + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + radio_do_ioctl); + } return 0; } -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) +static int radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctrl; - return 0; + return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); } static const struct file_operations video_fops = @@ -2327,7 +2333,7 @@ static const struct file_operations video_fops = .read = video_read, .poll = video_poll, .mmap = video_mmap, - .ioctl = video_ioctl2, + .ioctl = video_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2337,7 +2343,7 @@ static const struct file_operations radio_fops = .owner = THIS_MODULE, .open = video_open, .release = video_release, - .ioctl = video_ioctl2, + .ioctl = radio_ioctl, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2347,79 +2353,27 @@ static const struct file_operations radio_fops = struct video_device saa7134_video_template = { - .name = "saa7134-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER | - VID_TYPE_CLIPPING|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, - .vidioc_querycap = saa7134_querycap, - .vidioc_enum_fmt_cap = saa7134_enum_fmt_cap, - .vidioc_g_fmt_cap = saa7134_g_fmt_cap, - .vidioc_try_fmt_cap = saa7134_try_fmt_cap, - .vidioc_s_fmt_cap = saa7134_s_fmt_cap, - .vidioc_enum_fmt_overlay = saa7134_enum_fmt_overlay, - .vidioc_g_fmt_overlay = saa7134_g_fmt_overlay, - .vidioc_try_fmt_overlay = saa7134_try_fmt_overlay, - .vidioc_s_fmt_overlay = saa7134_s_fmt_overlay, - .vidioc_enum_fmt_vbi = saa7134_enum_fmt_vbi, - .vidioc_g_fmt_vbi = saa7134_try_get_set_fmt_vbi, - .vidioc_try_fmt_vbi = saa7134_try_get_set_fmt_vbi, - .vidioc_s_fmt_vbi = saa7134_try_get_set_fmt_vbi, - .vidioc_g_audio = saa7134_g_audio, - .vidioc_s_audio = saa7134_s_audio, - .vidioc_cropcap = saa7134_cropcap, - .vidioc_reqbufs = saa7134_reqbufs, - .vidioc_querybuf = saa7134_querybuf, - .vidioc_qbuf = saa7134_qbuf, - .vidioc_dqbuf = saa7134_dqbuf, - .vidioc_s_std = saa7134_s_std, - .vidioc_enum_input = saa7134_enum_input, - .vidioc_g_input = saa7134_g_input, - .vidioc_s_input = saa7134_s_input, - .vidioc_queryctrl = saa7134_queryctrl, - .vidioc_g_ctrl = saa7134_g_ctrl, - .vidioc_s_ctrl = saa7134_s_ctrl, - .vidioc_streamon = saa7134_streamon, - .vidioc_streamoff = saa7134_streamoff, - .vidioc_g_tuner = saa7134_g_tuner, - .vidioc_s_tuner = saa7134_s_tuner, -#ifdef CONFIG_VIDEO_V4L1_COMPAT - .vidiocgmbuf = vidiocgmbuf, -#endif - .vidioc_g_crop = saa7134_g_crop, - .vidioc_s_crop = saa7134_s_crop, - .vidioc_g_fbuf = saa7134_g_fbuf, - .vidioc_s_fbuf = saa7134_s_fbuf, - .vidioc_overlay = saa7134_overlay, - .vidioc_g_priority = saa7134_g_priority, - .vidioc_s_priority = saa7134_s_priority, - .vidioc_g_parm = saa7134_g_parm, - .vidioc_g_frequency = saa7134_g_frequency, - .vidioc_s_frequency = saa7134_s_frequency, - .tvnorms = SAA7134_NORMS, - .current_norm = V4L2_STD_PAL, + .name = "saa7134-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER| + VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .fops = &video_fops, + .minor = -1, +}; + +struct video_device saa7134_vbi_template = +{ + .name = "saa7134-vbi", + .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, + .fops = &video_fops, + .minor = -1, }; struct video_device saa7134_radio_template = { - .name = "saa7134-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, - .vidioc_g_ctrl = saa7134_g_ctrl, - .vidioc_s_ctrl = saa7134_s_ctrl, - .vidioc_g_frequency = saa7134_g_frequency, - .vidioc_s_frequency = saa7134_s_frequency, + .name = "saa7134-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .minor = -1, }; int saa7134_video_init1(struct saa7134_dev *dev) @@ -2557,7 +2511,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) goto done; } dev->video_q.curr->vb.field_count = dev->video_fieldcount; - saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE); + saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); } saa7134_buffer_next(dev,&dev->video_q); diff --git a/trunk/drivers/media/video/saa7134/saa7134.h b/trunk/drivers/media/video/saa7134/saa7134.h index ce450304fb53..66a390c321a7 100644 --- a/trunk/drivers/media/video/saa7134/saa7134.h +++ b/trunk/drivers/media/video/saa7134/saa7134.h @@ -240,19 +240,6 @@ struct saa7134_format { #define SAA7134_BOARD_SABRENT_TV_PCB05 115 #define SAA7134_BOARD_10MOONSTVMASTER3 116 #define SAA7134_BOARD_AVERMEDIA_SUPER_007 117 -#define SAA7134_BOARD_BEHOLD_401 118 -#define SAA7134_BOARD_BEHOLD_403 119 -#define SAA7134_BOARD_BEHOLD_403FM 120 -#define SAA7134_BOARD_BEHOLD_405 121 -#define SAA7134_BOARD_BEHOLD_405FM 122 -#define SAA7134_BOARD_BEHOLD_407 123 -#define SAA7134_BOARD_BEHOLD_407FM 124 -#define SAA7134_BOARD_BEHOLD_409 125 -#define SAA7134_BOARD_BEHOLD_505FM 126 -#define SAA7134_BOARD_BEHOLD_507_9FM 127 -#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128 -#define SAA7134_BOARD_BEHOLD_607_9FM 129 -#define SAA7134_BOARD_BEHOLD_M6 130 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -494,7 +481,7 @@ struct saa7134_dev { /* i2c i/o */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; - unsigned char eedata[256]; + unsigned char eedata[128]; /* video overlay */ struct v4l2_framebuffer ovbuf; @@ -579,12 +566,6 @@ struct saa7134_dev { #define saa_wait(us) { udelay(us); } -#define SAA7134_NORMS (\ - V4L2_STD_PAL | V4L2_STD_PAL_N | \ - V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ - V4L2_STD_NTSC | V4L2_STD_PAL_M | \ - V4L2_STD_PAL_60) - /* ----------------------------------------------------------- */ /* saa7134-core.c */ @@ -615,6 +596,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); void saa7134_buffer_timeout(unsigned long data); void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); +int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q); + int saa7134_set_dmabits(struct saa7134_dev *dev); extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); @@ -644,17 +628,16 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, /* ----------------------------------------------------------- */ /* saa7134-video.c */ -extern unsigned int video_debug; extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; -int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c); -int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c); -int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); - +void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm); int saa7134_videoport_init(struct saa7134_dev *dev); void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); +int saa7134_common_ioctl(struct saa7134_dev *dev, + unsigned int cmd, void *arg); + int saa7134_video_init1(struct saa7134_dev *dev); int saa7134_video_init2(struct saa7134_dev *dev); void saa7134_irq_video_signalchange(struct saa7134_dev *dev); @@ -699,7 +682,6 @@ void saa7134_tvaudio_setinput(struct saa7134_dev *dev, void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level); int saa7134_tvaudio_getstereo(struct saa7134_dev *dev); -void saa7134_tvaudio_init(struct saa7134_dev *dev); int saa7134_tvaudio_init2(struct saa7134_dev *dev); int saa7134_tvaudio_fini(struct saa7134_dev *dev); int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); diff --git a/trunk/drivers/media/video/sn9c102/Makefile b/trunk/drivers/media/video/sn9c102/Makefile index 7ecd5a90c7c9..a56d16f69c71 100644 --- a/trunk/drivers/media/video/sn9c102/Makefile +++ b/trunk/drivers/media/video/sn9c102/Makefile @@ -3,7 +3,6 @@ sn9c102-objs := sn9c102_core.o \ sn9c102_hv7131r.o \ sn9c102_mi0343.o \ sn9c102_mi0360.o \ - sn9c102_mt9v111.o \ sn9c102_ov7630.o \ sn9c102_ov7660.o \ sn9c102_pas106b.o \ diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_core.c b/trunk/drivers/media/video/sn9c102/sn9c102_core.c index c40ba3adab21..511847912c48 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_core.c +++ b/trunk/drivers/media/video/sn9c102/sn9c102_core.c @@ -47,7 +47,7 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.47pre49" +#define SN9C102_MODULE_VERSION "1:1.47" #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47) /*****************************************************************************/ @@ -3322,6 +3322,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; + video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); @@ -3339,7 +3340,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); - video_set_drvdata(cam->v4ldev, cam); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h b/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h index 35223e0d7e49..916054faf9be 100644 --- a/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/trunk/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -126,7 +126,6 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); -extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam); extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); @@ -145,7 +144,6 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ diff --git a/trunk/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/trunk/drivers/media/video/sn9c102/sn9c102_mt9v111.c deleted file mode 100644 index 3b98ac3bbc38..000000000000 --- a/trunk/drivers/media/video/sn9c102/sn9c102_mt9v111.c +++ /dev/null @@ -1,259 +0,0 @@ -/*************************************************************************** - * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera * - * Controllers * - * * - * Copyright (C) 2007 by Luca Risolia * - * * - * 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 "sn9c102_sensor.h" - - -static int mt9v111_init(struct sn9c102_device *cam) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - - err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, - {0x00, 0x03}, {0x1a, 0x04}, - {0x1f, 0x05}, {0x20, 0x06}, - {0x1f, 0x07}, {0x81, 0x08}, - {0x5c, 0x09}, {0x00, 0x0a}, - {0x00, 0x0b}, {0x00, 0x0c}, - {0x00, 0x0d}, {0x00, 0x0e}, - {0x00, 0x0f}, {0x03, 0x10}, - {0x00, 0x11}, {0x00, 0x12}, - {0x02, 0x13}, {0x14, 0x14}, - {0x28, 0x15}, {0x1e, 0x16}, - {0xe2, 0x17}, {0x06, 0x18}, - {0x00, 0x19}, {0x00, 0x1a}, - {0x00, 0x1b}, {0x08, 0x20}, - {0x39, 0x21}, {0x51, 0x22}, - {0x63, 0x23}, {0x73, 0x24}, - {0x82, 0x25}, {0x8f, 0x26}, - {0x9b, 0x27}, {0xa7, 0x28}, - {0xb1, 0x29}, {0xbc, 0x2a}, - {0xc6, 0x2b}, {0xcf, 0x2c}, - {0xd8, 0x2d}, {0xe1, 0x2e}, - {0xea, 0x2f}, {0xf2, 0x30}, - {0x13, 0x84}, {0x00, 0x85}, - {0x25, 0x86}, {0x00, 0x87}, - {0x07, 0x88}, {0x00, 0x89}, - {0xee, 0x8a}, {0x0f, 0x8b}, - {0xe5, 0x8c}, {0x0f, 0x8d}, - {0x2e, 0x8e}, {0x00, 0x8f}, - {0x30, 0x90}, {0x00, 0x91}, - {0xd4, 0x92}, {0x0f, 0x93}, - {0xfc, 0x94}, {0x0f, 0x95}, - {0x14, 0x96}, {0x00, 0x97}, - {0x00, 0x98}, {0x60, 0x99}, - {0x07, 0x9a}, {0x40, 0x9b}, - {0x20, 0x9c}, {0x00, 0x9d}, - {0x00, 0x9e}, {0x00, 0x9f}, - {0x2d, 0xc0}, {0x2d, 0xc1}, - {0x3a, 0xc2}, {0x05, 0xc3}, - {0x04, 0xc4}, {0x3f, 0xc5}, - {0x00, 0xc6}, {0x00, 0xc7}, - {0x50, 0xc8}, {0x3c, 0xc9}, - {0x28, 0xca}, {0xd8, 0xcb}, - {0x14, 0xcc}, {0xec, 0xcd}, - {0x32, 0xce}, {0xdd, 0xcf}, - {0x2d, 0xd0}, {0xdd, 0xd1}, - {0x6a, 0xd2}, {0x50, 0xd3}, - {0x60, 0xd4}, {0x00, 0xd5}, - {0x00, 0xd6}); - - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x01, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, - 0x04, 0x80, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x04, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, - 0x00, 0x08, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02, - 0x00, 0x16, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, - 0x01, 0xe7, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, - 0x02, 0x87, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, - 0x00, 0x40, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, - 0x00, 0x09, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07, - 0x30, 0x02, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12, - 0x00, 0xb0, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13, - 0x00, 0x7c, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, - 0x00, 0x00, 0, 0); - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, - 0x00, 0x04, 0, 0); - - return err; -} - -static int mt9v111_get_ctrl(struct sn9c102_device *cam, - struct v4l2_control *ctrl) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - u8 data[2]; - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, - data) < 0) - return -EIO; - ctrl->value = data[1] & 0x80 ? 1 : 0; - return 0; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - -static int mt9v111_set_ctrl(struct sn9c102_device *cam, - const struct v4l2_control *ctrl) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, - 0x20, - ctrl->value ? 0x80 : 0x00, - ctrl->value ? 0x80 : 0x00, 0, - 0); - break; - default: - return -EINVAL; - } - - return err ? -EIO : 0; -} - -static int mt9v111_set_crop(struct sn9c102_device *cam, - const struct v4l2_rect *rect) -{ - struct sn9c102_sensor *s = sn9c102_get_sensor(cam); - int err = 0; - u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2; - - err += sn9c102_write_reg(cam, v_start, 0x13); - - return err; -} - -static int mt9v111_set_pix_format(struct sn9c102_device *cam, - const struct v4l2_pix_format *pix) -{ - int err = 0; - - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { - err += sn9c102_write_reg(cam, 0xb4, 0x17); - } else { - err += sn9c102_write_reg(cam, 0xe2, 0x17); - } - - return err; -} - - -static const struct sn9c102_sensor mt9v111 = { - .name = "MT9V111", - .maintainer = "Luca Risolia ", - .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, - .frequency = SN9C102_I2C_100KHZ, - .interface = SN9C102_I2C_2WIRES, - .i2c_slave_id = 0x5c, - .init = &mt9v111_init, - .qctrl = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = 0, - }, - }, - .get_ctrl = &mt9v111_get_ctrl, - .set_ctrl = &mt9v111_set_ctrl, - .cropcap = { - .bounds = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - .defrect = { - .left = 0, - .top = 0, - .width = 640, - .height = 480, - }, - }, - .set_crop = &mt9v111_set_crop, - .pix_format = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .priv = 8, - }, - .set_pix_format = &mt9v111_set_pix_format -}; - - -int sn9c102_probe_mt9v111(struct sn9c102_device *cam) -{ - u8 data[2]; - int err = 0; - - err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, - {0x29, 0x01}, {0x42, 0x17}, - {0x62, 0x17}, {0x08, 0x01}); - err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4, - mt9v111.i2c_slave_id, 0x01, 0x00, - 0x04, 0, 0); - if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111, - mt9v111.i2c_slave_id, 0x36, 2, - data) < 0) - return -EIO; - - if (data[0] != 0x82 || data[1] != 0x3a) - return -ENODEV; - - sn9c102_attach_sensor(cam, &mt9v111); - - return 0; -} diff --git a/trunk/drivers/media/video/stk-sensor.c b/trunk/drivers/media/video/stk-sensor.c deleted file mode 100644 index 4a9a0b62efa3..000000000000 --- a/trunk/drivers/media/video/stk-sensor.c +++ /dev/null @@ -1,578 +0,0 @@ -/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams) - * - * Copyright 2007-2008 Jaime Velasco Juan - * - * Some parts derived from ov7670.c: - * Copyright 2006 One Laptop Per Child Association, Inc. Written - * by Jonathan Corbet with substantial inspiration from Mark - * McClelland's ovcamchip code. - * - * Copyright 2006-7 Jonathan Corbet - * - * This file may be distributed under the terms of the GNU General - * 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. - */ - -/* Controlling the sensor via the STK1125 vendor specific control interface: - * The camera uses an OmniVision sensor and the stk1125 provides an - * SCCB(i2c)-USB bridge which let us program the sensor. - * In my case the sensor id is 0x9652, it can be read from sensor's register - * 0x0A and 0x0B as follows: - * - read register #R: - * output #R to index 0x0208 - * output 0x0070 to index 0x0200 - * input 1 byte from index 0x0201 (some kind of status register) - * until its value is 0x01 - * input 1 byte from index 0x0209. This is the value of #R - * - write value V to register #R - * output #R to index 0x0204 - * output V to index 0x0205 - * output 0x0005 to index 0x0200 - * input 1 byte from index 0x0201 until its value becomes 0x04 - */ - -/* It seems the i2c bus is controlled with these registers */ - -#include "stk-webcam.h" - -#define STK_IIC_BASE (0x0200) -# define STK_IIC_OP (STK_IIC_BASE) -# define STK_IIC_OP_TX (0x05) -# define STK_IIC_OP_RX (0x70) -# define STK_IIC_STAT (STK_IIC_BASE+1) -# define STK_IIC_STAT_TX_OK (0x04) -# define STK_IIC_STAT_RX_OK (0x01) -/* I don't know what does this register. - * when it is 0x00 or 0x01, we cannot talk to the sensor, - * other values work */ -# define STK_IIC_ENABLE (STK_IIC_BASE+2) -# define STK_IIC_ENABLE_NO (0x00) -/* This is what the driver writes in windows */ -# define STK_IIC_ENABLE_YES (0x1e) -/* - * Address of the slave. Seems like the binary driver look for the - * sensor in multiple places, attempting a reset sequence. - * We only know about the ov9650 - */ -# define STK_IIC_ADDR (STK_IIC_BASE+3) -# define STK_IIC_TX_INDEX (STK_IIC_BASE+4) -# define STK_IIC_TX_VALUE (STK_IIC_BASE+5) -# define STK_IIC_RX_INDEX (STK_IIC_BASE+8) -# define STK_IIC_RX_VALUE (STK_IIC_BASE+9) - -#define MAX_RETRIES (50) - -#define SENSOR_ADDRESS (0x60) - -/* From ov7670.c (These registers aren't fully accurate) */ - -/* Registers */ -#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ -#define REG_BLUE 0x01 /* blue gain */ -#define REG_RED 0x02 /* red gain */ -#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ -#define REG_COM1 0x04 /* Control 1 */ -#define COM1_CCIR656 0x40 /* CCIR656 enable */ -#define COM1_QFMT 0x20 /* QVGA/QCIF format */ -#define COM1_SKIP_0 0x00 /* Do not skip any row */ -#define COM1_SKIP_2 0x04 /* Skip 2 rows of 4 */ -#define COM1_SKIP_3 0x08 /* Skip 3 rows of 4 */ -#define REG_BAVE 0x05 /* U/B Average level */ -#define REG_GbAVE 0x06 /* Y/Gb Average level */ -#define REG_AECHH 0x07 /* AEC MS 5 bits */ -#define REG_RAVE 0x08 /* V/R Average level */ -#define REG_COM2 0x09 /* Control 2 */ -#define COM2_SSLEEP 0x10 /* Soft sleep mode */ -#define REG_PID 0x0a /* Product ID MSB */ -#define REG_VER 0x0b /* Product ID LSB */ -#define REG_COM3 0x0c /* Control 3 */ -#define COM3_SWAP 0x40 /* Byte swap */ -#define COM3_SCALEEN 0x08 /* Enable scaling */ -#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ -#define REG_COM4 0x0d /* Control 4 */ -#define REG_COM5 0x0e /* All "reserved" */ -#define REG_COM6 0x0f /* Control 6 */ -#define REG_AECH 0x10 /* More bits of AEC value */ -#define REG_CLKRC 0x11 /* Clock control */ -#define CLK_PLL 0x80 /* Enable internal PLL */ -#define CLK_EXT 0x40 /* Use external clock directly */ -#define CLK_SCALE 0x3f /* Mask for internal clock scale */ -#define REG_COM7 0x12 /* Control 7 */ -#define COM7_RESET 0x80 /* Register reset */ -#define COM7_FMT_MASK 0x38 -#define COM7_FMT_SXGA 0x00 -#define COM7_FMT_VGA 0x40 -#define COM7_FMT_CIF 0x20 /* CIF format */ -#define COM7_FMT_QVGA 0x10 /* QVGA format */ -#define COM7_FMT_QCIF 0x08 /* QCIF format */ -#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ -#define COM7_YUV 0x00 /* YUV */ -#define COM7_BAYER 0x01 /* Bayer format */ -#define COM7_PBAYER 0x05 /* "Processed bayer" */ -#define REG_COM8 0x13 /* Control 8 */ -#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ -#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ -#define COM8_BFILT 0x20 /* Band filter enable */ -#define COM8_AGC 0x04 /* Auto gain enable */ -#define COM8_AWB 0x02 /* White balance enable */ -#define COM8_AEC 0x01 /* Auto exposure enable */ -#define REG_COM9 0x14 /* Control 9 - gain ceiling */ -#define REG_COM10 0x15 /* Control 10 */ -#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ -#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ -#define COM10_HREF_REV 0x08 /* Reverse HREF */ -#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ -#define COM10_VS_NEG 0x02 /* VSYNC negative */ -#define COM10_HS_NEG 0x01 /* HSYNC negative */ -#define REG_HSTART 0x17 /* Horiz start high bits */ -#define REG_HSTOP 0x18 /* Horiz stop high bits */ -#define REG_VSTART 0x19 /* Vert start high bits */ -#define REG_VSTOP 0x1a /* Vert stop high bits */ -#define REG_PSHFT 0x1b /* Pixel delay after HREF */ -#define REG_MIDH 0x1c /* Manuf. ID high */ -#define REG_MIDL 0x1d /* Manuf. ID low */ -#define REG_MVFP 0x1e /* Mirror / vflip */ -#define MVFP_MIRROR 0x20 /* Mirror image */ -#define MVFP_FLIP 0x10 /* Vertical flip */ - -#define REG_AEW 0x24 /* AGC upper limit */ -#define REG_AEB 0x25 /* AGC lower limit */ -#define REG_VPT 0x26 /* AGC/AEC fast mode op region */ -#define REG_ADVFL 0x2d /* Insert dummy lines (LSB) */ -#define REG_ADVFH 0x2e /* Insert dummy lines (MSB) */ -#define REG_HSYST 0x30 /* HSYNC rising edge delay */ -#define REG_HSYEN 0x31 /* HSYNC falling edge delay */ -#define REG_HREF 0x32 /* HREF pieces */ -#define REG_TSLB 0x3a /* lots of stuff */ -#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ -#define TSLB_BYTEORD 0x08 /* swap bytes in 16bit mode? */ -#define REG_COM11 0x3b /* Control 11 */ -#define COM11_NIGHT 0x80 /* NIght mode enable */ -#define COM11_NMFR 0x60 /* Two bit NM frame rate */ -#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ -#define COM11_50HZ 0x08 /* Manual 50Hz select */ -#define COM11_EXP 0x02 -#define REG_COM12 0x3c /* Control 12 */ -#define COM12_HREF 0x80 /* HREF always */ -#define REG_COM13 0x3d /* Control 13 */ -#define COM13_GAMMA 0x80 /* Gamma enable */ -#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ -#define COM13_CMATRIX 0x10 /* Enable color matrix for RGB or YUV */ -#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ -#define REG_COM14 0x3e /* Control 14 */ -#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ -#define REG_EDGE 0x3f /* Edge enhancement factor */ -#define REG_COM15 0x40 /* Control 15 */ -#define COM15_R10F0 0x00 /* Data range 10 to F0 */ -#define COM15_R01FE 0x80 /* 01 to FE */ -#define COM15_R00FF 0xc0 /* 00 to FF */ -#define COM15_RGB565 0x10 /* RGB565 output */ -#define COM15_RGBFIXME 0x20 /* FIXME */ -#define COM15_RGB555 0x30 /* RGB555 output */ -#define REG_COM16 0x41 /* Control 16 */ -#define COM16_AWBGAIN 0x08 /* AWB gain enable */ -#define REG_COM17 0x42 /* Control 17 */ -#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ -#define COM17_CBAR 0x08 /* DSP Color bar */ - -/* - * This matrix defines how the colors are generated, must be - * tweaked to adjust hue and saturation. - * - * Order: v-red, v-green, v-blue, u-red, u-green, u-blue - * - * They are nine-bit signed quantities, with the sign bit - * stored in 0x58. Sign for v-red is bit 0, and up from there. - */ -#define REG_CMATRIX_BASE 0x4f -#define CMATRIX_LEN 6 -#define REG_CMATRIX_SIGN 0x58 - - -#define REG_BRIGHT 0x55 /* Brightness */ -#define REG_CONTRAS 0x56 /* Contrast control */ - -#define REG_GFIX 0x69 /* Fix gain control */ - -#define REG_RGB444 0x8c /* RGB 444 control */ -#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ -#define R444_RGBX 0x01 /* Empty nibble at end */ - -#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ -#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ - -#define REG_BD50MAX 0xa5 /* 50hz banding step limit */ -#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ -#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ -#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ -#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ -#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ -#define REG_BD60MAX 0xab /* 60hz banding step limit */ - - - - -/* Returns 0 if OK */ -int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) -{ - int i = 0; - int tmpval = 0; - - if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX)) - return 1; - do { - if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) - return 1; - i++; - } while (tmpval == 0 && i < MAX_RETRIES); - if (tmpval != STK_IIC_STAT_TX_OK) { - if (tmpval) - STK_ERROR("stk_sensor_outb failed, status=0x%02x\n", - tmpval); - return 1; - } else - return 0; -} - -int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) -{ - int i = 0; - int tmpval = 0; - - if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg)) - return 1; - if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX)) - return 1; - do { - if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) - return 1; - i++; - } while (tmpval == 0 && i < MAX_RETRIES); - if (tmpval != STK_IIC_STAT_RX_OK) { - if (tmpval) - STK_ERROR("stk_sensor_inb failed, status=0x%02x\n", - tmpval); - return 1; - } - - if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval)) - return 1; - - *val = (u8) tmpval; - return 0; -} - -static int stk_sensor_write_regvals(struct stk_camera *dev, - struct regval *rv) -{ - int ret; - if (rv == NULL) - return 0; - while (rv->reg != 0xff || rv->val != 0xff) { - ret = stk_sensor_outb(dev, rv->reg, rv->val); - if (ret != 0) - return ret; - rv++; - } - return 0; -} - -int stk_sensor_sleep(struct stk_camera *dev) -{ - u8 tmp; - return stk_sensor_inb(dev, REG_COM2, &tmp) - || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP); -} - -int stk_sensor_wakeup(struct stk_camera *dev) -{ - u8 tmp; - return stk_sensor_inb(dev, REG_COM2, &tmp) - || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP); -} - -static struct regval ov_initvals[] = { - {REG_CLKRC, CLK_PLL}, - {REG_COM11, 0x01}, - {0x6a, 0x7d}, - {REG_AECH, 0x40}, - {REG_GAIN, 0x00}, - {REG_BLUE, 0x80}, - {REG_RED, 0x80}, - /* Do not enable fast AEC for now */ - /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/ - {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC}, - {0x39, 0x50}, {0x38, 0x93}, - {0x37, 0x00}, {0x35, 0x81}, - {REG_COM5, 0x20}, - {REG_COM1, 0x00}, - {REG_COM3, 0x00}, - {REG_COM4, 0x00}, - {REG_PSHFT, 0x00}, - {0x16, 0x07}, - {0x33, 0xe2}, {0x34, 0xbf}, - {REG_COM16, 0x00}, - {0x96, 0x04}, - /* Gamma curve values */ -/* { 0x7a, 0x20 }, { 0x7b, 0x10 }, - { 0x7c, 0x1e }, { 0x7d, 0x35 }, - { 0x7e, 0x5a }, { 0x7f, 0x69 }, - { 0x80, 0x76 }, { 0x81, 0x80 }, - { 0x82, 0x88 }, { 0x83, 0x8f }, - { 0x84, 0x96 }, { 0x85, 0xa3 }, - { 0x86, 0xaf }, { 0x87, 0xc4 }, - { 0x88, 0xd7 }, { 0x89, 0xe8 }, -*/ - {REG_GFIX, 0x40}, - {0x8e, 0x00}, - {REG_COM12, 0x73}, - {0x8f, 0xdf}, {0x8b, 0x06}, - {0x8c, 0x20}, - {0x94, 0x88}, {0x95, 0x88}, -/* {REG_COM15, 0xc1}, TODO */ - {0x29, 0x3f}, - {REG_COM6, 0x42}, - {REG_BD50MAX, 0x80}, - {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92}, - {REG_BD60MAX, 0x0a}, - {0x90, 0x00}, {0x91, 0x00}, - {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00}, - {REG_AEW, 0x68}, {REG_AEB, 0x5c}, - {REG_VPT, 0xc3}, - {REG_COM9, 0x2e}, - {0x2a, 0x00}, {0x2b, 0x00}, - - {0xff, 0xff}, /* END MARKER */ -}; - -/* Probe the I2C bus and initialise the sensor chip */ -int stk_sensor_init(struct stk_camera *dev) -{ - u8 idl = 0; - u8 idh = 0; - - if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES) - || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS) - || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) { - STK_ERROR("Sensor resetting failed\n"); - return -ENODEV; - } - msleep(10); - /* Read the manufacturer ID: ov = 0x7FA2 */ - if (stk_sensor_inb(dev, REG_MIDH, &idh) - || stk_sensor_inb(dev, REG_MIDL, &idl)) { - STK_ERROR("Strange error reading sensor ID\n"); - return -ENODEV; - } - if (idh != 0x7F || idl != 0xA2) { - STK_ERROR("Huh? you don't have a sensor from ovt\n"); - return -ENODEV; - } - if (stk_sensor_inb(dev, REG_PID, &idh) - || stk_sensor_inb(dev, REG_VER, &idl)) { - STK_ERROR("Could not read sensor model\n"); - return -ENODEV; - } - stk_sensor_write_regvals(dev, ov_initvals); - msleep(10); - STK_INFO("OmniVision sensor detected, id %02X%02X" - " at address %x\n", idh, idl, SENSOR_ADDRESS); - return 0; -} - -/* V4L2_PIX_FMT_UYVY */ -static struct regval ov_fmt_uyvy[] = { - {REG_TSLB, TSLB_YLAST|0x08 }, - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ - {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; - -/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */ -static struct regval ov_fmt_rgbr[] = { - { REG_RGB444, 0 }, /* No RGB444 please */ - {REG_TSLB, 0x00}, - { REG_COM1, 0x0 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA }, - { REG_COM15, COM15_RGB565|COM15_R00FF }, - { 0xff, 0xff }, -}; - -/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */ -static struct regval ov_fmt_rgbp[] = { - { REG_RGB444, 0 }, /* No RGB444 please */ - {REG_TSLB, TSLB_BYTEORD }, - { REG_COM1, 0x0 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ - { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ - { REG_COM13, COM13_GAMMA }, - { REG_COM15, COM15_RGB565|COM15_R00FF }, - { 0xff, 0xff }, -}; - -/* V4L2_PIX_FMT_SRGGB8 */ -static struct regval ov_fmt_bayer[] = { - /* This changes color order */ - {REG_TSLB, 0x40}, /* BGGR */ - /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */ - {REG_COM15, COM15_R00FF }, - {0xff, 0xff}, /* END MARKER */ -}; -/* - * Store a set of start/stop values into the camera. - */ -static int stk_sensor_set_hw(struct stk_camera *dev, - int hstart, int hstop, int vstart, int vstop) -{ - int ret; - unsigned char v; -/* - * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of - * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is - * a mystery "edge offset" value in the top two bits of href. - */ - ret = stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff); - ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff); - ret += stk_sensor_inb(dev, REG_HREF, &v); - v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); - msleep(10); - ret += stk_sensor_outb(dev, REG_HREF, v); -/* - * Vertical: similar arrangement (note: this is different from ov7670.c) - */ - ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff); - ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff); - ret += stk_sensor_inb(dev, REG_VREF, &v); - v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7); - msleep(10); - ret += stk_sensor_outb(dev, REG_VREF, v); - return ret; -} - - -int stk_sensor_configure(struct stk_camera *dev) -{ - int com7; - /* - * We setup the sensor to output dummy lines in low-res modes, - * so we don't get absurdly hight framerates. - */ - unsigned dummylines; - int flip; - struct regval *rv; - - switch (dev->vsettings.mode) { - case MODE_QCIF: com7 = COM7_FMT_QCIF; - dummylines = 604; - break; - case MODE_QVGA: com7 = COM7_FMT_QVGA; - dummylines = 267; - break; - case MODE_CIF: com7 = COM7_FMT_CIF; - dummylines = 412; - break; - case MODE_VGA: com7 = COM7_FMT_VGA; - dummylines = 11; - break; - case MODE_SXGA: com7 = COM7_FMT_SXGA; - dummylines = 0; - break; - default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode); - return -EFAULT; - } - switch (dev->vsettings.palette) { - case V4L2_PIX_FMT_UYVY: - com7 |= COM7_YUV; - rv = ov_fmt_uyvy; - break; - case V4L2_PIX_FMT_RGB565: - com7 |= COM7_RGB; - rv = ov_fmt_rgbp; - break; - case V4L2_PIX_FMT_RGB565X: - com7 |= COM7_RGB; - rv = ov_fmt_rgbr; - break; - case V4L2_PIX_FMT_SBGGR8: - com7 |= COM7_PBAYER; - rv = ov_fmt_bayer; - break; - default: STK_ERROR("Unsupported colorspace\n"); - return -EFAULT; - } - /*FIXME sometimes the sensor go to a bad state - stk_sensor_write_regvals(dev, ov_initvals); */ - stk_sensor_outb(dev, REG_COM7, com7); - msleep(50); - stk_sensor_write_regvals(dev, rv); - flip = (dev->vsettings.vflip?MVFP_FLIP:0) - | (dev->vsettings.hflip?MVFP_MIRROR:0); - stk_sensor_outb(dev, REG_MVFP, flip); - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8 - && !dev->vsettings.vflip) - stk_sensor_outb(dev, REG_TSLB, 0x08); - stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8); - stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff); - msleep(50); - switch (dev->vsettings.mode) { - case MODE_VGA: - if (stk_sensor_set_hw(dev, 302, 1582, 6, 486)) - STK_ERROR("stk_sensor_set_hw failed (VGA)\n"); - break; - case MODE_SXGA: - case MODE_CIF: - case MODE_QVGA: - case MODE_QCIF: - /*FIXME These settings seem ignored by the sensor - if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034)) - STK_ERROR("stk_sensor_set_hw failed (SXGA)\n"); - */ - break; - } - msleep(10); - return 0; -} - -int stk_sensor_set_brightness(struct stk_camera *dev, int br) -{ - if (br < 0 || br > 0xff) - return -EINVAL; - stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6)); - stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6)); - return 0; -} - diff --git a/trunk/drivers/media/video/stk-webcam.c b/trunk/drivers/media/video/stk-webcam.c deleted file mode 100644 index d37e5e2594b4..000000000000 --- a/trunk/drivers/media/video/stk-webcam.c +++ /dev/null @@ -1,1465 +0,0 @@ -/* - * stk-webcam.c : Driver for Syntek 1125 USB webcam controller - * - * Copyright (C) 2006 Nicolas VIVIEN - * Copyright 2007-2008 Jaime Velasco Juan - * - * Some parts are inspired from cafe_ccic.c - * Copyright 2006-2007 Jonathan Corbet - * - * 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 - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "stk-webcam.h" - - -static int hflip = 1; -module_param(hflip, bool, 0444); -MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1"); - -static int vflip = 1; -module_param(vflip, bool, 0444); -MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1"); - -static int debug; -module_param(debug, int, 0444); -MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0"); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jaime Velasco Juan and Nicolas VIVIEN"); -MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); - - - -/* Some cameras have audio interfaces, we aren't interested in those */ -static struct usb_device_id stkwebcam_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) }, - { } -}; -MODULE_DEVICE_TABLE(usb, stkwebcam_table); - -void stk_camera_cleanup(struct kref *kref) -{ - struct stk_camera *dev = to_stk_camera(kref); - - STK_INFO("Syntek USB2.0 Camera release resources" - " video device /dev/video%d\n", dev->vdev.minor); - video_unregister_device(&dev->vdev); - dev->vdev.priv = NULL; - - if (dev->sio_bufs != NULL || dev->isobufs != NULL) - STK_ERROR("We are leaking memory\n"); - usb_put_intf(dev->interface); - kfree(dev); -} - - -/* - * Basic stuff - */ -int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) -{ - struct usb_device *udev = dev->udev; - int ret; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x01, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - index, - NULL, - 0, - 500); - if (ret < 0) - return ret; - else - return 0; -} - -int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) -{ - struct usb_device *udev = dev->udev; - int ret; - - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x00, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, - index, - (u8 *) value, - sizeof(u8), - 500); - if (ret < 0) - return ret; - else - return 0; -} - -static int stk_start_stream(struct stk_camera *dev) -{ - int value; - int i, ret; - int value_116, value_117; - - if (!is_present(dev)) - return -ENODEV; - if (!is_memallocd(dev) || !is_initialised(dev)) { - STK_ERROR("FIXME: Buffers are not allocated\n"); - return -EFAULT; - } - ret = usb_set_interface(dev->udev, 0, 5); - - if (ret < 0) - STK_ERROR("usb_set_interface failed !\n"); - if (stk_sensor_wakeup(dev)) - STK_ERROR("error awaking the sensor\n"); - - stk_camera_read_reg(dev, 0x0116, &value_116); - stk_camera_read_reg(dev, 0x0117, &value_117); - - stk_camera_write_reg(dev, 0x0116, 0x0000); - stk_camera_write_reg(dev, 0x0117, 0x0000); - - stk_camera_read_reg(dev, 0x0100, &value); - stk_camera_write_reg(dev, 0x0100, value | 0x80); - - stk_camera_write_reg(dev, 0x0116, value_116); - stk_camera_write_reg(dev, 0x0117, value_117); - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].urb) { - ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL); - atomic_inc(&dev->urbs_used); - if (ret) - return ret; - } - } - set_streaming(dev); - return 0; -} - -static int stk_stop_stream(struct stk_camera *dev) -{ - int value; - int i; - if (is_present(dev)) { - stk_camera_read_reg(dev, 0x0100, &value); - stk_camera_write_reg(dev, 0x0100, value & ~0x80); - if (dev->isobufs != NULL) { - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].urb) - usb_kill_urb(dev->isobufs[i].urb); - } - } - unset_streaming(dev); - - if (usb_set_interface(dev->udev, 0, 0)) - STK_ERROR("usb_set_interface failed !\n"); - if (stk_sensor_sleep(dev)) - STK_ERROR("error suspending the sensor\n"); - } - return 0; -} - -/* - * This seems to be the shortest init sequence we - * must do in order to find the sensor - * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor - * is also reset. Maybe powers down it? - * Rest of values don't make a difference - */ - -static struct regval stk1125_initvals[] = { - /*TODO: What means this sequence? */ - {0x0000, 0x24}, - {0x0100, 0x21}, - {0x0002, 0x68}, - {0x0003, 0x80}, - {0x0005, 0x00}, - {0x0007, 0x03}, - {0x000d, 0x00}, - {0x000f, 0x02}, - {0x0300, 0x12}, - {0x0350, 0x41}, - {0x0351, 0x00}, - {0x0352, 0x00}, - {0x0353, 0x00}, - {0x0018, 0x10}, - {0x0019, 0x00}, - {0x001b, 0x0e}, - {0x001c, 0x46}, - {0x0300, 0x80}, - {0x001a, 0x04}, - {0x0110, 0x00}, - {0x0111, 0x00}, - {0x0112, 0x00}, - {0x0113, 0x00}, - - {0xffff, 0xff}, -}; - - -static int stk_initialise(struct stk_camera *dev) -{ - struct regval *rv; - int ret; - if (!is_present(dev)) - return -ENODEV; - if (is_initialised(dev)) - return 0; - rv = stk1125_initvals; - while (rv->reg != 0xffff) { - ret = stk_camera_write_reg(dev, rv->reg, rv->val); - if (ret) - return ret; - rv++; - } - if (stk_sensor_init(dev) == 0) { - set_initialised(dev); - return 0; - } else - return -1; -} - -/* sysfs functions */ -/*FIXME cleanup this */ - -static ssize_t show_brightness(struct device *class, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = to_video_device(class); - struct stk_camera *dev = vdev_to_camera(vdev); - - return sprintf(buf, "%X\n", dev->vsettings.brightness); -} - -static ssize_t store_brightness(struct device *class, - struct device_attribute *attr, const char *buf, size_t count) -{ - char *endp; - unsigned long value; - int ret; - - struct video_device *vdev = to_video_device(class); - struct stk_camera *dev = vdev_to_camera(vdev); - - value = simple_strtoul(buf, &endp, 16); - - dev->vsettings.brightness = (int) value; - - ret = stk_sensor_set_brightness(dev, value >> 8); - if (ret) - return ret; - else - return count; -} - -static ssize_t show_hflip(struct device *class, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = to_video_device(class); - struct stk_camera *dev = vdev_to_camera(vdev); - - return sprintf(buf, "%d\n", dev->vsettings.hflip); -} - -static ssize_t store_hflip(struct device *class, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct video_device *vdev = to_video_device(class); - struct stk_camera *dev = vdev_to_camera(vdev); - - if (strncmp(buf, "1", 1) == 0) - dev->vsettings.hflip = 1; - else if (strncmp(buf, "0", 1) == 0) - dev->vsettings.hflip = 0; - else - return -EINVAL; - - return strlen(buf); -} - -static ssize_t show_vflip(struct device *class, - struct device_attribute *attr, char *buf) -{ - struct video_device *vdev = to_video_device(class); - struct stk_camera *dev = vdev_to_camera(vdev); - - return sprintf(buf, "%d\n", dev->vsettings.vflip); -} - -static ssize_t store_vflip(struct device *class, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct video_device *vdev = to_video_device(class); - struct stk_camera *dev = vdev_to_camera(vdev); - - if (strncmp(buf, "1", 1) == 0) - dev->vsettings.vflip = 1; - else if (strncmp(buf, "0", 1) == 0) - dev->vsettings.vflip = 0; - else - return -EINVAL; - - return strlen(buf); -} - -static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO, - show_brightness, store_brightness); -static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip); -static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip); - -static int stk_create_sysfs_files(struct video_device *vdev) -{ - int ret; - - ret = video_device_create_file(vdev, &dev_attr_brightness); - ret += video_device_create_file(vdev, &dev_attr_hflip); - ret += video_device_create_file(vdev, &dev_attr_vflip); - return ret; -} - -static void stk_remove_sysfs_files(struct video_device *vdev) -{ - video_device_remove_file(vdev, &dev_attr_brightness); - video_device_remove_file(vdev, &dev_attr_hflip); - video_device_remove_file(vdev, &dev_attr_vflip); -} - - -/* *********************************************** */ -/* - * This function is called as an URB transfert is complete (Isochronous pipe). - * So, the traitement is done in interrupt time, so it has be fast, not crash, - * and not stall. Neat. - */ -static void stk_isoc_handler(struct urb *urb) -{ - int i; - int ret; - int framelen; - unsigned long flags; - - unsigned char *fill = NULL; - unsigned char *iso_buf = NULL; - - struct stk_camera *dev; - struct stk_sio_buffer *fb; - - dev = (struct stk_camera *) urb->context; - - if (dev == NULL) { - STK_ERROR("isoc_handler called with NULL device !\n"); - return; - } - - if (urb->status == -ENOENT || urb->status == -ECONNRESET - || urb->status == -ESHUTDOWN) { - atomic_dec(&dev->urbs_used); - return; - } - - spin_lock_irqsave(&dev->spinlock, flags); - - if (urb->status != -EINPROGRESS && urb->status != 0) { - STK_ERROR("isoc_handler: urb->status == %d\n", urb->status); - goto resubmit; - } - - if (list_empty(&dev->sio_avail)) { - /*FIXME Stop streaming after a while */ - (void) (printk_ratelimit() && - STK_ERROR("isoc_handler without available buffer!\n")); - goto resubmit; - } - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fill = fb->buffer + fb->v4lbuf.bytesused; - - for (i = 0; i < urb->number_of_packets; i++) { - if (urb->iso_frame_desc[i].status != 0) { - if (urb->iso_frame_desc[i].status != -EXDEV) - STK_ERROR("Frame %d has error %d\n", i, - urb->iso_frame_desc[i].status); - continue; - } - framelen = urb->iso_frame_desc[i].actual_length; - iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - if (framelen <= 4) - continue; /* no data */ - - /* - * we found something informational from there - * the isoc frames have to type of headers - * type1: 00 xx 00 00 or 20 xx 00 00 - * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00 - * xx is a sequencer which has never been seen over 0x3f - * imho data written down looks like bayer, i see similarities - * after every 640 bytes - */ - if (*iso_buf & 0x80) { - framelen -= 8; - iso_buf += 8; - /* This marks a new frame */ - if (fb->v4lbuf.bytesused != 0 - && fb->v4lbuf.bytesused != dev->frame_size) { - (void) (printk_ratelimit() && - STK_ERROR("frame %d, " - "bytesused=%d, skipping\n", - i, fb->v4lbuf.bytesused)); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } else if (fb->v4lbuf.bytesused == dev->frame_size) { - list_move_tail(dev->sio_avail.next, - &dev->sio_full); - wake_up(&dev->wait_frame); - if (list_empty(&dev->sio_avail)) { - (void) (printk_ratelimit() && - STK_ERROR("No buffer available\n")); - goto resubmit; - } - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; - } - } else { - framelen -= 4; - iso_buf += 4; - } - - /* Our buffer is full !!! */ - if (framelen + fb->v4lbuf.bytesused > dev->frame_size) { - (void) (printk_ratelimit() && - STK_ERROR("Frame buffer overflow, lost sync\n")); - /*FIXME Do something here? */ - continue; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - memcpy(fill, iso_buf, framelen); - spin_lock_irqsave(&dev->spinlock, flags); - fill += framelen; - - /* New size of our buffer */ - fb->v4lbuf.bytesused += framelen; - } - -resubmit: - spin_unlock_irqrestore(&dev->spinlock, flags); - urb->dev = dev->udev; - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret != 0) { - STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n", - ret); - } -} - -/* -------------------------------------------- */ - -static int stk_prepare_iso(struct stk_camera *dev) -{ - void *kbuf; - int i, j; - struct urb *urb; - struct usb_device *udev; - - if (dev == NULL) - return -ENXIO; - udev = dev->udev; - - if (dev->isobufs) - STK_ERROR("isobufs already allocated. Bad\n"); - else - dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs), - GFP_KERNEL); - if (dev->isobufs == NULL) { - STK_ERROR("Unable to allocate iso buffers\n"); - return -ENOMEM; - } - for (i = 0; i < MAX_ISO_BUFS; i++) { - if (dev->isobufs[i].data == NULL) { - kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); - if (kbuf == NULL) { - STK_ERROR("Failed to allocate iso buffer %d\n", - i); - goto isobufs_out; - } - dev->isobufs[i].data = kbuf; - } else - STK_ERROR("isobuf data already allocated\n"); - if (dev->isobufs[i].urb == NULL) { - urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); - if (urb == NULL) { - STK_ERROR("Failed to allocate URB %d\n", i); - goto isobufs_out; - } - dev->isobufs[i].urb = urb; - } else { - STK_ERROR("Killing URB\n"); - usb_kill_urb(dev->isobufs[i].urb); - urb = dev->isobufs[i].urb; - } - urb->interval = 1; - urb->dev = udev; - urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->isobufs[i].data; - urb->transfer_buffer_length = ISO_BUFFER_SIZE; - urb->complete = stk_isoc_handler; - urb->context = dev; - urb->start_frame = 0; - urb->number_of_packets = ISO_FRAMES_PER_DESC; - - for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; - urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; - } - } - set_memallocd(dev); - return 0; - -isobufs_out: - for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++) - kfree(dev->isobufs[i].data); - for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++) - usb_free_urb(dev->isobufs[i].urb); - kfree(dev->isobufs); - dev->isobufs = NULL; - return -ENOMEM; -} - -static void stk_clean_iso(struct stk_camera *dev) -{ - int i; - - if (dev == NULL || dev->isobufs == NULL) - return; - - for (i = 0; i < MAX_ISO_BUFS; i++) { - struct urb *urb; - - urb = dev->isobufs[i].urb; - if (urb) { - if (atomic_read(&dev->urbs_used)) - usb_kill_urb(urb); - usb_free_urb(urb); - } - kfree(dev->isobufs[i].data); - } - kfree(dev->isobufs); - dev->isobufs = NULL; - unset_memallocd(dev); -} - -static int stk_setup_siobuf(struct stk_camera *dev, int index) -{ - struct stk_sio_buffer *buf = dev->sio_bufs + index; - INIT_LIST_HEAD(&buf->list); - buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size); - buf->buffer = vmalloc_user(buf->v4lbuf.length); - if (buf->buffer == NULL) - return -ENOMEM; - buf->mapcount = 0; - buf->dev = dev; - buf->v4lbuf.index = index; - buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->v4lbuf.field = V4L2_FIELD_NONE; - buf->v4lbuf.memory = V4L2_MEMORY_MMAP; - buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; - return 0; -} - -static int stk_free_sio_buffers(struct stk_camera *dev) -{ - int i; - int nbufs; - unsigned long flags; - if (dev->n_sbufs == 0 || dev->sio_bufs == NULL) - return 0; - /* - * If any buffers are mapped, we cannot free them at all. - */ - for (i = 0; i < dev->n_sbufs; i++) { - if (dev->sio_bufs[i].mapcount > 0) - return -EBUSY; - } - /* - * OK, let's do it. - */ - spin_lock_irqsave(&dev->spinlock, flags); - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - nbufs = dev->n_sbufs; - dev->n_sbufs = 0; - spin_unlock_irqrestore(&dev->spinlock, flags); - for (i = 0; i < nbufs; i++) { - if (dev->sio_bufs[i].buffer != NULL) - vfree(dev->sio_bufs[i].buffer); - } - kfree(dev->sio_bufs); - dev->sio_bufs = NULL; - return 0; -} - -static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs) -{ - int i; - if (dev->sio_bufs != NULL) - STK_ERROR("sio_bufs already allocated\n"); - else { - dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer), - GFP_KERNEL); - if (dev->sio_bufs == NULL) - return -ENOMEM; - for (i = 0; i < n_sbufs; i++) { - if (stk_setup_siobuf(dev, i)) - return (dev->n_sbufs > 1)? 0 : -ENOMEM; - dev->n_sbufs = i+1; - } - } - return 0; -} - -static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs) -{ - int err; - err = stk_prepare_iso(dev); - if (err) { - stk_clean_iso(dev); - return err; - } - err = stk_prepare_sio_buffers(dev, n_sbufs); - if (err) { - stk_free_sio_buffers(dev); - return err; - } - return 0; -} - -static void stk_free_buffers(struct stk_camera *dev) -{ - stk_clean_iso(dev); - stk_free_sio_buffers(dev); -} -/* -------------------------------------------- */ - -/* v4l file operations */ - -static int v4l_stk_open(struct inode *inode, struct file *fp) -{ - struct stk_camera *dev; - struct video_device *vdev; - - vdev = video_devdata(fp); - dev = vdev_to_camera(vdev); - - if (dev == NULL || !is_present(dev)) - return -ENXIO; - fp->private_data = vdev; - kref_get(&dev->kref); - - return 0; -} - -static int v4l_stk_release(struct inode *inode, struct file *fp) -{ - struct stk_camera *dev; - struct video_device *vdev; - - vdev = video_devdata(fp); - if (vdev == NULL) { - STK_ERROR("v4l_release called w/o video devdata\n"); - return -EFAULT; - } - dev = vdev_to_camera(vdev); - if (dev == NULL) { - STK_ERROR("v4l_release called on removed device\n"); - return -ENODEV; - } - - if (dev->owner != fp) { - kref_put(&dev->kref, stk_camera_cleanup); - return 0; - } - - stk_stop_stream(dev); - - stk_free_buffers(dev); - - dev->owner = NULL; - - kref_put(&dev->kref, stk_camera_cleanup); - - return 0; -} - -static ssize_t v4l_stk_read(struct file *fp, char __user *buf, - size_t count, loff_t *f_pos) -{ - int i; - int ret; - unsigned long flags; - struct stk_camera *dev; - struct video_device *vdev; - struct stk_sio_buffer *sbuf; - - vdev = video_devdata(fp); - if (vdev == NULL) - return -EFAULT; - dev = vdev_to_camera(vdev); - - if (dev == NULL) - return -EIO; - - if (!is_present(dev)) - return -EIO; - if (dev->owner && dev->owner != fp) - return -EBUSY; - dev->owner = fp; - if (!is_streaming(dev)) { - if (stk_initialise(dev) - || stk_allocate_buffers(dev, 3) - || stk_start_stream(dev)) - return -ENOMEM; - spin_lock_irqsave(&dev->spinlock, flags); - for (i = 0; i < dev->n_sbufs; i++) { - list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail); - dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - } - if (*f_pos == 0) { - if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) - return -EWOULDBLOCK; - ret = wait_event_interruptible(dev->wait_frame, - !list_empty(&dev->sio_full) || !is_present(dev)); - if (ret) - return ret; - if (!is_present(dev)) - return -EIO; - } - if (count + *f_pos > dev->frame_size) - count = dev->frame_size - *f_pos; - spin_lock_irqsave(&dev->spinlock, flags); - if (list_empty(&dev->sio_full)) { - spin_unlock_irqrestore(&dev->spinlock, flags); - STK_ERROR("BUG: No siobufs ready\n"); - return 0; - } - sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); - spin_unlock_irqrestore(&dev->spinlock, flags); - - if (copy_to_user(buf, sbuf->buffer + *f_pos, count)) - return -EFAULT; - - *f_pos += count; - - if (*f_pos >= dev->frame_size) { - *f_pos = 0; - spin_lock_irqsave(&dev->spinlock, flags); - list_move_tail(&sbuf->list, &dev->sio_avail); - spin_unlock_irqrestore(&dev->spinlock, flags); - } - return count; -} - -static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) -{ - struct stk_camera *dev; - struct video_device *vdev; - - vdev = video_devdata(fp); - - if (vdev == NULL) - return -EFAULT; - - dev = vdev_to_camera(vdev); - if (dev == NULL) - return -ENODEV; - - poll_wait(fp, &dev->wait_frame, wait); - - if (!is_present(dev)) - return POLLERR; - - if (!list_empty(&dev->sio_full)) - return (POLLIN | POLLRDNORM); - - return 0; -} - - -static void stk_v4l_vm_open(struct vm_area_struct *vma) -{ - struct stk_sio_buffer *sbuf = vma->vm_private_data; - sbuf->mapcount++; -} -static void stk_v4l_vm_close(struct vm_area_struct *vma) -{ - struct stk_sio_buffer *sbuf = vma->vm_private_data; - sbuf->mapcount--; - if (sbuf->mapcount == 0) - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; -} -static struct vm_operations_struct stk_v4l_vm_ops = { - .open = stk_v4l_vm_open, - .close = stk_v4l_vm_close -}; - -static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) -{ - unsigned int i; - int ret; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct stk_camera *dev; - struct video_device *vdev; - struct stk_sio_buffer *sbuf = NULL; - - if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) - return -EINVAL; - - vdev = video_devdata(fp); - dev = vdev_to_camera(vdev); - - for (i = 0; i < dev->n_sbufs; i++) { - if (dev->sio_bufs[i].v4lbuf.m.offset == offset) { - sbuf = dev->sio_bufs + i; - break; - } - } - if (sbuf == NULL) - return -EINVAL; - ret = remap_vmalloc_range(vma, sbuf->buffer, 0); - if (ret) - return ret; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_private_data = sbuf; - vma->vm_ops = &stk_v4l_vm_ops; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; - stk_v4l_vm_open(vma); - return 0; -} - -/* v4l ioctl handlers */ - -static int stk_vidioc_querycap(struct file *filp, - void *priv, struct v4l2_capability *cap) -{ - strcpy(cap->driver, "stk"); - strcpy(cap->card, "stk"); - cap->version = DRIVER_VERSION_NUM; - - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - return 0; -} - -static int stk_vidioc_enum_input(struct file *filp, - void *priv, struct v4l2_input *input) -{ - if (input->index != 0) - return -EINVAL; - - strcpy(input->name, "Syntek USB Camera"); - input->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - - -static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - else - return 0; -} - -/* from vivi.c */ -static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) -{ - return 0; -} - -/* List of all V4Lv2 controls supported by the driver */ -static struct v4l2_queryctrl stk_controls[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xffff, - .step = 0x0100, - .default_value = 0x6000, - }, - /*TODO: get more controls to work */ -}; - -static int stk_vidioc_queryctrl(struct file *filp, - void *priv, struct v4l2_queryctrl *c) -{ - int i; - int nbr; - nbr = ARRAY_SIZE(stk_controls); - - for (i = 0; i < nbr; i++) { - if (stk_controls[i].id == c->id) { - memcpy(c, &stk_controls[i], - sizeof(struct v4l2_queryctrl)); - return 0; - } - } - return -EINVAL; -} - -static int stk_vidioc_g_ctrl(struct file *filp, - void *priv, struct v4l2_control *c) -{ - struct stk_camera *dev = priv; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = dev->vsettings.brightness; - break; - default: - return -EINVAL; - } - return 0; -} - -static int stk_vidioc_s_ctrl(struct file *filp, - void *priv, struct v4l2_control *c) -{ - struct stk_camera *dev = priv; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - dev->vsettings.brightness = c->value; - return stk_sensor_set_brightness(dev, c->value >> 8); - default: - return -EINVAL; - } - return 0; -} - - -static int stk_vidioc_enum_fmt_cap(struct file *filp, - void *priv, struct v4l2_fmtdesc *fmtd) -{ - fmtd->flags = 0; - - switch (fmtd->index) { - case 0: - fmtd->pixelformat = V4L2_PIX_FMT_RGB565; - strcpy(fmtd->description, "r5g6b5"); - break; - case 1: - fmtd->pixelformat = V4L2_PIX_FMT_RGB565X; - strcpy(fmtd->description, "r5g6b5BE"); - break; - case 2: - fmtd->pixelformat = V4L2_PIX_FMT_UYVY; - strcpy(fmtd->description, "yuv4:2:2"); - break; - case 3: - fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; - strcpy(fmtd->description, "Raw bayer"); - break; - default: - return -EINVAL; - } - return 0; -} - -static struct stk_size { - unsigned w; - unsigned h; - enum stk_mode m; -} stk_sizes[] = { - { .w = 1280, .h = 1024, .m = MODE_SXGA, }, - { .w = 640, .h = 480, .m = MODE_VGA, }, - { .w = 352, .h = 288, .m = MODE_CIF, }, - { .w = 320, .h = 240, .m = MODE_QVGA, }, - { .w = 176, .h = 144, .m = MODE_QCIF, }, -}; - -static int stk_vidioc_g_fmt_cap(struct file *filp, - void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format *pix_format = &f->fmt.pix; - struct stk_camera *dev = priv; - int i; - - for (i = 0; i < ARRAY_SIZE(stk_sizes) - && stk_sizes[i].m != dev->vsettings.mode; - i++); - if (i == ARRAY_SIZE(stk_sizes)) { - STK_ERROR("ERROR: mode invalid\n"); - return -EINVAL; - } - pix_format->width = stk_sizes[i].w; - pix_format->height = stk_sizes[i].h; - pix_format->field = V4L2_FIELD_NONE; - pix_format->colorspace = V4L2_COLORSPACE_SRGB; - pix_format->priv = 0; - pix_format->pixelformat = dev->vsettings.palette; - if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) - pix_format->bytesperline = pix_format->width; - else - pix_format->bytesperline = 2 * pix_format->width; - pix_format->sizeimage = pix_format->bytesperline - * pix_format->height; - return 0; -} - -static int stk_vidioc_try_fmt_cap(struct file *filp, - void *priv, struct v4l2_format *fmtd) -{ - int i; - switch (fmtd->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB565X: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_SBGGR8: - break; - default: - return -EINVAL; - } - for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) { - if (fmtd->fmt.pix.width > stk_sizes[i].w) - break; - } - if (i == ARRAY_SIZE(stk_sizes) - || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w) - < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) { - fmtd->fmt.pix.height = stk_sizes[i-1].h; - fmtd->fmt.pix.width = stk_sizes[i-1].w; - fmtd->fmt.pix.priv = i - 1; - } else { - fmtd->fmt.pix.height = stk_sizes[i].h; - fmtd->fmt.pix.width = stk_sizes[i].w; - fmtd->fmt.pix.priv = i; - } - - fmtd->fmt.pix.field = V4L2_FIELD_NONE; - fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) - fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width; - else - fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; - fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline - * fmtd->fmt.pix.height; - return 0; -} - -static int stk_vidioc_s_fmt_cap(struct file *filp, - void *priv, struct v4l2_format *fmtd) -{ - int ret; - struct stk_camera *dev = priv; - - if (dev == NULL) - return -ENODEV; - if (!is_present(dev)) - return -ENODEV; - if (is_streaming(dev)) - return -EBUSY; - if (dev->owner && dev->owner != filp) - return -EBUSY; - dev->owner = filp; - ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd); - if (ret) - return ret; - - dev->vsettings.palette = fmtd->fmt.pix.pixelformat; - stk_free_buffers(dev); - dev->frame_size = fmtd->fmt.pix.sizeimage; - dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m; - - stk_initialise(dev); - /* This registers controls some timings, not sure of what. */ - stk_camera_write_reg(dev, 0x001b, 0x0e); - if (dev->vsettings.mode == MODE_SXGA) - stk_camera_write_reg(dev, 0x001c, 0x0e); - else - stk_camera_write_reg(dev, 0x001c, 0x46); - /* - * Registers 0x0115 0x0114 are the size of each line (bytes), - * regs 0x0117 0x0116 are the heigth of the image. - */ - stk_camera_write_reg(dev, 0x0115, - (fmtd->fmt.pix.bytesperline >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0114, - fmtd->fmt.pix.bytesperline & 0xff); - stk_camera_write_reg(dev, 0x0117, - (fmtd->fmt.pix.height >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0116, - fmtd->fmt.pix.height & 0xff); - return stk_sensor_configure(dev); -} - -static int stk_vidioc_reqbufs(struct file *filp, - void *priv, struct v4l2_requestbuffers *rb) -{ - struct stk_camera *dev = priv; - - if (dev == NULL) - return -ENODEV; - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - if (is_streaming(dev) - || (dev->owner && dev->owner != filp)) - return -EBUSY; - dev->owner = filp; - - /*FIXME If they ask for zero, we must stop streaming and free */ - if (rb->count < 3) - rb->count = 3; - /* Arbitrary limit */ - else if (rb->count > 5) - rb->count = 5; - - stk_allocate_buffers(dev, rb->count); - rb->count = dev->n_sbufs; - return 0; -} - -static int stk_vidioc_querybuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - int index; - struct stk_camera *dev = priv; - struct stk_sio_buffer *sbuf; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - index = buf->index; - - if (index < 0 || index >= dev->n_sbufs) - return -EINVAL; - sbuf = dev->sio_bufs + buf->index; - *buf = sbuf->v4lbuf; - return 0; -} - -static int stk_vidioc_qbuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = priv; - struct stk_sio_buffer *sbuf; - unsigned long flags; - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (buf->index < 0 || buf->index >= dev->n_sbufs) - return -EINVAL; - sbuf = dev->sio_bufs + buf->index; - if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) - return 0; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; - spin_lock_irqsave(&dev->spinlock, flags); - list_add_tail(&sbuf->list, &dev->sio_avail); - *buf = sbuf->v4lbuf; - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; -} - -static int stk_vidioc_dqbuf(struct file *filp, - void *priv, struct v4l2_buffer *buf) -{ - struct stk_camera *dev = priv; - struct stk_sio_buffer *sbuf; - unsigned long flags; - int ret; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || !is_streaming(dev)) - return -EINVAL; - - if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) - return -EWOULDBLOCK; - ret = wait_event_interruptible(dev->wait_frame, - !list_empty(&dev->sio_full) || !is_present(dev)); - if (ret) - return ret; - if (!is_present(dev)) - return -EIO; - - spin_lock_irqsave(&dev->spinlock, flags); - sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); - list_del_init(&sbuf->list); - spin_unlock_irqrestore(&dev->spinlock, flags); - sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; - sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; - sbuf->v4lbuf.sequence = ++dev->sequence; - do_gettimeofday(&sbuf->v4lbuf.timestamp); - - *buf = sbuf->v4lbuf; - return 0; -} - -static int stk_vidioc_streamon(struct file *filp, - void *priv, enum v4l2_buf_type type) -{ - struct stk_camera *dev = priv; - if (is_streaming(dev)) - return 0; - if (dev->sio_bufs == NULL) - return -EINVAL; - dev->sequence = 0; - return stk_start_stream(dev); -} - -static int stk_vidioc_streamoff(struct file *filp, - void *priv, enum v4l2_buf_type type) -{ - struct stk_camera *dev = priv; - unsigned long flags; - int i; - stk_stop_stream(dev); - spin_lock_irqsave(&dev->spinlock, flags); - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - for (i = 0; i < dev->n_sbufs; i++) { - INIT_LIST_HEAD(&dev->sio_bufs[i].list); - dev->sio_bufs[i].v4lbuf.flags = 0; - } - spin_unlock_irqrestore(&dev->spinlock, flags); - return 0; -} - - -static int stk_vidioc_g_parm(struct file *filp, - void *priv, struct v4l2_streamparm *sp) -{ - if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - sp->parm.capture.capability = 0; - sp->parm.capture.capturemode = 0; - /*FIXME This is not correct */ - sp->parm.capture.timeperframe.numerator = 1; - sp->parm.capture.timeperframe.denominator = 30; - sp->parm.capture.readbuffers = 2; - sp->parm.capture.extendedmode = 0; - return 0; -} - -static struct file_operations v4l_stk_fops = { - .owner = THIS_MODULE, - .open = v4l_stk_open, - .release = v4l_stk_release, - .read = v4l_stk_read, - .poll = v4l_stk_poll, - .mmap = v4l_stk_mmap, - .ioctl = video_ioctl2, - .llseek = no_llseek -}; - -static void stk_v4l_dev_release(struct video_device *vd) -{ -} - -static struct video_device stk_v4l_data = { - .name = "stkwebcam", - .type = VFL_TYPE_GRABBER, - .type2 = VID_TYPE_CAPTURE, - .minor = -1, - .tvnorms = V4L2_STD_UNKNOWN, - .current_norm = V4L2_STD_UNKNOWN, - .fops = &v4l_stk_fops, - .release = stk_v4l_dev_release, - - .vidioc_querycap = stk_vidioc_querycap, - .vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap, - .vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap, - .vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap, - .vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap, - .vidioc_enum_input = stk_vidioc_enum_input, - .vidioc_s_input = stk_vidioc_s_input, - .vidioc_g_input = stk_vidioc_g_input, - .vidioc_s_std = stk_vidioc_s_std, - .vidioc_reqbufs = stk_vidioc_reqbufs, - .vidioc_querybuf = stk_vidioc_querybuf, - .vidioc_qbuf = stk_vidioc_qbuf, - .vidioc_dqbuf = stk_vidioc_dqbuf, - .vidioc_streamon = stk_vidioc_streamon, - .vidioc_streamoff = stk_vidioc_streamoff, - .vidioc_queryctrl = stk_vidioc_queryctrl, - .vidioc_g_ctrl = stk_vidioc_g_ctrl, - .vidioc_s_ctrl = stk_vidioc_s_ctrl, - .vidioc_g_parm = stk_vidioc_g_parm, -}; - - -static int stk_register_video_device(struct stk_camera *dev) -{ - int err; - - dev->vdev = stk_v4l_data; - dev->vdev.debug = debug; - dev->vdev.dev = &dev->interface->dev; - dev->vdev.priv = dev; - err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); - if (err) - STK_ERROR("v4l registration failed\n"); - else - STK_INFO("Syntek USB2.0 Camera is now controlling video device" - " /dev/video%d\n", dev->vdev.minor); - return err; -} - - -/* USB Stuff */ - -static int stk_camera_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - int i; - int err; - - struct stk_camera *dev = NULL; - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - - dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL); - if (dev == NULL) { - STK_ERROR("Out of memory !\n"); - return -ENOMEM; - } - - kref_init(&dev->kref); - spin_lock_init(&dev->spinlock); - init_waitqueue_head(&dev->wait_frame); - - dev->udev = udev; - dev->interface = interface; - usb_get_intf(interface); - - dev->vsettings.vflip = vflip; - dev->vsettings.hflip = hflip; - dev->n_sbufs = 0; - set_present(dev); - - /* Set up the endpoint information - * use only the first isoc-in endpoint - * for the current alternate setting */ - iface_desc = interface->cur_altsetting; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!dev->isoc_ep - && ((endpoint->bEndpointAddress - & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) - && ((endpoint->bmAttributes - & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) { - /* we found an isoc in endpoint */ - dev->isoc_ep = (endpoint->bEndpointAddress & 0xF); - break; - } - } - if (!dev->isoc_ep) { - STK_ERROR("Could not find isoc-in endpoint"); - kref_put(&dev->kref, stk_camera_cleanup); - return -ENODEV; - } - dev->vsettings.brightness = 0x7fff; - dev->vsettings.palette = V4L2_PIX_FMT_RGB565; - dev->vsettings.mode = MODE_VGA; - dev->frame_size = 640*480*2; - - INIT_LIST_HEAD(&dev->sio_avail); - INIT_LIST_HEAD(&dev->sio_full); - - usb_set_intfdata(interface, dev); - - err = stk_register_video_device(dev); - if (err) { - kref_put(&dev->kref, stk_camera_cleanup); - return err; - } - - stk_create_sysfs_files(&dev->vdev); - - return 0; -} - -static void stk_camera_disconnect(struct usb_interface *interface) -{ - struct stk_camera *dev = usb_get_intfdata(interface); - - usb_set_intfdata(interface, NULL); - unset_present(dev); - - wake_up_interruptible(&dev->wait_frame); - stk_remove_sysfs_files(&dev->vdev); - - kref_put(&dev->kref, stk_camera_cleanup); -} - -static struct usb_driver stk_camera_driver = { - .name = "stkwebcam", - .probe = stk_camera_probe, - .disconnect = stk_camera_disconnect, - .id_table = stkwebcam_table, -}; - - -static int __init stk_camera_init(void) -{ - int result; - - result = usb_register(&stk_camera_driver); - if (result) - STK_ERROR("usb_register failed ! Error number %d\n", result); - - - return result; -} - -static void __exit stk_camera_exit(void) -{ - usb_deregister(&stk_camera_driver); -} - -module_init(stk_camera_init); -module_exit(stk_camera_exit); - - diff --git a/trunk/drivers/media/video/stk-webcam.h b/trunk/drivers/media/video/stk-webcam.h deleted file mode 100644 index 7e989d1ac1e0..000000000000 --- a/trunk/drivers/media/video/stk-webcam.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * stk-webcam.h : Driver for Syntek 1125 USB webcam controller - * - * Copyright (C) 2006 Nicolas VIVIEN - * Copyright 2007-2008 Jaime Velasco Juan - * - * 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 - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef STKWEBCAM_H -#define STKWEBCAM_H - -#include -#include - -#define DRIVER_VERSION "v0.0.1" -#define DRIVER_VERSION_NUM 0x000001 - -#define MAX_ISO_BUFS 3 -#define ISO_FRAMES_PER_DESC 16 -#define ISO_MAX_FRAME_SIZE 3 * 1024 -#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) - - -#define PREFIX "stkwebcam: " -#define STK_INFO(str, args...) printk(KERN_INFO PREFIX str, ##args) -#define STK_ERROR(str, args...) printk(KERN_ERR PREFIX str, ##args) -#define STK_WARNING(str, args...) printk(KERN_WARNING PREFIX str, ##args) - -struct stk_iso_buf { - void *data; - int length; - int read; - struct urb *urb; -}; - -/* Streaming IO buffers */ -struct stk_sio_buffer { - struct v4l2_buffer v4lbuf; - char *buffer; - int mapcount; - struct stk_camera *dev; - struct list_head list; -}; - -enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF}; - -struct stk_video { - enum stk_mode mode; - int brightness; - __u32 palette; - int hflip; - int vflip; -}; - -enum stk_status { - S_PRESENT = 1, - S_INITIALISED = 2, - S_MEMALLOCD = 4, - S_STREAMING = 8, -}; -#define is_present(dev) ((dev)->status & S_PRESENT) -#define is_initialised(dev) ((dev)->status & S_INITIALISED) -#define is_streaming(dev) ((dev)->status & S_STREAMING) -#define is_memallocd(dev) ((dev)->status & S_MEMALLOCD) -#define set_present(dev) ((dev)->status = S_PRESENT) -#define unset_present(dev) ((dev)->status &= \ - ~(S_PRESENT|S_INITIALISED|S_STREAMING)) -#define set_initialised(dev) ((dev)->status |= S_INITIALISED) -#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD) -#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD) -#define set_streaming(dev) ((dev)->status |= S_STREAMING) -#define unset_streaming(dev) ((dev)->status &= ~S_STREAMING) - -struct regval { - unsigned reg; - unsigned val; -}; - -struct stk_camera { - struct video_device vdev; - struct usb_device *udev; - struct usb_interface *interface; - int webcam_model; - struct file *owner; - - u8 isoc_ep; - - struct kref kref; - /* Not sure if this is right */ - atomic_t urbs_used; - - struct stk_video vsettings; - - enum stk_status status; - - spinlock_t spinlock; - wait_queue_head_t wait_frame; - - struct stk_iso_buf *isobufs; - - int frame_size; - /* Streaming buffers */ - unsigned int n_sbufs; - struct stk_sio_buffer *sio_bufs; - struct list_head sio_avail; - struct list_head sio_full; - unsigned sequence; -}; - -#define to_stk_camera(d) container_of(d, struct stk_camera, kref) -#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) - -void stk_camera_delete(struct kref *); -int stk_camera_write_reg(struct stk_camera *, u16, u8); -int stk_camera_read_reg(struct stk_camera *, u16, int *); - -int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val); -int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val); -int stk_sensor_init(struct stk_camera *); -int stk_sensor_configure(struct stk_camera *); -int stk_sensor_sleep(struct stk_camera *dev); -int stk_sensor_wakeup(struct stk_camera *dev); -int stk_sensor_set_brightness(struct stk_camera *dev, int br); - -#endif diff --git a/trunk/drivers/media/video/tda7432.c b/trunk/drivers/media/video/tda7432.c index b4d10f7a4e57..43225802a551 100644 --- a/trunk/drivers/media/video/tda7432.c +++ b/trunk/drivers/media/video/tda7432.c @@ -8,7 +8,6 @@ * Muting and tone control by Jonathan Isom * * Copyright (c) 2000 Eric Sandeen - * Copyright (c) 2006 Mauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -277,7 +276,7 @@ static void do_tda7432_init(struct i2c_client *client) t->volume = 0x3b ; /* -27dB Volume */ if (loudness) /* Turn loudness on? */ t->volume |= TDA7432_LD_ON; - t->muted = 1; + t->muted = VIDEO_AUDIO_MUTE; t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ @@ -333,160 +332,151 @@ static int tda7432_detach(struct i2c_client *client) return 0; } -static int tda7432_get_ctrl(struct i2c_client *client, - struct v4l2_control *ctrl) +static int tda7432_command(struct i2c_client *client, + unsigned int cmd, void *arg) { struct tda7432 *t = i2c_get_clientdata(client); + v4l_dbg(2, debug,client,"In tda7432_command\n"); + if (debug>1) + v4l_i2c_print_ioctl(client,cmd); - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value=t->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + + /* Query card - scale from TDA7432 settings to V4L settings */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE | + VIDEO_AUDIO_MUTABLE; + if (t->muted) + va->flags |= VIDEO_AUDIO_MUTE; + va->mode |= VIDEO_SOUND_STEREO; + /* Master volume control + * V4L volume is min 0, max 65535 + * TDA7432 Volume: + * Min (-79dB) is 0x6f + * Max (+20dB) is 0x07 (630) + * Max (0dB) is 0x20 (829) + * (Mask out bit 7 of vol - it's for the loudness setting) + */ if (!maxvol){ /* max +20db */ - ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; + va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; } else { /* max 0db */ - ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; + va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829; } - return 0; - case V4L2_CID_AUDIO_BALANCE: - { + + /* Balance depends on L,R attenuation + * V4L balance is 0 to 65535, middle is 32768 + * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f + * to scale up to V4L numbers, mult by 1057 + * attenuation exists for lf, lr, rf, rr + * we use only lf and rf (front channels) + */ + if ( (t->lf) < (t->rf) ) /* right is attenuated, balance shifted left */ - ctrl->value = (32768 - 1057*(t->rf)); + va->balance = (32768 - 1057*(t->rf)); else /* left is attenuated, balance shifted right */ - ctrl->value = (32768 + 1057*(t->lf)); - return 0; - } - case V4L2_CID_AUDIO_BASS: - { + va->balance = (32768 + 1057*(t->lf)); + /* Bass/treble 4 bits each */ - int bass=t->bass; - if(bass >= 0x8) - bass = ~(bass - 0x8) & 0xf; - ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); - return 0; + va->bass=t->bass; + if(va->bass >= 0x8) + va->bass = ~(va->bass - 0x8) & 0xf; + va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass); + va->treble=t->treble; + if(va->treble >= 0x8) + va->treble = ~(va->treble - 0x8) & 0xf; + va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble); + + break; /* VIDIOCGAUDIO case */ } - case V4L2_CID_AUDIO_TREBLE: + + /* Set card - scale from V4L settings to TDA7432 settings */ + case VIDIOCSAUDIO: { - int treble=t->treble; - if(treble >= 0x8) - treble = ~(treble - 0x8) & 0xf; - ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); - return 0; - } - } - return -EINVAL; -} + struct video_audio *va = arg; -static int tda7432_set_ctrl(struct i2c_client *client, - struct v4l2_control *ctrl) -{ - struct tda7432 *t = i2c_get_clientdata(client); + if(va->flags & VIDEO_AUDIO_VOLUME){ + if(!maxvol){ /* max +20db */ + t->volume = 0x6f - ((va->volume)/630); + } else { /* max 0db */ + t->volume = 0x6f - ((va->volume)/829); + } - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - t->muted=ctrl->value; - break; - case V4L2_CID_AUDIO_VOLUME: - if(!maxvol){ /* max +20db */ - t->volume = 0x6f - ((ctrl->value)/630); - } else { /* max 0db */ - t->volume = 0x6f - ((ctrl->value)/829); - } if (loudness) /* Turn on the loudness bit */ t->volume |= TDA7432_LD_ON; - tda7432_write(client,TDA7432_VL, t->volume); - return 0; - case V4L2_CID_AUDIO_BALANCE: - if (ctrl->value < 32768) { + tda7432_write(client,TDA7432_VL, t->volume); + } + + if(va->flags & VIDEO_AUDIO_BASS) + { + t->bass = va->bass >> 12; + if(t->bass>= 0x8) + t->bass = (~t->bass & 0xf) + 0x8 ; + } + if(va->flags & VIDEO_AUDIO_TREBLE) + { + t->treble= va->treble >> 12; + if(t->treble>= 0x8) + t->treble = (~t->treble & 0xf) + 0x8 ; + } + if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS)) + tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); + + if(va->flags & VIDEO_AUDIO_BALANCE) { + if (va->balance < 32768) + { /* shifted to left, attenuate right */ - t->rr = (32768 - ctrl->value)/1057; + t->rr = (32768 - va->balance)/1057; t->rf = t->rr; t->lr = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; - } else if(ctrl->value > 32769) { + } + else if(va->balance > 32769) + { /* shifted to right, attenuate left */ - t->lf = (ctrl->value - 32768)/1057; + t->lf = (va->balance - 32768)/1057; t->lr = t->lf; t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; - } else { + } + else + { /* centered */ t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; t->lr = TDA7432_ATTEN_0DB; } - break; - case V4L2_CID_AUDIO_BASS: - t->bass = ctrl->value >> 12; - if(t->bass>= 0x8) - t->bass = (~t->bass & 0xf) + 0x8 ; - - tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); - return 0; - case V4L2_CID_AUDIO_TREBLE: - t->treble= ctrl->value >> 12; - if(t->treble>= 0x8) - t->treble = (~t->treble & 0xf) + 0x8 ; - - tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); - return 0; - default: - return -EINVAL; - } - - /* Used for both mute and balance changes */ - if (t->muted) - { - /* Mute & update balance*/ - tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); - tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); - tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); - tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); - } else { - tda7432_write(client,TDA7432_LF, t->lf); - tda7432_write(client,TDA7432_LR, t->lr); - tda7432_write(client,TDA7432_RF, t->rf); - tda7432_write(client,TDA7432_RR, t->rr); - } - return 0; -} - -static int tda7432_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - v4l_dbg(2, debug,client,"In tda7432_command\n"); - if (debug>1) - v4l_i2c_print_ioctl(client,cmd); + } - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - default: - return -EINVAL; + t->muted=(va->flags & VIDEO_AUDIO_MUTE); + if (t->muted) + { + /* Mute & update balance*/ + tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); + tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); + tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); + tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); + } else { + tda7432_write(client,TDA7432_LF, t->lf); + tda7432_write(client,TDA7432_LR, t->lr); + tda7432_write(client,TDA7432_RF, t->rf); + tda7432_write(client,TDA7432_RR, t->rr); } - return v4l2_ctrl_query_fill_std(qc); - } - case VIDIOC_S_CTRL: - return tda7432_set_ctrl(client, arg); - case VIDIOC_G_CTRL: - return tda7432_get_ctrl(client, arg); + break; + + } /* end of VIDEOCSAUDIO case */ } /* end of (cmd) switch */ diff --git a/trunk/drivers/media/video/tda8290.c b/trunk/drivers/media/video/tda8290.c index 55bc89a6f069..0e5cf459d3ed 100644 --- a/trunk/drivers/media/video/tda8290.c +++ b/trunk/drivers/media/video/tda8290.c @@ -25,14 +25,12 @@ #include #include "tuner-i2c.h" #include "tda8290.h" -#include "tda827x.h" -#include "tda18271.h" -static int debug; +static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tda8290" +#define PREFIX "tda8290 " /* ---------------------------------------------------------------------- */ @@ -40,71 +38,345 @@ struct tda8290_priv { struct tuner_i2c_props i2c_props; unsigned char tda8290_easy_mode; - + unsigned char tda827x_lpsel; unsigned char tda827x_addr; + unsigned char tda827x_ver; + unsigned int sgIF; - unsigned char ver; -#define TDA8290 1 -#define TDA8295 2 -#define TDA8275 4 -#define TDA8275A 8 -#define TDA18271 16 + u32 frequency; - struct tda827x_config cfg; + unsigned int *lna_cfg; + int (*tuner_callback) (void *dev, int command,int arg); }; -/*---------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------- */ + +struct tda827x_data { + u32 lomax; + u8 spd; + u8 bs; + u8 bp; + u8 cp; + u8 gc3; + u8 div1p5; +}; + + /* Note lomax entry is lo / 62500 */ + +static struct tda827x_data tda827x_analog[] = { + { .lomax = 992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 62 MHz */ + { .lomax = 1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 66 MHz */ + { .lomax = 1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 76 MHz */ + { .lomax = 1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 84 MHz */ + { .lomax = 1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 93 MHz */ + { .lomax = 1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 98 MHz */ + { .lomax = 1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */ + { .lomax = 1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */ + { .lomax = 2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */ + { .lomax = 2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */ + { .lomax = 2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */ + { .lomax = 2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */ + { .lomax = 2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */ + { .lomax = 3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */ + { .lomax = 3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */ + { .lomax = 4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */ + { .lomax = 4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */ + { .lomax = 5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */ + { .lomax = 5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */ + { .lomax = 7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */ + { .lomax = 7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */ + { .lomax = 8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */ + { .lomax = 8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */ + { .lomax = 9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */ + { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */ + { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */ + { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */ + { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */ + { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ +}; -static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) +static void tda827x_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char tuner_reg[8]; + unsigned char reg2[2]; + u32 N; + int i; + struct tda8290_priv *priv = fe->tuner_priv; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; + unsigned int freq = params->frequency; - unsigned char enable[2] = { 0x21, 0xC0 }; - unsigned char disable[2] = { 0x21, 0x00 }; - unsigned char *msg; + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; - if (close) { - msg = enable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); - /* let the bridge stabilize */ - msleep(20); - } else { - msg = disable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + N = freq + priv->sgIF; + i = 0; + while (tda827x_analog[i].lomax < N) { + if(tda827x_analog[i + 1].lomax == 0) + break; + i++; } - return 0; + N = N << tda827x_analog[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0x40; + tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5); + tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) + + (tda827x_analog[i].bs <<3) + tda827x_analog[i].bp; + tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4); + tuner_reg[7] = 0x8f; + + msg.buf = tuner_reg; + msg.len = 8; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + msg.buf= reg2; + msg.len = 2; + reg2[0] = 0x80; + reg2[1] = 0; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0xbf; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 0x80; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 4; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4]; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + msleep(550); + reg2[0] = 0x30; + reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0x3f; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + reg2[0] = 0x80; + reg2[1] = 0x08; // Vsync en + i2c_transfer(priv->i2c_props.adap, &msg, 1); } -static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) +static void tda827x_agcf(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->analog_demod_priv; + struct tda8290_priv *priv = fe->tuner_priv; + unsigned char data[] = {0x80, 0x0c}; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, + .flags = 0, .len = 2}; + i2c_transfer(priv->i2c_props.adap, &msg, 1); +} - unsigned char enable[2] = { 0x45, 0xc1 }; - unsigned char disable[2] = { 0x46, 0x00 }; - unsigned char buf[3] = { 0x45, 0x01, 0x00 }; - unsigned char *msg; +/* ---------------------------------------------------------------------- */ + +struct tda827xa_data { + u32 lomax; + u8 svco; + u8 spd; + u8 scr; + u8 sbs; + u8 gc3; +}; + +static struct tda827xa_data tda827xa_analog[] = { + { .lomax = 910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, /* 56.875 MHz */ + { .lomax = 1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 67.25 MHz */ + { .lomax = 1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 81.25 MHz */ + { .lomax = 1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 97.5 MHz */ + { .lomax = 1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, /* 113.75 MHz */ + { .lomax = 2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 134.5 MHz */ + { .lomax = 2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 154 MHz */ + { .lomax = 2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 162.5 MHz */ + { .lomax = 2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 183 MHz */ + { .lomax = 3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, /* 195 MHz */ + { .lomax = 3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, /* 227.5 MHz */ + { .lomax = 4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, /* 269 MHz */ + { .lomax = 5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, /* 325 MHz */ + { .lomax = 6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 390 MHz */ + { .lomax = 7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 455 MHz */ + { .lomax = 8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 520 MHz */ + { .lomax = 8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, /* 538 MHz */ + { .lomax = 8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 554 MHz */ + { .lomax = 9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 620 MHz */ + { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 650 MHz */ + { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 700 MHz */ + { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 780 MHz */ + { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 820 MHz */ + { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 870 MHz */ + { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, /* 911 MHz */ + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ +}; + +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) +{ + struct tda8290_priv *priv = fe->tuner_priv; + unsigned char buf[] = {0x22, 0x01}; + int arg; + struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; + + if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL)) + return; + + if (*priv->lna_cfg) { + if (high) + tuner_dbg("setting LNA to high gain\n"); + else + tuner_dbg("setting LNA to low gain\n"); + } + switch (*priv->lna_cfg) { + case 0: /* no LNA */ + break; + case 1: /* switch is GPIO 0 of tda8290 */ + case 2: + /* turn Vsync on */ + if (params->std & V4L2_STD_MN) + arg = 1; + else + arg = 0; + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); + buf[1] = high ? 0 : 1; + if (*priv->lna_cfg == 2) + buf[1] = high ? 1 : 0; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + break; + case 3: /* switch with GPIO of saa713x */ + if (priv->tuner_callback) + priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); + break; + } +} + +static void tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[11]; + u32 N; + int i; + struct tda8290_priv *priv = fe->tuner_priv; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; + unsigned int freq = params->frequency; - if (close) { + tda827xa_lna_gain(fe, 1, params); + msleep(10); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + i = 0; + while (tda827xa_analog[i].lomax < N) { + if(tda827xa_analog[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827xa_analog[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0; + tuner_reg[4] = 0x16; + tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + + tda827xa_analog[i].sbs; + tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); + tuner_reg[7] = 0x1c; + tuner_reg[8] = 4; + tuner_reg[9] = 0x20; + tuner_reg[10] = 0x00; + msg.len = 11; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + tuner_reg[0] = 0x90; + tuner_reg[1] = 0xff; + tuner_reg[2] = 0xe0; + tuner_reg[3] = 0; + tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); + msg.len = 5; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + tuner_reg[0] = 0xa0; + tuner_reg[1] = 0xc0; + msg.len = 2; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + tuner_reg[0] = 0x30; + tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + msg.flags = I2C_M_RD; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + msg.flags = 0; + tuner_reg[1] >>= 4; + tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); + if (tuner_reg[1] < 1) + tda827xa_lna_gain(fe, 0, params); + + msleep(100); + tuner_reg[0] = 0x60; + tuner_reg[1] = 0x3c; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + msleep(163); + tuner_reg[0] = 0x50; + tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + tuner_reg[0] = 0x80; + tuner_reg[1] = 0x28; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + tuner_reg[0] = 0xb0; + tuner_reg[1] = 0x01; + i2c_transfer(priv->i2c_props.adap, &msg, 1); + + tuner_reg[0] = 0xc0; + tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); + i2c_transfer(priv->i2c_props.adap, &msg, 1); +} + +static void tda827xa_agcf(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->tuner_priv; + unsigned char data[] = {0x80, 0x2c}; + struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, + .flags = 0, .len = 2}; + i2c_transfer(priv->i2c_props.adap, &msg, 1); +} + +/*---------------------------------------------------------------------*/ + +static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) +{ + struct tda8290_priv *priv = fe->tuner_priv; + + unsigned char enable[2] = { 0x21, 0xC0 }; + unsigned char disable[2] = { 0x21, 0x00 }; + unsigned char *msg; + if(close) { msg = enable; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); /* let the bridge stabilize */ msleep(20); } else { msg = disable; - tuner_i2c_xfer_send(&priv->i2c_props, msg, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1); - - buf[2] = msg[1]; - buf[2] &= ~0x04; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); - msleep(5); - - msg[1] |= 0x04; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } - - return 0; } /*---------------------------------------------------------------------*/ @@ -112,43 +384,55 @@ static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) static void set_audio(struct dvb_frontend *fe, struct analog_parameters *params) { - struct tda8290_priv *priv = fe->analog_demod_priv; + struct tda8290_priv *priv = fe->tuner_priv; char* mode; + priv->tda827x_lpsel = 0; if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; priv->tda8290_easy_mode = 0x01; + priv->tda827x_lpsel = 1; mode = "MN"; } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; priv->tda8290_easy_mode = 0x02; mode = "B"; } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; priv->tda8290_easy_mode = 0x04; mode = "GH"; } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; priv->tda8290_easy_mode = 0x08; mode = "I"; } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "DK"; } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; priv->tda8290_easy_mode = 0x20; mode = "L"; } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; priv->tda8290_easy_mode = 0x40; mode = "LC"; } else { + priv->sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "xx"; } - tuner_dbg("setting tda829x to system %s\n", mode); + if (params->mode == V4L2_TUNER_RADIO) + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + + tuner_dbg("setting tda8290 to system %s\n", mode); } -static void tda8290_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static int tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tda8290_priv *priv = fe->analog_demod_priv; - + struct tda8290_priv *priv = fe->tuner_priv; unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -173,8 +457,8 @@ static void tda8290_set_params(struct dvb_frontend *fe, set_audio(fe, params); - if (priv->cfg.config) - tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config); + if (priv->lna_cfg) + tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -191,10 +475,10 @@ static void tda8290_set_params(struct dvb_frontend *fe, tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); tda8290_i2c_bridge(fe, 1); - - if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, params); - + if (priv->tda827x_ver != 0) + tda827xa_set_analog_params(fe, params); + else + tda827x_set_analog_params(fe, params); for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); @@ -223,8 +507,10 @@ static void tda8290_set_params(struct dvb_frontend *fe, if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); - if (priv->cfg.agcf) - priv->cfg.agcf(fe); + if (priv->tda827x_ver != 0) + tda827xa_agcf(fe); + else + tda827x_agcf(fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -255,242 +541,99 @@ static void tda8290_set_params(struct dvb_frontend *fe, tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); -} - -/*---------------------------------------------------------------------*/ - -static void tda8295_power(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ - - tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); - - if (enable) - buf[1] = 0x01; - else - buf[1] = 0x03; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} -static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x01, 0x00 }; - - tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); - - if (enable) - buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ - else - buf[1] = 0x00; /* reset active bit */ - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_set_video_std(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; + priv->frequency = (V4L2_TUNER_RADIO == params->mode) ? + params->frequency * 125 / 2 : params->frequency * 62500; - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); - - tda8295_set_easy_mode(fe, 1); - msleep(20); - tda8295_set_easy_mode(fe, 0); + return 0; } /*---------------------------------------------------------------------*/ -static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ - - tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); - - if (enable) - buf[1] &= ~0x40; - else - buf[1] |= 0x40; - - tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); -} - -static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) +static int tda8290_has_signal(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char set_gpio_cf[] = { 0x44, 0x00 }; - unsigned char set_gpio_val[] = { 0x46, 0x00 }; + struct tda8290_priv *priv = fe->tuner_priv; + int ret; - tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1); - tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1); - - set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ + unsigned char i2c_get_afc[1] = { 0x1B }; + unsigned char afc = 0; - if (enable) { - set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ - set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ - } - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); -} + /* for now, report based on afc status */ + tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); -static int tda8295_has_signal(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; + ret = (afc & 0x80) ? 65535 : 0; - unsigned char hvpll_stat = 0x26; - unsigned char ret; + tuner_dbg("AFC status: %d\n", ret); - tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1); - return (ret & 0x01) ? 65535 : 0; + return ret; } -/*---------------------------------------------------------------------*/ - -static void tda8295_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) { - struct tda8290_priv *priv = fe->analog_demod_priv; - - unsigned char blanking_mode[] = { 0x1d, 0x00 }; - - set_audio(fe, params); - - tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency); + *status = 0; - tda8295_power(fe, 1); - tda8295_agc1_out(fe, 1); - - tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); - tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); - - tda8295_set_video_std(fe); - - blanking_mode[1] = 0x03; - tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); - msleep(20); - - tda8295_i2c_bridge(fe, 1); - - if (fe->ops.tuner_ops.set_analog_params) - fe->ops.tuner_ops.set_analog_params(fe, params); - - if (priv->cfg.agcf) - priv->cfg.agcf(fe); - - if (tda8295_has_signal(fe)) - tuner_dbg("tda8295 is locked\n"); - else - tuner_dbg("tda8295 not locked, no signal?\n"); + if (tda8290_has_signal(fe)) + *status = TUNER_STATUS_LOCKED; - tda8295_i2c_bridge(fe, 0); + return 0; } -/*---------------------------------------------------------------------*/ - -static int tda8290_has_signal(struct dvb_frontend *fe) +static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength) { - struct tda8290_priv *priv = fe->analog_demod_priv; + *strength = tda8290_has_signal(fe); - unsigned char i2c_get_afc[1] = { 0x1B }; - unsigned char afc = 0; - - tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); - return (afc & 0x80)? 65535:0; + return 0; } /*---------------------------------------------------------------------*/ -static void tda8290_standby(struct dvb_frontend *fe) +static int tda8290_standby(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->analog_demod_priv; - + struct tda8290_priv *priv = fe->tuner_priv; unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; tda8290_i2c_bridge(fe, 1); - if (priv->ver & TDA8275A) + if (priv->tda827x_ver != 0) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); -} -static void tda8295_standby(struct dvb_frontend *fe) -{ - tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ - - tda8295_power(fe, 0); + return 0; } + static void tda8290_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->analog_demod_priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((priv->cfg.config) && - ((*priv->cfg.config == 1) || (*priv->cfg.config == 2))) + if ((priv->lna_cfg) && + ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2))) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } -static void tda8295_init_if(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->analog_demod_priv; - - static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; - static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; - static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; - static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; - static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; - static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; - static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; - - tda8295_power(fe, 1); - - tda8295_set_easy_mode(fe, 0); - tda8295_set_video_std(fe); - - tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); - tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); - - tda8295_agc1_out(fe, 0); - tda8295_agc2_out(fe, 0); -} - static void tda8290_init_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->analog_demod_priv; + struct tda8290_priv *priv = fe->tuner_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=tda8275_init, .len = 14}; - if (priv->ver & TDA8275A) + if (priv->tda827x_ver != 0) msg.buf = tda8275a_init; tda8290_i2c_bridge(fe, 1); @@ -500,42 +643,58 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) /*---------------------------------------------------------------------*/ -static void tda829x_release(struct dvb_frontend *fe) +static int tda8290_release(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->analog_demod_priv; + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; - /* only try to release the tuner if we've - * attached it from within this module */ - if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); + return 0; +} - kfree(fe->analog_demod_priv); - fe->analog_demod_priv = NULL; +static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda8290_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; } -static struct tda18271_config tda829x_tda18271_config = { - .gate = TDA18271_GATE_ANALOG, +static struct dvb_tuner_ops tda8290_tuner_ops = { + .sleep = tda8290_standby, + .set_analog_params = tda8290_set_params, + .release = tda8290_release, + .get_frequency = tda8290_get_frequency, + .get_status = tda8290_get_status, + .get_rf_strength = tda8290_get_rf_strength, }; -static int tda829x_find_tuner(struct dvb_frontend *fe) +struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, + u8 i2c_addr, + struct tda8290_config *cfg) { - struct tda8290_priv *priv = fe->analog_demod_priv; - struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; + struct tda8290_priv *priv = NULL; + u8 data; int i, ret, tuners_found; u32 tuner_addrs; - u8 data; - struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; + struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1}; - if (NULL == analog_ops->i2c_gate_ctrl) - return -EINVAL; + priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->tuner_priv = priv; - analog_ops->i2c_gate_ctrl(fe, 1); + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + if (cfg) { + priv->lna_cfg = cfg->lna_cfg; + priv->tuner_callback = cfg->tuner_callback; + } + tda8290_i2c_bridge(fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; - for (i = 0x60; i <= 0x63; i++) { + for (i=0x60; i<= 0x63; i++) { msg.addr = i; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { @@ -547,23 +706,20 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) behind the bridge and we choose the highest address that doesn't give a response now */ - - analog_ops->i2c_gate_ctrl(fe, 0); - - if (tuners_found > 1) + tda8290_i2c_bridge(fe, 0); + if(tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if (ret == 1) + if(ret == 1) tuner_addrs = tuner_addrs >> 8; else break; } - if (tuner_addrs == 0) { - tuner_addrs = 0x60; - tuner_info("could not clearly identify tuner address, " - "defaulting to %x\n", tuner_addrs); + tuner_addrs = 0x61; + tuner_info("could not clearly identify tuner address, defaulting to %x\n", + tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; tuner_info("setting tuner address to %x\n", tuner_addrs); @@ -571,181 +727,42 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - analog_ops->i2c_gate_ctrl(fe, 1); + tda8290_i2c_bridge(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - - if (ret != 1) { - tuner_warn("tuner access failed!\n"); - return -EREMOTEIO; - } - - if ((data == 0x83) || (data == 0x84)) { - priv->ver |= TDA18271; - tda18271_attach(fe, priv->tda827x_addr, - priv->i2c_props.adap, - &tda829x_tda18271_config); + if( ret != 1) + tuner_warn("TDA827x access failed!\n"); + + memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if ((data & 0x3c) == 0) { + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 55000000; + fe->ops.tuner_ops.info.frequency_max = 860000000; + fe->ops.tuner_ops.info.frequency_step = 250000; + priv->tda827x_ver = 0; } else { - if ((data & 0x3c) == 0) - priv->ver |= TDA8275; - else - priv->ver |= TDA8275A; - - tda827x_attach(fe, priv->tda827x_addr, - priv->i2c_props.adap, &priv->cfg); - } - if (fe->ops.tuner_ops.init) - fe->ops.tuner_ops.init(fe); - - if (fe->ops.tuner_ops.sleep) - fe->ops.tuner_ops.sleep(fe); - - analog_ops->i2c_gate_ctrl(fe, 0); - - return 0; -} - -static int tda8290_probe(struct tuner_i2c_props *i2c_props) -{ -#define TDA8290_ID 0x89 - unsigned char tda8290_id[] = { 0x1f, 0x00 }; - - /* detect tda8290 */ - tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1); - tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1); - - if (tda8290_id[1] == TDA8290_ID) { - if (debug) - printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", - __FUNCTION__, i2c_adapter_id(i2c_props->adap), - i2c_props->addr); - return 0; - } - - return -ENODEV; -} - -static int tda8295_probe(struct tuner_i2c_props *i2c_props) -{ -#define TDA8295_ID 0x8a - unsigned char tda8295_id[] = { 0x2f, 0x00 }; - - /* detect tda8295 */ - tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1); - tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1); - - if (tda8295_id[1] == TDA8295_ID) { - if (debug) - printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n", - __FUNCTION__, i2c_adapter_id(i2c_props->adap), - i2c_props->addr); - return 0; + strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a", + sizeof(fe->ops.tuner_ops.info.name)); + fe->ops.tuner_ops.info.frequency_min = 44000000; + fe->ops.tuner_ops.info.frequency_max = 906000000; + fe->ops.tuner_ops.info.frequency_step = 62500; + priv->tda827x_ver = 2; } - return -ENODEV; -} - -static struct analog_demod_ops tda8290_ops = { - .set_params = tda8290_set_params, - .has_signal = tda8290_has_signal, - .standby = tda8290_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8290_i2c_bridge, -}; - -static struct analog_demod_ops tda8295_ops = { - .set_params = tda8295_set_params, - .has_signal = tda8295_has_signal, - .standby = tda8295_standby, - .release = tda829x_release, - .i2c_gate_ctrl = tda8295_i2c_bridge, -}; - -struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, - struct tda829x_config *cfg) -{ - struct tda8290_priv *priv = NULL; - char *name; - - priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->analog_demod_priv = priv; - - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - if (cfg) { - priv->cfg.config = cfg->lna_cfg; - priv->cfg.tuner_callback = cfg->tuner_callback; - } - - if (tda8290_probe(&priv->i2c_props) == 0) { - priv->ver = TDA8290; - memcpy(&fe->ops.analog_ops, &tda8290_ops, - sizeof(struct analog_demod_ops)); - } - - if (tda8295_probe(&priv->i2c_props) == 0) { - priv->ver = TDA8295; - memcpy(&fe->ops.analog_ops, &tda8295_ops, - sizeof(struct analog_demod_ops)); - } - - if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) && - (tda829x_find_tuner(fe) < 0)) - goto fail; - - switch (priv->ver) { - case TDA8290: - name = "tda8290"; - break; - case TDA8295: - name = "tda8295"; - break; - case TDA8290 | TDA8275: - name = "tda8290+75"; - break; - case TDA8295 | TDA8275: - name = "tda8295+75"; - break; - case TDA8290 | TDA8275A: - name = "tda8290+75a"; - break; - case TDA8295 | TDA8275A: - name = "tda8295+75a"; - break; - case TDA8290 | TDA18271: - name = "tda8290+18271"; - break; - case TDA8295 | TDA18271: - name = "tda8295+18271"; - break; - default: - goto fail; - } - tuner_info("type set to %s\n", name); - - fe->ops.analog_ops.info.name = name; - - if (priv->ver & TDA8290) { - tda8290_init_tuner(fe); - tda8290_init_if(fe); - } else if (priv->ver & TDA8295) - tda8295_init_if(fe); + priv->tda827x_lpsel = 0; + tda8290_init_tuner(fe); + tda8290_init_if(fe); return fe; - -fail: - tda829x_release(fe); - return NULL; } -EXPORT_SYMBOL_GPL(tda829x_attach); -int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) +int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) { struct tuner_i2c_props i2c_props = { .adap = i2c_adap, - .addr = i2c_addr, + .addr = i2c_addr }; unsigned char soft_reset[] = { 0x00, 0x00 }; @@ -754,27 +771,7 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; unsigned char addr_dto_lsb = 0x07; unsigned char data; -#define PROBE_BUFFER_SIZE 8 - unsigned char buf[PROBE_BUFFER_SIZE]; - int i; - - /* rule out tda9887, which would return the same byte repeatedly */ - tuner_i2c_xfer_send(&i2c_props, soft_reset, 1); - tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE); - for (i = 1; i < PROBE_BUFFER_SIZE; i++) { - if (buf[i] != buf[0]) - break; - } - /* all bytes are equal, not a tda829x - probably a tda9887 */ - if (i == PROBE_BUFFER_SIZE) - return -ENODEV; - - if ((tda8290_probe(&i2c_props) == 0) || - (tda8295_probe(&i2c_props) == 0)) - return 0; - - /* fall back to old probing method */ tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); @@ -789,12 +786,14 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) } } tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); - return -ENODEV; + return -1; } -EXPORT_SYMBOL_GPL(tda829x_probe); -MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); -MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); +EXPORT_SYMBOL_GPL(tda8290_probe); +EXPORT_SYMBOL_GPL(tda8290_attach); + +MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); MODULE_LICENSE("GPL"); /* diff --git a/trunk/drivers/media/video/tda8290.h b/trunk/drivers/media/video/tda8290.h index dc8ef310b7b2..107b24b05aa1 100644 --- a/trunk/drivers/media/video/tda8290.h +++ b/trunk/drivers/media/video/tda8290.h @@ -20,36 +20,33 @@ #include #include "dvb_frontend.h" -struct tda829x_config { +struct tda8290_config +{ unsigned int *lna_cfg; - int (*tuner_callback) (void *dev, int command, int arg); - - unsigned int probe_tuner:1; -#define TDA829X_PROBE_TUNER 0 -#define TDA829X_DONT_PROBE 1 + int (*tuner_callback) (void *dev, int command,int arg); }; #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); +extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); -extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, +extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, u8 i2c_addr, - struct tda829x_config *cfg); + struct tda8290_config *cfg); #else -static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) +static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); return -EINVAL; } -static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, +static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, + struct i2c_adapter* i2c_adap, u8 i2c_addr, - struct tda829x_config *cfg) + struct tda8290_config *cfg) { - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __FUNCTION__); + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } #endif diff --git a/trunk/drivers/media/video/tda9875.c b/trunk/drivers/media/video/tda9875.c index 3c0557130a70..d11044170872 100644 --- a/trunk/drivers/media/video/tda9875.c +++ b/trunk/drivers/media/video/tda9875.c @@ -7,7 +7,6 @@ * * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and * Eric Sandeen - * Copyright (c) 2006 Mauro Carvalho Chehab * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -269,143 +268,87 @@ static int tda9875_detach(struct i2c_client *client) return 0; } -static int tda9875_get_ctrl(struct i2c_client *client, - struct v4l2_control *ctrl) +static int tda9875_command(struct i2c_client *client, + unsigned int cmd, void *arg) { struct tda9875 *t = i2c_get_clientdata(client); - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - { - int left = (t->lvol+84)*606; - int right = (t->rvol+84)*606; + dprintk("In tda9875_command...\n"); - ctrl->value=max(left,right); - return 0; - } - case V4L2_CID_AUDIO_BALANCE: + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: { - int left = (t->lvol+84)*606; - int right = (t->rvol+84)*606; - int volume = max(left,right); - int balance = (32768*min(left,right))/ - (volume ? volume : 1); - ctrl->value=(leftvalue = (t->bass+12)*2427; /* min -12 max +15 */ - return 0; - case V4L2_CID_AUDIO_TREBLE: - ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */ - return 0; - } - return -EINVAL; -} + struct video_audio *va = arg; + int left,right; -static int tda9875_set_ctrl(struct i2c_client *client, - struct v4l2_control *ctrl) -{ - struct tda9875 *t = i2c_get_clientdata(client); - int chvol=0, volume, balance, left, right; + dprintk("VIDIOCGAUDIO\n"); - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - left = (t->lvol+84)*606; - right = (t->rvol+84)*606; - - volume = max(left,right); - balance = (32768*min(left,right))/ - (volume ? volume : 1); - balance =(leftvalue; + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; - chvol=1; - break; - case V4L2_CID_AUDIO_BALANCE: + /* min is -84 max is 24 */ left = (t->lvol+84)*606; right = (t->rvol+84)*606; - - volume=max(left,right); - - balance = ctrl->value; - - chvol=1; - break; - case V4L2_CID_AUDIO_BASS: - t->bass = ((ctrl->value/2400)-12) & 0xff; - if (t->bass > 15) - t->bass = 15; - if (t->bass < -12) - t->bass = -12 & 0xff; - break; - case V4L2_CID_AUDIO_TREBLE: - t->treble = ((ctrl->value/2700)-12) & 0xff; - if (t->treble > 12) - t->treble = 12; - if (t->treble < -12) - t->treble = -12 & 0xff; - break; - default: - return -EINVAL; + va->volume=max(left,right); + va->balance=(32768*min(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(leftbalance) : va->balance; + va->bass = (t->bass+12)*2427; /* min -12 max +15 */ + va->treble = (t->treble+12)*2730;/* min -12 max +12 */ + va->mode |= VIDEO_SOUND_MONO; + + break; /* VIDIOCGAUDIO case */ } - if (chvol) { - left = (min(65536 - balance,32768) * - volume) / 32768; - right = (min(balance,32768) * - volume) / 32768; + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + int left,right; + + dprintk("VIDEOCSAUDIO...\n"); + left = (min(65536 - va->balance,32768) * + va->volume) / 32768; + right = (min(va->balance,(__u16)32768) * + va->volume) / 32768; t->lvol = ((left/606)-84) & 0xff; if (t->lvol > 24) - t->lvol = 24; + t->lvol = 24; if (t->lvol < -84) - t->lvol = -84 & 0xff; + t->lvol = -84 & 0xff; t->rvol = ((right/606)-84) & 0xff; if (t->rvol > 24) - t->rvol = 24; + t->rvol = 24; if (t->rvol < -84) - t->rvol = -84 & 0xff; - } + t->rvol = -84 & 0xff; -//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + t->bass = ((va->bass/2400)-12) & 0xff; + if (t->bass > 15) + t->bass = 15; + if (t->bass < -12) + t->bass = -12 & 0xff; - tda9875_set(client); + t->treble = ((va->treble/2700)-12) & 0xff; + if (t->treble > 12) + t->treble = 12; + if (t->treble < -12) + t->treble = -12 & 0xff; - return 0; -} -static int tda9875_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - dprintk("In tda9875_command...\n"); +//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - - switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - default: - return -EINVAL; - } - return v4l2_ctrl_query_fill_std(qc); - } - case VIDIOC_S_CTRL: - return tda9875_set_ctrl(client, arg); - case VIDIOC_G_CTRL: - return tda9875_get_ctrl(client, arg); + tda9875_set(client); + + break; + + } /* end of VIDEOCSAUDIO case */ default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ diff --git a/trunk/drivers/media/video/tda9887.c b/trunk/drivers/media/video/tda9887.c index 106c93b8203f..be5387f11afb 100644 --- a/trunk/drivers/media/video/tda9887.c +++ b/trunk/drivers/media/video/tda9887.c @@ -9,8 +9,7 @@ #include #include #include -#include "tuner-i2c.h" -#include "tda9887.h" +#include "tuner-driver.h" /* Chips: @@ -21,20 +20,18 @@ Used as part of several tuners */ -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -#define PREFIX "tda9887" +#define tda9887_info(fmt, arg...) do {\ + printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +#define tda9887_dbg(fmt, arg...) do {\ + if (tuner_debug) \ + printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) struct tda9887_priv { struct tuner_i2c_props i2c_props; unsigned char data[4]; - unsigned int config; - unsigned int mode; - unsigned int audmode; - v4l2_std_id std; }; /* ---------------------------------------------------------------------- */ @@ -265,10 +262,8 @@ static struct tvnorm radio_mono = { /* ---------------------------------------------------------------------- */ -static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) +static void dump_read_message(struct tuner *t, unsigned char *buf) { - struct tda9887_priv *priv = fe->analog_demod_priv; - static char *afc[16] = { "- 12.5 kHz", "- 37.5 kHz", @@ -287,18 +282,16 @@ static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) "+ 37.5 kHz", "+ 12.5 kHz", }; - tuner_info("read: 0x%2x\n", buf[0]); - tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); - tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); - tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); - tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); - tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); + tda9887_info("read: 0x%2x\n", buf[0]); + tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); + tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); + tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); + tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); + tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); } -static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) +static void dump_write_message(struct tuner *t, unsigned char *buf) { - struct tda9887_priv *priv = fe->analog_demod_priv; - static char *sound[4] = { "AM/TV", "FM/radio", @@ -337,90 +330,86 @@ static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) "44 MHz", }; - tuner_info("write: byte B 0x%02x\n", buf[1]); - tuner_info(" B0 video mode : %s\n", - (buf[1] & 0x01) ? "video trap" : "sound trap"); - tuner_info(" B1 auto mute fm : %s\n", - (buf[1] & 0x02) ? "yes" : "no"); - tuner_info(" B2 carrier mode : %s\n", - (buf[1] & 0x04) ? "QSS" : "Intercarrier"); - tuner_info(" B3-4 tv sound/radio : %s\n", - sound[(buf[1] & 0x18) >> 3]); - tuner_info(" B5 force mute audio: %s\n", - (buf[1] & 0x20) ? "yes" : "no"); - tuner_info(" B6 output port 1 : %s\n", - (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); - tuner_info(" B7 output port 2 : %s\n", - (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); - - tuner_info("write: byte C 0x%02x\n", buf[2]); - tuner_info(" C0-4 top adjustment : %s dB\n", - adjust[buf[2] & 0x1f]); - tuner_info(" C5-6 de-emphasis : %s\n", - deemph[(buf[2] & 0x60) >> 5]); - tuner_info(" C7 audio gain : %s\n", - (buf[2] & 0x80) ? "-6" : "0"); - - tuner_info("write: byte E 0x%02x\n", buf[3]); - tuner_info(" E0-1 sound carrier : %s\n", - carrier[(buf[3] & 0x03)]); - tuner_info(" E6 l pll gating : %s\n", - (buf[3] & 0x40) ? "36" : "13"); + tda9887_info("write: byte B 0x%02x\n",buf[1]); + tda9887_info(" B0 video mode : %s\n", + (buf[1] & 0x01) ? "video trap" : "sound trap"); + tda9887_info(" B1 auto mute fm : %s\n", + (buf[1] & 0x02) ? "yes" : "no"); + tda9887_info(" B2 carrier mode : %s\n", + (buf[1] & 0x04) ? "QSS" : "Intercarrier"); + tda9887_info(" B3-4 tv sound/radio : %s\n", + sound[(buf[1] & 0x18) >> 3]); + tda9887_info(" B5 force mute audio: %s\n", + (buf[1] & 0x20) ? "yes" : "no"); + tda9887_info(" B6 output port 1 : %s\n", + (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); + tda9887_info(" B7 output port 2 : %s\n", + (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); + + tda9887_info("write: byte C 0x%02x\n",buf[2]); + tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]); + tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]); + tda9887_info(" C7 audio gain : %s\n", + (buf[2] & 0x80) ? "-6" : "0"); + + tda9887_info("write: byte E 0x%02x\n",buf[3]); + tda9887_info(" E0-1 sound carrier : %s\n", + carrier[(buf[3] & 0x03)]); + tda9887_info(" E6 l pll gating : %s\n", + (buf[3] & 0x40) ? "36" : "13"); if (buf[1] & 0x08) { /* radio */ - tuner_info(" E2-4 video if : %s\n", - rif[(buf[3] & 0x0c) >> 2]); - tuner_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x10) ? "fm-agc radio" : - "sif-agc radio") - : "fm radio carrier afc"); + tda9887_info(" E2-4 video if : %s\n", + rif[(buf[3] & 0x0c) >> 2]); + tda9887_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio") + : "fm radio carrier afc"); } else { /* video */ - tuner_info(" E2-4 video if : %s\n", - vif[(buf[3] & 0x1c) >> 2]); - tuner_info(" E5 tuner gain : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) ? "external" : "normal") - : ((buf[3] & 0x20) ? "minimum" : "normal")); - tuner_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) ? ((buf[3] & 0x20) - ? "pin3 port, pin22 vif agc out" - : "pin22 port, pin3 vif acg ext in") - : "pin3+pin22 port"); + tda9887_info(" E2-4 video if : %s\n", + vif[(buf[3] & 0x1c) >> 2]); + tda9887_info(" E5 tuner gain : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) ? "external" : "normal") + : ((buf[3] & 0x20) ? "minimum" : "normal")); + tda9887_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) + ? "pin3 port, pin22 vif agc out" + : "pin22 port, pin3 vif acg ext in") + : "pin3+pin22 port"); } - tuner_info("--\n"); + tda9887_info("--\n"); } /* ---------------------------------------------------------------------- */ -static int tda9887_set_tvnorm(struct dvb_frontend *fe) +static int tda9887_set_tvnorm(struct tuner *t, char *buf) { - struct tda9887_priv *priv = fe->analog_demod_priv; struct tvnorm *norm = NULL; - char *buf = priv->data; int i; - if (priv->mode == V4L2_TUNER_RADIO) { - if (priv->audmode == V4L2_TUNER_MODE_MONO) + if (t->mode == V4L2_TUNER_RADIO) { + if (t->audmode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else norm = &radio_stereo; } else { for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { - if (tvnorms[i].std & priv->std) { + if (tvnorms[i].std & t->std) { norm = tvnorms+i; break; } } } if (NULL == norm) { - tuner_dbg("Unsupported tvnorm entry - audio muted\n"); + tda9887_dbg("Unsupported tvnorm entry - audio muted\n"); return -1; } - tuner_dbg("configure for: %s\n", norm->name); + tda9887_dbg("configure for: %s\n",norm->name); buf[1] = norm->b; buf[2] = norm->c; buf[3] = norm->e; @@ -437,11 +426,8 @@ module_param(port2, int, 0644); module_param(qss, int, 0644); module_param(adjust, int, 0644); -static int tda9887_set_insmod(struct dvb_frontend *fe) +static int tda9887_set_insmod(struct tuner *t, char *buf) { - struct tda9887_priv *priv = fe->analog_demod_priv; - char *buf = priv->data; - if (UNSET != port1) { if (port1) buf[1] |= cOutputPort1Inactive; @@ -469,30 +455,27 @@ static int tda9887_set_insmod(struct dvb_frontend *fe) return 0; } -static int tda9887_do_config(struct dvb_frontend *fe) +static int tda9887_set_config(struct tuner *t, char *buf) { - struct tda9887_priv *priv = fe->analog_demod_priv; - char *buf = priv->data; - - if (priv->config & TDA9887_PORT1_ACTIVE) + if (t->tda9887_config & TDA9887_PORT1_ACTIVE) buf[1] &= ~cOutputPort1Inactive; - if (priv->config & TDA9887_PORT1_INACTIVE) + if (t->tda9887_config & TDA9887_PORT1_INACTIVE) buf[1] |= cOutputPort1Inactive; - if (priv->config & TDA9887_PORT2_ACTIVE) + if (t->tda9887_config & TDA9887_PORT2_ACTIVE) buf[1] &= ~cOutputPort2Inactive; - if (priv->config & TDA9887_PORT2_INACTIVE) + if (t->tda9887_config & TDA9887_PORT2_INACTIVE) buf[1] |= cOutputPort2Inactive; - if (priv->config & TDA9887_QSS) + if (t->tda9887_config & TDA9887_QSS) buf[1] |= cQSS; - if (priv->config & TDA9887_INTERCARRIER) + if (t->tda9887_config & TDA9887_INTERCARRIER) buf[1] &= ~cQSS; - if (priv->config & TDA9887_AUTOMUTE) + if (t->tda9887_config & TDA9887_AUTOMUTE) buf[1] |= cAutoMuteFmActive; - if (priv->config & TDA9887_DEEMPHASIS_MASK) { + if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { buf[2] &= ~0x60; - switch (priv->config & TDA9887_DEEMPHASIS_MASK) { + switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { case TDA9887_DEEMPHASIS_NONE: buf[2] |= cDeemphasisOFF; break; @@ -504,22 +487,21 @@ static int tda9887_do_config(struct dvb_frontend *fe) break; } } - if (priv->config & TDA9887_TOP_SET) { + if (t->tda9887_config & TDA9887_TOP_SET) { buf[2] &= ~cTopMask; - buf[2] |= (priv->config >> 8) & cTopMask; + buf[2] |= (t->tda9887_config >> 8) & cTopMask; } - if ((priv->config & TDA9887_INTERCARRIER_NTSC) && - (priv->std & V4L2_STD_NTSC)) + if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) buf[1] &= ~cQSS; - if (priv->config & TDA9887_GATING_18) + if (t->tda9887_config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (priv->mode == V4L2_TUNER_RADIO) { - if (priv->config & TDA9887_RIF_41_3) { + if (t->mode == V4L2_TUNER_RADIO) { + if (t->tda9887_config & TDA9887_RIF_41_3) { buf[3] &= ~cVideoIFMask; buf[3] |= cRadioIF_41_30; } - if (priv->config & TDA9887_GAIN_NORMAL) + if (t->tda9887_config & TDA9887_GAIN_NORMAL) buf[3] &= ~cTunerGainLow; } @@ -528,26 +510,26 @@ static int tda9887_do_config(struct dvb_frontend *fe) /* ---------------------------------------------------------------------- */ -static int tda9887_status(struct dvb_frontend *fe) +static int tda9887_status(struct tuner *t) { - struct tda9887_priv *priv = fe->analog_demod_priv; + struct tda9887_priv *priv = t->priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) - tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); - dump_read_message(fe, buf); + tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); + dump_read_message(t, buf); return 0; } -static void tda9887_configure(struct dvb_frontend *fe) +static void tda9887_configure(struct tuner *t) { - struct tda9887_priv *priv = fe->analog_demod_priv; + struct tda9887_priv *priv = t->priv; int rc; memset(priv->data,0,sizeof(priv->data)); - tda9887_set_tvnorm(fe); + tda9887_set_tvnorm(t,priv->data); /* A note on the port settings: These settings tend to depend on the specifics of the board. @@ -565,38 +547,38 @@ static void tda9887_configure(struct dvb_frontend *fe) priv->data[1] |= cOutputPort1Inactive; priv->data[1] |= cOutputPort2Inactive; - tda9887_do_config(fe); - tda9887_set_insmod(fe); + tda9887_set_config(t,priv->data); + tda9887_set_insmod(t,priv->data); - if (priv->mode == T_STANDBY) + if (t->mode == T_STANDBY) { priv->data[1] |= cForcedMuteAudioON; + } - tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1], priv->data[2], priv->data[3]); - if (debug > 1) - dump_write_message(fe, priv->data); + tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1],priv->data[2],priv->data[3]); + if (tuner_debug > 1) + dump_write_message(t, priv->data); if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) - tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); + tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); - if (debug > 2) { + if (tuner_debug > 2) { msleep_interruptible(1000); - tda9887_status(fe); + tda9887_status(t); } } /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct dvb_frontend *fe) +static void tda9887_tuner_status(struct tuner *t) { - struct tda9887_priv *priv = fe->analog_demod_priv; - tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1], priv->data[2], priv->data[3]); + struct tda9887_priv *priv = t->priv; + tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct dvb_frontend *fe) +static int tda9887_get_afc(struct tuner *t) { - struct tda9887_priv *priv = fe->analog_demod_priv; + struct tda9887_priv *priv = t->priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -612,79 +594,52 @@ static int tda9887_get_afc(struct dvb_frontend *fe) return afc; } -static void tda9887_standby(struct dvb_frontend *fe) -{ - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->mode = T_STANDBY; - - tda9887_configure(fe); -} - -static void tda9887_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static void tda9887_standby(struct tuner *t) { - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->mode = params->mode; - priv->audmode = params->audmode; - priv->std = params->std; - tda9887_configure(fe); + tda9887_configure(t); } -static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) +static void tda9887_set_freq(struct tuner *t, unsigned int freq) { - struct tda9887_priv *priv = fe->analog_demod_priv; - - priv->config = *(unsigned int *)priv_cfg; - tda9887_configure(fe); - - return 0; + tda9887_configure(t); } -static void tda9887_release(struct dvb_frontend *fe) +static void tda9887_release(struct tuner *t) { - kfree(fe->analog_demod_priv); - fe->analog_demod_priv = NULL; + kfree(t->priv); + t->priv = NULL; } -static struct analog_demod_ops tda9887_ops = { - .info = { - .name = "tda9887", - }, - .set_params = tda9887_set_params, +static struct tuner_operations tda9887_tuner_ops = { + .set_tv_freq = tda9887_set_freq, + .set_radio_freq = tda9887_set_freq, .standby = tda9887_standby, .tuner_status = tda9887_tuner_status, .get_afc = tda9887_get_afc, .release = tda9887_release, - .set_config = tda9887_set_config, }; -struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr) +int tda9887_tuner_init(struct tuner *t) { struct tda9887_priv *priv = NULL; priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) - return NULL; - fe->analog_demod_priv = priv; + return -ENOMEM; + t->priv = priv; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->mode = T_STANDBY; + priv->i2c_props.addr = t->i2c.addr; + priv->i2c_props.adap = t->i2c.adapter; - tuner_info("tda988[5/6/7] found\n"); + strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); - memcpy(&fe->ops.analog_ops, &tda9887_ops, - sizeof(struct analog_demod_ops)); + tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, + t->i2c.driver->driver.name); - return fe; -} -EXPORT_SYMBOL_GPL(tda9887_attach); + memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations)); -MODULE_LICENSE("GPL"); + return 0; +} /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/trunk/drivers/media/video/tda9887.h b/trunk/drivers/media/video/tda9887.h deleted file mode 100644 index 8f873a8e6ed2..000000000000 --- a/trunk/drivers/media/video/tda9887.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - 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 __TDA9887_H__ -#define __TDA9887_H__ - -#include -#include "dvb_frontend.h" - -/* ------------------------------------------------------------------------ */ -#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) -extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr); -#else -static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr) -{ - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); - return NULL; -} -#endif - -#endif /* __TDA9887_H__ */ diff --git a/trunk/drivers/media/video/tea5761.c b/trunk/drivers/media/video/tea5761.c index 5326eeceaacd..2150222a3860 100644 --- a/trunk/drivers/media/video/tea5761.c +++ b/trunk/drivers/media/video/tea5761.c @@ -18,7 +18,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5761" +#define PREFIX "tea5761 " struct tea5761_priv { struct tuner_i2c_props i2c_props; diff --git a/trunk/drivers/media/video/tea5767.c b/trunk/drivers/media/video/tea5767.c index e1b48d87e7b7..71df419df7bc 100644 --- a/trunk/drivers/media/video/tea5767.c +++ b/trunk/drivers/media/video/tea5767.c @@ -20,14 +20,12 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5767" - -/*****************************************************************************/ +#define PREFIX "tea5767 " struct tea5767_priv { - struct tuner_i2c_props i2c_props; - u32 frequency; - struct tea5767_ctrl ctrl; + struct tuner_i2c_props i2c_props; + + u32 frequency; }; /*****************************************************************************/ @@ -129,10 +127,17 @@ struct tea5767_priv { /* Reserved for future extensions */ #define TEA5767_RESERVED_MASK 0xff +enum tea5767_xtal_freq { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + + /*****************************************************************************/ -static void tea5767_status_dump(struct tea5767_priv *priv, - unsigned char *buffer) +static void tea5767_status_dump(unsigned char *buffer) { unsigned int div, frq; @@ -148,7 +153,7 @@ static void tea5767_status_dump(struct tea5767_priv *priv, div = ((buffer[0] & 0x3f) << 8) | buffer[1]; - switch (priv->ctrl.xtal_freq) { + switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ break; @@ -197,10 +202,13 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); - buffer[2] = 0; + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ - if (priv->ctrl.port1) - buffer[2] |= TEA5767_PORT1_HIGH; + buffer[2] = TEA5767_PORT1_HIGH; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | + TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; + buffer[4] = 0; if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); @@ -209,45 +217,18 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("TEA5767 set to stereo\n"); } - - buffer[3] = 0; - - if (priv->ctrl.port2) - buffer[3] |= TEA5767_PORT2_HIGH; - - if (priv->ctrl.high_cut) - buffer[3] |= TEA5767_HIGH_CUT_CTRL; - - if (priv->ctrl.st_noise) - buffer[3] |= TEA5767_ST_NOISE_CTL; - - if (priv->ctrl.soft_mute) - buffer[3] |= TEA5767_SOFT_MUTE; - - if (priv->ctrl.japan_band) - buffer[3] |= TEA5767_JAPAN_BAND; - - buffer[4] = 0; - - if (priv->ctrl.deemph_75) - buffer[4] |= TEA5767_DEEMPH_75; - - if (priv->ctrl.pllref) - buffer[4] |= TEA5767_PLLREF_ENABLE; - - - /* Rounds freq to next decimal value - for 62.5 KHz step */ - /* frq = 20*(frq/16)+radio_frq[frq%16]; */ - - switch (priv->ctrl.xtal_freq) { + /* Should be replaced */ + switch (TEA5767_HIGH_LO_32768) { case TEA5767_HIGH_LO_13MHz: tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; + buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_13MHz: tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); + buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_32768: @@ -275,7 +256,7 @@ static int set_radio_freq(struct dvb_frontend *fe, if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else - tea5767_status_dump(priv, buffer); + tea5767_status_dump(buffer); } priv->frequency = frq * 125 / 2; @@ -401,6 +382,7 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return EINVAL; } + printk(KERN_WARNING "TEA5767 detected.\n"); return 0; } @@ -416,16 +398,6 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5767_priv *priv = fe->tuner_priv; *frequency = priv->frequency; - - return 0; -} - -static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) -{ - struct tea5767_priv *priv = fe->tuner_priv; - - memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); - return 0; } @@ -435,7 +407,6 @@ static struct dvb_tuner_ops tea5767_tuner_ops = { }, .set_analog_params = set_radio_freq, - .set_config = tea5767_set_config, .sleep = tea5767_standby, .release = tea5767_release, .get_frequency = tea5767_get_frequency, @@ -454,14 +425,8 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return NULL; fe->tuner_priv = priv; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; - priv->ctrl.port1 = 1; - priv->ctrl.port2 = 1; - priv->ctrl.high_cut = 1; - priv->ctrl.st_noise = 1; - priv->ctrl.japan_band = 1; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -471,6 +436,7 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return fe; } + EXPORT_SYMBOL_GPL(tea5767_attach); EXPORT_SYMBOL_GPL(tea5767_autodetection); diff --git a/trunk/drivers/media/video/tea5767.h b/trunk/drivers/media/video/tea5767.h index a44451f61145..5d78281adcc2 100644 --- a/trunk/drivers/media/video/tea5767.h +++ b/trunk/drivers/media/video/tea5767.h @@ -20,25 +20,6 @@ #include #include "dvb_frontend.h" -enum tea5767_xtal { - TEA5767_LOW_LO_32768 = 0, - TEA5767_HIGH_LO_32768 = 1, - TEA5767_LOW_LO_13MHz = 2, - TEA5767_HIGH_LO_13MHz = 3, -}; - -struct tea5767_ctrl { - unsigned int port1:1; - unsigned int port2:1; - unsigned int high_cut:1; - unsigned int st_noise:1; - unsigned int soft_mute:1; - unsigned int japan_band:1; - unsigned int deemph_75:1; - unsigned int pllref:1; - enum tea5767_xtal xtal_freq; -}; - #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/trunk/drivers/media/video/tlv320aic23b.c b/trunk/drivers/media/video/tlv320aic23b.c index dc7b9c220b90..76b2e96429d9 100644 --- a/trunk/drivers/media/video/tlv320aic23b.c +++ b/trunk/drivers/media/video/tlv320aic23b.c @@ -31,7 +31,6 @@ #include #include #include -#include MODULE_DESCRIPTION("tlv320aic23b driver"); MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); @@ -57,35 +56,37 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val) return -1; } - for (i = 0; i < 3; i++) - if (i2c_smbus_write_byte_data(client, - (reg << 1) | (val >> 8), val & 0xff) == 0) + for (i = 0; i < 3; i++) { + if (i2c_smbus_write_byte_data(client, (reg << 1) | + (val >> 8), val & 0xff) == 0) { return 0; + } + } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } -static int tlv320aic23b_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, + void *arg) { struct tlv320aic23b_state *state = i2c_get_clientdata(client); struct v4l2_control *ctrl = arg; - u32 *freq = arg; + u32* freq = arg; switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: switch (*freq) { - case 32000: /* set sample rate to 32 kHz */ - tlv320aic23b_write(client, 8, 0x018); - break; - case 44100: /* set sample rate to 44.1 kHz */ - tlv320aic23b_write(client, 8, 0x022); - break; - case 48000: /* set sample rate to 48 kHz */ - tlv320aic23b_write(client, 8, 0x000); - break; - default: - return -EINVAL; + case 32000: /* set sample rate to 32 kHz */ + tlv320aic23b_write(client, 8, 0x018); + break; + case 44100: /* set sample rate to 44.1 kHz */ + tlv320aic23b_write(client, 8, 0x022); + break; + case 48000: /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 8, 0x000); + break; + default: + return -EINVAL; } break; @@ -125,53 +126,92 @@ static int tlv320aic23b_command(struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int tlv320aic23b_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct tlv320aic23b_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b"); - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); - if (state == NULL) + if (state == NULL) { + kfree(client); return -ENOMEM; + } state->muted = 0; i2c_set_clientdata(client, state); - /* Initialize tlv320aic23b */ - - /* RESET */ - tlv320aic23b_write(client, 15, 0x000); - /* turn off DAC & mic input */ - tlv320aic23b_write(client, 6, 0x00A); - /* left-justified, 24-bit, master mode */ - tlv320aic23b_write(client, 7, 0x049); - /* set gain on both channels to +3.0 dB */ - tlv320aic23b_write(client, 0, 0x119); - /* set sample rate to 48 kHz */ - tlv320aic23b_write(client, 8, 0x000); - /* activate digital interface */ - tlv320aic23b_write(client, 9, 0x001); + /* initialize tlv320aic23b */ + tlv320aic23b_write(client, 15, 0x000); /* RESET */ + tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */ + tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */ + tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */ + tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */ + + i2c_attach_client(client); + return 0; } -static int tlv320aic23b_remove(struct i2c_client *client) +static int tlv320aic23b_probe(struct i2c_adapter *adapter) { - kfree(i2c_get_clientdata(client)); + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, tlv320aic23b_attach); return 0; } -/* ----------------------------------------------------------------------- */ +static int tlv320aic23b_detach(struct i2c_client *client) +{ + int err; + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(client); -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "tlv320aic23b", - .driverid = I2C_DRIVERID_TLV320AIC23B, - .command = tlv320aic23b_command, - .probe = tlv320aic23b_probe, - .remove = tlv320aic23b_remove, + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "tlv320aic23b", + }, + .id = I2C_DRIVERID_TLV320AIC23B, + .attach_adapter = tlv320aic23b_probe, + .detach_client = tlv320aic23b_detach, + .command = tlv320aic23b_command, }; + + +static int __init tlv320aic23b_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit tlv320aic23b_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(tlv320aic23b_init_module); +module_exit(tlv320aic23b_cleanup_module); diff --git a/trunk/drivers/media/video/tuner-core.c b/trunk/drivers/media/video/tuner-core.c index ba538f6fbcc3..9e99f3636d3d 100644 --- a/trunk/drivers/media/video/tuner-core.c +++ b/trunk/drivers/media/video/tuner-core.c @@ -19,41 +19,15 @@ #include #include #include -#include +#include "tuner-driver.h" #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" #include "tea5767.h" -#include "tuner-xc2028.h" #include "tuner-simple.h" -#include "tda9887.h" -#include "xc5000.h" #define UNSET (-1U) -#define PREFIX t->i2c->driver->driver.name - -struct tuner { - /* device */ - struct dvb_frontend fe; - struct i2c_client *i2c; - struct list_head list; - unsigned int using_v4l2:1; - - /* keep track of the current settings */ - v4l2_std_id std; - unsigned int tv_freq; - unsigned int radio_freq; - unsigned int audmode; - - unsigned int mode; - unsigned int mode_mask; /* Combination of allowable modes */ - - unsigned int type; /* chip type id */ - unsigned int config; - int (*tuner_callback) (void *dev, int command, int arg); -}; - /* standard i2c insmod options */ static unsigned short normal_i2c[] = { #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) @@ -73,34 +47,7 @@ static unsigned int no_autodetect = 0; static unsigned int show_i2c = 0; /* insmod options used at runtime => read/write */ -static int tuner_debug; - -#define tuner_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_dbg(fmt, arg...) do { \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -/* ------------------------------------------------------------------------ */ +int tuner_debug = 0; static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; @@ -124,96 +71,66 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); +static struct i2c_driver driver; +static struct i2c_client client_template; + /* ---------------------------------------------------------------------- */ -static void fe_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static void fe_set_freq(struct tuner *t, unsigned int freq) { - struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; - struct tuner *t = fe->analog_demod_priv; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + struct analog_parameters params = { + .frequency = freq, + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; if (NULL == fe_tuner_ops->set_analog_params) { tuner_warn("Tuner frontend module has no way to set freq\n"); return; } - fe_tuner_ops->set_analog_params(fe, params); + fe_tuner_ops->set_analog_params(&t->fe, ¶ms); } -static void fe_release(struct dvb_frontend *fe) +static void fe_release(struct tuner *t) { - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - - /* DO NOT kfree(fe->analog_demod_priv) - * - * If we are in this function, analog_demod_priv contains a pointer - * to struct tuner *t. This will be kfree'd in tuner_detach(). - * - * Otherwise, fe->ops.analog_demod_ops->release will - * handle the cleanup for analog demodulator modules. - */ - fe->analog_demod_priv = NULL; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + + if (fe_tuner_ops->release) + fe_tuner_ops->release(&t->fe); } -static void fe_standby(struct dvb_frontend *fe) +static void fe_standby(struct tuner *t) { - struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; if (fe_tuner_ops->sleep) - fe_tuner_ops->sleep(fe); + fe_tuner_ops->sleep(&t->fe); } -static int fe_has_signal(struct dvb_frontend *fe) +static int fe_has_signal(struct tuner *t) { + struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; u16 strength = 0; - if (fe->ops.tuner_ops.get_rf_strength) - fe->ops.tuner_ops.get_rf_strength(fe, &strength); + if (fe_tuner_ops->get_rf_strength) + fe_tuner_ops->get_rf_strength(&t->fe, &strength); return strength; } -static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; - struct tuner *t = fe->analog_demod_priv; - - if (fe_tuner_ops->set_config) - return fe_tuner_ops->set_config(fe, priv_cfg); - - tuner_warn("Tuner frontend module has no way to set config\n"); - - return 0; -} - -static void tuner_status(struct dvb_frontend *fe); - -static struct analog_demod_ops tuner_core_ops = { - .set_params = fe_set_params, - .standby = fe_standby, - .release = fe_release, - .has_signal = fe_has_signal, - .set_config = fe_set_config, - .tuner_status = tuner_status -}; - /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - struct analog_parameters params = { - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == analog_ops->set_params) { + if (NULL == t->ops.set_tv_freq) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -228,27 +145,18 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - params.frequency = freq; - - analog_ops->set_params(&t->fe, ¶ms); + t->ops.set_tv_freq(t, freq); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - struct analog_parameters params = { - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == analog_ops->set_params) { + if (NULL == t->ops.set_radio_freq) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -263,9 +171,8 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) else freq = radio_range[1] * 16000; } - params.frequency = freq; - analog_ops->set_params(&t->fe, ¶ms); + t->ops.set_radio_freq(t, freq); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -286,65 +193,54 @@ static void set_freq(struct i2c_client *c, unsigned long freq) set_tv_freq(c, freq); t->tv_freq = freq; break; - default: - tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); } } static void tuner_i2c_address_check(struct tuner *t) { if ((t->type == UNSET || t->type == TUNER_ABSENT) || - ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f))) - return; - - /* We already know that the XC5000 can only be located at - * i2c address 0x61, 0x62, 0x63 or 0x64 */ - if ((t->type == TUNER_XC5000) && - ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61)) + ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) return; tuner_warn("====================== WARNING! ======================\n"); tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); tuner_warn("will soon be dropped. This message indicates that your\n"); tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", - t->i2c->name, t->i2c->addr); + t->i2c.name, t->i2c.addr); tuner_warn("To ensure continued support for your device, please\n"); tuner_warn("send a copy of this message, along with full dmesg\n"); tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", - t->i2c->adapter->name, t->i2c->addr, t->type, + t->i2c.adapter->name, t->i2c.addr, t->type, tuners[t->type].name); tuner_warn("====================== WARNING! ======================\n"); } -static void attach_simple_tuner(struct tuner *t) +static void attach_tda8290(struct tuner *t) { - struct simple_tuner_config cfg = { - .type = t->type, - .tun = &tuners[t->type] + struct tda8290_config cfg = { + .lna_cfg = &t->config, + .tuner_callback = t->tuner_callback }; - simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); + tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); } -static void attach_tda829x(struct tuner *t) +static void attach_simple_tuner(struct tuner *t) { - struct tda829x_config cfg = { - .lna_cfg = &t->config, - .tuner_callback = t->tuner_callback, + struct simple_tuner_config cfg = { + .type = t->type, + .tun = &tuners[t->type] }; - tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); + simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); } -static struct xc5000_config xc5000_cfg; - static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) { struct tuner *t = i2c_get_clientdata(c); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -364,27 +260,32 @@ static void set_type(struct i2c_client *c, unsigned int type, t->tuner_callback = tuner_callback; } - if (t->mode == T_UNINITIALIZED) { + /* This code detects calls by card attach_inform */ + if (NULL == t->i2c.dev.driver) { tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); return; } /* discard private data, in case set_type() was previously called */ - if (analog_ops->release) - analog_ops->release(&t->fe); + if (t->ops.release) + t->ops.release(t); + else { + kfree(t->priv); + t->priv = NULL; + } switch (t->type) { case TUNER_MT2032: - microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); break; case TUNER_PHILIPS_TDA8290: { - attach_tda829x(t); + attach_tda8290(t); break; } case TUNER_TEA5767: - if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { + if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -392,7 +293,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->mode_mask = T_RADIO; break; case TUNER_TEA5761: - if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { + if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -419,60 +320,25 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c,buffer,4); attach_simple_tuner(t); break; - case TUNER_XC2028: - { - struct xc2028_config cfg = { - .i2c_adap = t->i2c->adapter, - .i2c_addr = t->i2c->addr, - .video_dev = c->adapter->algo_data, - .callback = t->tuner_callback, - }; - if (!xc2028_attach(&t->fe, &cfg)) { - t->type = TUNER_ABSENT; - t->mode_mask = T_UNINITIALIZED; - return; - } - break; - } case TUNER_TDA9887: - tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); - break; - case TUNER_XC5000: - xc5000_cfg.i2c_address = t->i2c->addr; - xc5000_cfg.if_khz = 5380; - xc5000_cfg.priv = c->adapter->algo_data; - xc5000_cfg.tuner_callback = t->tuner_callback; - if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) { - t->type = TUNER_ABSENT; - t->mode_mask = T_UNINITIALIZED; - return; - } - { - struct dvb_tuner_ops *xc_tuner_ops; - xc_tuner_ops = &t->fe.ops.tuner_ops; - if(xc_tuner_ops->init != NULL) - xc_tuner_ops->init(&t->fe); - } + tda9887_tuner_init(t); break; default: attach_simple_tuner(t); break; } - if ((NULL == analog_ops->set_params) && - (fe_tuner_ops->set_analog_params)) { - strlcpy(t->i2c->name, fe_tuner_ops->info.name, - sizeof(t->i2c->name)); + if (fe_tuner_ops->set_analog_params) { + strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); - t->fe.analog_demod_priv = t; - memcpy(analog_ops, &tuner_core_ops, - sizeof(struct analog_demod_ops)); - } else { - strlcpy(t->i2c->name, analog_ops->info.name, - sizeof(t->i2c->name)); + t->ops.set_tv_freq = fe_set_freq; + t->ops.set_radio_freq = fe_set_freq; + t->ops.standby = fe_standby; + t->ops.release = fe_release; + t->ops.has_signal = fe_has_signal; } - tuner_dbg("type set to %s\n", t->i2c->name); + tuner_info("type set to %s\n", t->i2c.name); if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -642,12 +508,10 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct dvb_frontend *fe) +static void tuner_status(struct tuner *t) { - struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; const char *p; switch (t->mode) { @@ -677,16 +541,172 @@ static void tuner_status(struct dvb_frontend *fe) if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } - if (analog_ops->has_signal) - tuner_info("Signal strength: %d\n", - analog_ops->has_signal(fe)); - if (analog_ops->is_stereo) - tuner_info("Stereo: %s\n", - analog_ops->is_stereo(fe) ? "yes" : "no"); + if (t->ops.has_signal) { + tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); + } + if (t->ops.is_stereo) { + tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); + } } /* ---------------------------------------------------------------------- */ +/* static vars: used only in tuner_attach and tuner_probe */ +static unsigned default_mode_mask; + +/* During client attach, set_type is called by adapter's attach_inform callback. + set_type must then be completed by tuner_attach. + */ +static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) +{ + struct tuner *t; + + client_template.adapter = adap; + client_template.addr = addr; + + t = kzalloc(sizeof(struct tuner), GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); + i2c_set_clientdata(&t->i2c, t); + t->type = UNSET; + t->audmode = V4L2_TUNER_MODE_STEREO; + t->mode_mask = T_UNINITIALIZED; + t->ops.tuner_status = tuner_status; + + if (show_i2c) { + unsigned char buffer[16]; + int i,rc; + + memset(buffer, 0, sizeof(buffer)); + rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer)); + tuner_info("I2C RECV = "); + for (i=0;iid == I2C_HW_SAA7146 && addr < 0x4a) + return -ENODEV; + + /* autodetection code based on the i2c addr */ + if (!no_autodetect) { + switch (addr) { + case 0x10: + if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { + t->type = TUNER_TEA5761; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + default_mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + case 0x42: + case 0x43: + case 0x4a: + case 0x4b: + /* If chip is not tda8290, don't register. + since it can be tda9887*/ + if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { + tuner_dbg("chip at addr %x is a tda8290\n", addr); + } else { + /* Default is being tda9887 */ + t->type = TUNER_TDA9887; + t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + t->mode = T_STANDBY; + goto register_client; + } + break; + case 0x60: + if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { + t->type = TUNER_TEA5767; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + default_mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + } + } + + /* Initializes only the first adapter found */ + if (default_mode_mask != T_UNINITIALIZED) { + tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); + t->mode_mask = default_mode_mask; + t->tv_freq = 400 * 16; /* Sets freq to VHF High */ + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + default_mode_mask = T_UNINITIALIZED; + } + + /* Should be just before return */ +register_client: + tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); + i2c_attach_client (&t->i2c); + set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); + return 0; +} + +static int tuner_probe(struct i2c_adapter *adap) +{ + if (0 != addr) { + normal_i2c[0] = addr; + normal_i2c[1] = I2C_CLIENT_END; + } + + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. + */ + if ((adap->id == I2C_HW_B_CX2388x) || + (adap->id == I2C_HW_B_CX23885)) { + unsigned int i = 0; + + while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) + i += 2; + if (i + 4 < I2C_CLIENT_MAX_OPTS) { + ignore[i+0] = adap->nr; + ignore[i+1] = 0x6b; + ignore[i+2] = adap->nr; + ignore[i+3] = 0x6f; + ignore[i+4] = I2C_CLIENT_END; + } else + printk(KERN_WARNING "tuner: " + "too many options specified " + "in i2c probe ignore list!\n"); + } + + default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; + + if (adap->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, tuner_attach); + return 0; +} + +static int tuner_detach(struct i2c_client *client) +{ + struct tuner *t = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(&t->i2c); + if (err) { + tuner_warn + ("Client deregistration failed, client not detached.\n"); + return err; + } + + if (t->ops.release) + t->ops.release(t); + else { + kfree(t->priv); + } + kfree(t); + return 0; +} + /* * Switch tuner to other mode. If tuner support both tv and radio, * set another frequency to some value (This is needed for some pal @@ -696,8 +716,6 @@ static void tuner_status(struct dvb_frontend *fe) static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (mode == t->mode) return 0; @@ -705,8 +723,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if (analog_ops->standby) - analog_ops->standby(&t->fe); + if (t->ops.standby) + t->ops.standby(t); return EINVAL; } return 0; @@ -729,10 +747,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; if (tuner_debug>1) - v4l_i2c_print_ioctl(client,cmd); + v4l_i2c_print_ioctl(&(t->i2c),cmd); switch (cmd) { /* --- configuration --- */ @@ -756,8 +773,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; t->mode = T_STANDBY; - if (analog_ops->standby) - analog_ops->standby(&t->fe); + if (t->ops.standby) + t->ops.standby(t); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -825,8 +842,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { - if (analog_ops->is_stereo) { - if (analog_ops->is_stereo(&t->fe)) + if (t->ops.is_stereo) { + if (t->ops.is_stereo(t)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -834,9 +851,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ~VIDEO_TUNER_STEREO_ON; } } - if (analog_ops->has_signal) - vt->signal = - analog_ops->has_signal(&t->fe); + if (t->ops.has_signal) + vt->signal = t->ops.has_signal(t); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -866,28 +882,21 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); va->mode = (tuner_status & TUNER_STATUS_STEREO) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - } else if (analog_ops->is_stereo) - va->mode = analog_ops->is_stereo(&t->fe) + } else if (t->ops.is_stereo) + va->mode = t->ops.is_stereo(t) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } return 0; } #endif - case TUNER_SET_CONFIG: - { - struct v4l2_priv_tun_config *cfg = arg; + case TDA9887_SET_CONFIG: + if (t->type == TUNER_TDA9887) { + int *i = arg; - if (t->type != cfg->tuner) - break; - - if (analog_ops->set_config) { - analog_ops->set_config(&t->fe, cfg->priv); - break; + t->tda9887_config = *i; + set_freq(client, t->tv_freq); } - - tuner_dbg("Tuner frontend module has no way to set config\n"); break; - } /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -949,8 +958,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; - if (analog_ops->get_afc) - tuner->afc = analog_ops->get_afc(&t->fe); + if (t->ops.get_afc) + tuner->afc=t->ops.get_afc(t); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -966,20 +975,16 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); - tuner->rxsubchans = - (tuner_status & TUNER_STATUS_STEREO) ? - V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; + tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } else { - if (analog_ops->is_stereo) { - tuner->rxsubchans = - analog_ops->is_stereo(&t->fe) ? - V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; + if (t->ops.is_stereo) { + tuner->rxsubchans = t->ops.is_stereo(t) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } } - if (analog_ops->has_signal) - tuner->signal = analog_ops->has_signal(&t->fe); + if (t->ops.has_signal) + tuner->signal = t->ops.has_signal(t); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; @@ -1004,8 +1009,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } case VIDIOC_LOG_STATUS: - if (analog_ops->tuner_status) - analog_ops->tuner_status(&t->fe); + if (t->ops.tuner_status) + t->ops.tuner_status(t); break; } @@ -1014,18 +1019,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) static int tuner_suspend(struct i2c_client *c, pm_message_t state) { - struct tuner *t = i2c_get_clientdata(c); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("suspend\n"); + tuner_dbg ("suspend\n"); /* FIXME: power down ??? */ return 0; } static int tuner_resume(struct i2c_client *c) { - struct tuner *t = i2c_get_clientdata(c); + struct tuner *t = i2c_get_clientdata (c); - tuner_dbg("resume\n"); + tuner_dbg ("resume\n"); if (V4L2_TUNER_RADIO == t->mode) { if (t->radio_freq) set_freq(c, t->radio_freq); @@ -1036,227 +1041,36 @@ static int tuner_resume(struct i2c_client *c) return 0; } -/* ---------------------------------------------------------------------- */ - -LIST_HEAD(tuner_list); - -/* Search for existing radio and/or TV tuners on the given I2C adapter. - Note that when this function is called from tuner_probe you can be - certain no other devices will be added/deleted at the same time, I2C - core protects against that. */ -static void tuner_lookup(struct i2c_adapter *adap, - struct tuner **radio, struct tuner **tv) -{ - struct tuner *pos; - - *radio = NULL; - *tv = NULL; - - list_for_each_entry(pos, &tuner_list, list) { - int mode_mask; - - if (pos->i2c->adapter != adap || - pos->i2c->driver->id != I2C_DRIVERID_TUNER) - continue; - - mode_mask = pos->mode_mask & ~T_STANDBY; - if (*radio == NULL && mode_mask == T_RADIO) - *radio = pos; - /* Note: currently TDA9887 is the only demod-only - device. If other devices appear then we need to - make this test more general. */ - else if (*tv == NULL && pos->type != TUNER_TDA9887 && - (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) - *tv = pos; - } -} - -/* During client attach, set_type is called by adapter's attach_inform callback. - set_type must then be completed by tuner_probe. - */ -static int tuner_probe(struct i2c_client *client) -{ - struct tuner *t; - struct tuner *radio; - struct tuner *tv; - - t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - t->i2c = client; - strlcpy(client->name, "(tuner unset)", sizeof(client->name)); - i2c_set_clientdata(client, t); - t->type = UNSET; - t->audmode = V4L2_TUNER_MODE_STEREO; - t->mode_mask = T_UNINITIALIZED; - - if (show_i2c) { - unsigned char buffer[16]; - int i, rc; - - memset(buffer, 0, sizeof(buffer)); - rc = i2c_master_recv(client, buffer, sizeof(buffer)); - tuner_info("I2C RECV = "); - for (i = 0; i < rc; i++) - printk(KERN_CONT "%02x ", buffer[i]); - printk("\n"); - } - /* HACK: This test was added to avoid tuner to probe tda9840 and - tea6415c on the MXB card */ - if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) { - kfree(t); - return -ENODEV; - } - - /* autodetection code based on the i2c addr */ - if (!no_autodetect) { - switch (client->addr) { - case 0x10: - if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) - != EINVAL) { - t->type = TUNER_TEA5761; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - /* Sets freq to FM range */ - t->radio_freq = 87.5 * 16000; - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - case 0x42: - case 0x43: - case 0x4a: - case 0x4b: - /* If chip is not tda8290, don't register. - since it can be tda9887*/ - if (tda829x_probe(t->i2c->adapter, - t->i2c->addr) == 0) { - tuner_dbg("tda829x detected\n"); - } else { - /* Default is being tda9887 */ - t->type = TUNER_TDA9887; - t->mode_mask = T_RADIO | T_ANALOG_TV | - T_DIGITAL_TV; - t->mode = T_STANDBY; - goto register_client; - } - break; - case 0x60: - if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) - != EINVAL) { - t->type = TUNER_TEA5767; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - /* Sets freq to FM range */ - t->radio_freq = 87.5 * 16000; - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - } - } - - /* Initializes only the first TV tuner on this adapter. Why only the - first? Because there are some devices (notably the ones with TI - tuners) that have more than one i2c address for the *same* device. - Experience shows that, except for just one case, the first - address is the right one. The exception is a Russian tuner - (ACORP_Y878F). So, the desired behavior is just to enable the - first found TV tuner. */ - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv == NULL) { - t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - if (radio == NULL) - t->mode_mask |= T_RADIO; - tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); - t->tv_freq = 400 * 16; /* Sets freq to VHF High */ - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - } +/* ----------------------------------------------------------------------- */ - /* Should be just before return */ -register_client: - tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1, - client->adapter->name); - - /* Sets a default mode */ - if (t->mode_mask & T_ANALOG_TV) { - t->mode = V4L2_TUNER_ANALOG_TV; - } else if (t->mode_mask & T_RADIO) { - t->mode = V4L2_TUNER_RADIO; - } else { - t->mode = V4L2_TUNER_DIGITAL_TV; - } - set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback); - list_add_tail(&t->list, &tuner_list); - return 0; -} +static struct i2c_driver driver = { + .id = I2C_DRIVERID_TUNER, + .attach_adapter = tuner_probe, + .detach_client = tuner_detach, + .command = tuner_command, + .suspend = tuner_suspend, + .resume = tuner_resume, + .driver = { + .name = "tuner", + }, +}; +static struct i2c_client client_template = { + .name = "(tuner unset)", + .driver = &driver, +}; -static int tuner_legacy_probe(struct i2c_adapter *adap) +static int __init tuner_init_module(void) { - if (0 != addr) { - normal_i2c[0] = addr; - normal_i2c[1] = I2C_CLIENT_END; - } - - if ((adap->class & I2C_CLASS_TV_ANALOG) == 0) - return 0; - - /* HACK: Ignore 0x6b and 0x6f on cx88 boards. - * FusionHDTV5 RT Gold has an ir receiver at 0x6b - * and an RTC at 0x6f which can get corrupted if probed. - */ - if ((adap->id == I2C_HW_B_CX2388x) || - (adap->id == I2C_HW_B_CX23885)) { - unsigned int i = 0; - - while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) - i += 2; - if (i + 4 < I2C_CLIENT_MAX_OPTS) { - ignore[i+0] = adap->nr; - ignore[i+1] = 0x6b; - ignore[i+2] = adap->nr; - ignore[i+3] = 0x6f; - ignore[i+4] = I2C_CLIENT_END; - } else - printk(KERN_WARNING "tuner: " - "too many options specified " - "in i2c probe ignore list!\n"); - } - return 1; + return i2c_add_driver(&driver); } -static int tuner_remove(struct i2c_client *client) +static void __exit tuner_cleanup_module(void) { - struct tuner *t = i2c_get_clientdata(client); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - if (analog_ops->release) - analog_ops->release(&t->fe); - - list_del(&t->list); - kfree(t); - return 0; + i2c_del_driver(&driver); } -/* ----------------------------------------------------------------------- */ - -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "tuner", - .driverid = I2C_DRIVERID_TUNER, - .command = tuner_command, - .probe = tuner_probe, - .remove = tuner_remove, - .suspend = tuner_suspend, - .resume = tuner_resume, - .legacy_probe = tuner_legacy_probe, -}; - +module_init(tuner_init_module); +module_exit(tuner_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/trunk/drivers/media/video/tuner-driver.h b/trunk/drivers/media/video/tuner-driver.h new file mode 100644 index 000000000000..28a10da76d12 --- /dev/null +++ b/trunk/drivers/media/video/tuner-driver.h @@ -0,0 +1,99 @@ +/* + tuner-driver.h - interface for different tuners + + Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) + minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de) + + 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 __TUNER_DRIVER_H__ +#define __TUNER_DRIVER_H__ + +#include +#include +#include "tuner-i2c.h" +#include "dvb_frontend.h" + +extern unsigned const int tuner_count; + +struct tuner; + +struct tuner_operations { + void (*set_tv_freq)(struct tuner *t, unsigned int freq); + void (*set_radio_freq)(struct tuner *t, unsigned int freq); + int (*has_signal)(struct tuner *t); + int (*is_stereo)(struct tuner *t); + int (*get_afc)(struct tuner *t); + void (*tuner_status)(struct tuner *t); + void (*standby)(struct tuner *t); + void (*release)(struct tuner *t); +}; + +struct tuner { + /* device */ + struct i2c_client i2c; + + unsigned int type; /* chip type */ + + unsigned int mode; + unsigned int mode_mask; /* Combination of allowable modes */ + + unsigned int tv_freq; /* keep track of the current settings */ + unsigned int radio_freq; + unsigned int audmode; + v4l2_std_id std; + + int using_v4l2; + void *priv; + + struct dvb_frontend fe; + + /* used by tda9887 */ + unsigned int tda9887_config; + + unsigned int config; + int (*tuner_callback) (void *dev, int command,int arg); + + struct tuner_operations ops; +}; + +/* ------------------------------------------------------------------------ */ + +extern int tda9887_tuner_init(struct tuner *t); + +/* ------------------------------------------------------------------------ */ + +#define tuner_warn(fmt, arg...) do {\ + printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +#define tuner_info(fmt, arg...) do {\ + printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +#define tuner_dbg(fmt, arg...) do {\ + extern int tuner_debug; \ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ + i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) + +#endif /* __TUNER_DRIVER_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/trunk/drivers/media/video/tuner-i2c.h b/trunk/drivers/media/video/tuner-i2c.h index de52e8ffd347..159019ec3373 100644 --- a/trunk/drivers/media/video/tuner-i2c.h +++ b/trunk/drivers/media/video/tuner-i2c.h @@ -46,42 +46,25 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, return (ret == 1) ? len : ret; } -static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, - char *obuf, int olen, - char *ibuf, int ilen) -{ - struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, - .buf = obuf, .len = olen }, - { .addr = props->addr, .flags = I2C_M_RD, - .buf = ibuf, .len = ilen } }; - int ret = i2c_transfer(props->adap, msg, 2); - - return (ret == 2) ? ilen : ret; -} - -#define tuner_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(priv->i2c_props.adap), \ - priv->i2c_props.addr, ##arg); \ - } while (0) - -#define tuner_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(priv->i2c_props.adap), \ - priv->i2c_props.addr , ##arg); \ - } while (0) - -#define tuner_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(priv->i2c_props.adap), \ - priv->i2c_props.addr , ##arg); \ - } while (0) - -#define tuner_dbg(fmt, arg...) do { \ - if ((debug)) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(priv->i2c_props.adap), \ - priv->i2c_props.addr , ##arg); \ - } while (0) +#ifndef __TUNER_DRIVER_H__ +#define tuner_warn(fmt, arg...) do {\ + printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_info(fmt, arg...) do {\ + printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#define tuner_dbg(fmt, arg...) do {\ + if ((debug)) \ + printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ + i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) +#endif /* __TUNER_DRIVER_H__ */ #endif /* __TUNER_I2C_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/trunk/drivers/media/video/tuner-simple.c b/trunk/drivers/media/video/tuner-simple.c index c1db576696c6..7b93d3b1f4c6 100644 --- a/trunk/drivers/media/video/tuner-simple.c +++ b/trunk/drivers/media/video/tuner-simple.c @@ -17,7 +17,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tuner-simple" +#define PREFIX "tuner-simple " static int offset = 0; module_param(offset, int, 0664); @@ -355,14 +355,10 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } priv->last_div = div; if (t_params->has_tda9887) { - struct v4l2_priv_tun_config tda9887_cfg; int config = 0; int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &config; - if (params->std == V4L2_STD_SECAM_LC) { if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) config |= TDA9887_PORT1_ACTIVE; @@ -395,8 +391,7 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } if (t_params->default_pll_gating_18) config |= TDA9887_GATING_18; - i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, - &tda9887_cfg); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); @@ -539,11 +534,6 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, if (t_params->has_tda9887) { int config = 0; - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &config; - if (t_params->port1_active && !t_params->port1_fm_high_sensitivity) config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active && !t_params->port2_fm_high_sensitivity) @@ -556,8 +546,7 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, config |= TDA9887_GAIN_NORMAL; if (t_params->radio_if == 2) config |= TDA9887_RIF_41_3; - i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, - &tda9887_cfg); + i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); } if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); diff --git a/trunk/drivers/media/video/tuner-types.c b/trunk/drivers/media/video/tuner-types.c index 883047f9c28c..c6a7934bd5a6 100644 --- a/trunk/drivers/media/video/tuner-types.c +++ b/trunk/drivers/media/video/tuner-types.c @@ -1366,7 +1366,7 @@ struct tunertype tuners[] = { .count = ARRAY_SIZE(tuner_philips_fq1286_params), }, [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ - .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", + .name = "tda8290+75", /* see tda8290.c for details */ }, [TUNER_TCL_2002MB] = { /* TCL PAL */ .name = "TCL 2002MB", @@ -1452,9 +1452,9 @@ struct tunertype tuners[] = { .params = tuner_samsung_tcpn_2121p30a_params, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), }, - [TUNER_XC2028] = { /* Xceive 2028 */ - .name = "Xceive xc2028/xc3028 tuner", - /* see tuner-xc2028.c for details */ + [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */ + .name = "Xceive xc3028", + /* see xc3028.c for details */ }, [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ .name = "Thomson FE6600", @@ -1475,10 +1475,6 @@ struct tunertype tuners[] = { .name = "Philips TEA5761 FM Radio", /* see tea5767.c for details */ }, - [TUNER_XC5000] = { /* Xceive 5000 */ - .name = "Xceive 5000 tuner", - /* see xc5000.c for details */ - }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/trunk/drivers/media/video/tuner-xc2028-types.h b/trunk/drivers/media/video/tuner-xc2028-types.h deleted file mode 100644 index d0057fbf0ec7..000000000000 --- a/trunk/drivers/media/video/tuner-xc2028-types.h +++ /dev/null @@ -1,128 +0,0 @@ -/* tuner-xc2028_types - * - * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -/* xc3028 firmware types */ - -/* BASE firmware should be loaded before any other firmware */ -#define BASE (1<<0) -#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) - -/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ -#define F8MHZ (1<<1) - -/* Multichannel Television Sound (MTS) - Those firmwares are capable of using xc2038 DSP to decode audio and - produce a baseband audio output on some pins of the chip. - There are MTS firmwares for the most used video standards. It should be - required to use MTS firmwares, depending on the way audio is routed into - the bridge chip - */ -#define MTS (1<<2) - -/* FIXME: I have no idea what's the difference between - D2620 and D2633 firmwares - */ -#define D2620 (1<<3) -#define D2633 (1<<4) - -/* DTV firmwares for 6, 7 and 8 MHz - DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS - DTV8 - 8MHz - DVB-C/DVB-T - */ -#define DTV6 (1 << 5) -#define QAM (1 << 6) -#define DTV7 (1<<7) -#define DTV78 (1<<8) -#define DTV8 (1<<9) - -#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) - -/* There's a FM | BASE firmware + FM specific firmware (std=0) */ -#define FM (1<<10) - -#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) - -/* Applies only for FM firmware - Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) - */ -#define INPUT1 (1<<11) - - -/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) - and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) - There are variants both with and without NOGD - */ -#define LCD (1<<12) - -/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) - and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) - */ -#define NOGD (1<<13) - -/* Old firmwares were broken into init0 and init1 */ -#define INIT1 (1<<14) - -/* SCODE firmware selects particular behaviours */ -#define MONO (1 << 15) -#define ATSC (1 << 16) -#define IF (1 << 17) -#define LG60 (1 << 18) -#define ATI638 (1 << 19) -#define OREN538 (1 << 20) -#define OREN36 (1 << 21) -#define TOYOTA388 (1 << 22) -#define TOYOTA794 (1 << 23) -#define DIBCOM52 (1 << 24) -#define ZARLINK456 (1 << 25) -#define CHINA (1 << 26) -#define F6MHZ (1 << 27) -#define INPUT2 (1 << 28) -#define SCODE (1 << 29) - -/* This flag identifies that the scode table has a new format */ -#define HAS_IF (1 << 30) - -#define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ - LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ - DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) - -/* Newer types to be moved to videodev2.h */ - -#define V4L2_STD_SECAM_K3 (0x04000000) - -/* Audio types */ - -#define V4L2_STD_A2_A (1LL<<32) -#define V4L2_STD_A2_B (1LL<<33) -#define V4L2_STD_NICAM_A (1LL<<34) -#define V4L2_STD_NICAM_B (1LL<<35) -#define V4L2_STD_AM (1LL<<36) -#define V4L2_STD_BTSC (1LL<<37) -#define V4L2_STD_EIAJ (1LL<<38) - -#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) -#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) - -/* To preserve backward compatibilty, - (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported - */ - -#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ - V4L2_STD_NICAM | \ - V4L2_STD_AM | \ - V4L2_STD_BTSC | \ - V4L2_STD_EIAJ) - -/* Used standards with audio restrictions */ - -#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) -#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) -#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) -#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) -#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) -#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) -#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) -#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff --git a/trunk/drivers/media/video/tuner-xc2028.c b/trunk/drivers/media/video/tuner-xc2028.c deleted file mode 100644 index f191f6a48070..000000000000 --- a/trunk/drivers/media/video/tuner-xc2028.c +++ /dev/null @@ -1,1213 +0,0 @@ -/* tuner-xc2028 - * - * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) - * - * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) - * - frontend interface - * - * This code is placed under the terms of the GNU General Public License v2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include "tuner-i2c.h" -#include "tuner-xc2028.h" -#include "tuner-xc2028-types.h" - -#include -#include "dvb_frontend.h" - - -#define PREFIX "xc2028" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable verbose debug messages"); - -static char audio_std[8]; -module_param_string(audio_std, audio_std, sizeof(audio_std), 0); -MODULE_PARM_DESC(audio_std, - "Audio standard. XC3028 audio decoder explicitly " - "needs to know what audio\n" - "standard is needed for some video standards with audio A2 or NICAM.\n" - "The valid values are:\n" - "A2\n" - "A2/A\n" - "A2/B\n" - "NICAM\n" - "NICAM/A\n" - "NICAM/B\n"); - -static LIST_HEAD(xc2028_list); -static DEFINE_MUTEX(xc2028_list_mutex); - -/* struct for storing firmware table */ -struct firmware_description { - unsigned int type; - v4l2_std_id id; - __u16 int_freq; - unsigned char *ptr; - unsigned int size; -}; - -struct firmware_properties { - unsigned int type; - v4l2_std_id id; - v4l2_std_id std_req; - __u16 int_freq; - unsigned int scode_table; - int scode_nr; -}; - -struct xc2028_data { - struct list_head xc2028_list; - struct tuner_i2c_props i2c_props; - int (*tuner_callback) (void *dev, - int command, int arg); - void *video_dev; - int count; - __u32 frequency; - - struct firmware_description *firm; - int firm_size; - __u16 firm_version; - - __u16 hwmodel; - __u16 hwvers; - - struct xc2028_ctrl ctrl; - - struct firmware_properties cur_fw; - - struct mutex lock; -}; - -#define i2c_send(priv, buf, size) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ - if (size != _rc) \ - tuner_info("i2c output error: rc = %d (should be %d)\n",\ - _rc, (int)size); \ - _rc; \ -}) - -#define i2c_rcv(priv, buf, size) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ - if (size != _rc) \ - tuner_err("i2c input error: rc = %d (should be %d)\n", \ - _rc, (int)size); \ - _rc; \ -}) - -#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ - int _rc; \ - _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ - ibuf, isize); \ - if (isize != _rc) \ - tuner_err("i2c input error: rc = %d (should be %d)\n", \ - _rc, (int)isize); \ - _rc; \ -}) - -#define send_seq(priv, data...) ({ \ - static u8 _val[] = data; \ - int _rc; \ - if (sizeof(_val) != \ - (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ - _val, sizeof(_val)))) { \ - tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ - } else \ - msleep(10); \ - _rc; \ -}) - -static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) -{ - unsigned char buf[2]; - unsigned char ibuf[2]; - - tuner_dbg("%s %04x called\n", __FUNCTION__, reg); - - buf[0] = reg >> 8; - buf[1] = (unsigned char) reg; - - if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) - return -EIO; - - *val = (ibuf[1]) | (ibuf[0] << 8); - return 0; -} - -#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) -void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) -{ - if (type & BASE) - printk("BASE "); - if (type & INIT1) - printk("INIT1 "); - if (type & F8MHZ) - printk("F8MHZ "); - if (type & MTS) - printk("MTS "); - if (type & D2620) - printk("D2620 "); - if (type & D2633) - printk("D2633 "); - if (type & DTV6) - printk("DTV6 "); - if (type & QAM) - printk("QAM "); - if (type & DTV7) - printk("DTV7 "); - if (type & DTV78) - printk("DTV78 "); - if (type & DTV8) - printk("DTV8 "); - if (type & FM) - printk("FM "); - if (type & INPUT1) - printk("INPUT1 "); - if (type & LCD) - printk("LCD "); - if (type & NOGD) - printk("NOGD "); - if (type & MONO) - printk("MONO "); - if (type & ATSC) - printk("ATSC "); - if (type & IF) - printk("IF "); - if (type & LG60) - printk("LG60 "); - if (type & ATI638) - printk("ATI638 "); - if (type & OREN538) - printk("OREN538 "); - if (type & OREN36) - printk("OREN36 "); - if (type & TOYOTA388) - printk("TOYOTA388 "); - if (type & TOYOTA794) - printk("TOYOTA794 "); - if (type & DIBCOM52) - printk("DIBCOM52 "); - if (type & ZARLINK456) - printk("ZARLINK456 "); - if (type & CHINA) - printk("CHINA "); - if (type & F6MHZ) - printk("F6MHZ "); - if (type & INPUT2) - printk("INPUT2 "); - if (type & SCODE) - printk("SCODE "); - if (type & HAS_IF) - printk("HAS_IF_%d ", int_freq); -} - -static v4l2_std_id parse_audio_std_option(void) -{ - if (strcasecmp(audio_std, "A2") == 0) - return V4L2_STD_A2; - if (strcasecmp(audio_std, "A2/A") == 0) - return V4L2_STD_A2_A; - if (strcasecmp(audio_std, "A2/B") == 0) - return V4L2_STD_A2_B; - if (strcasecmp(audio_std, "NICAM") == 0) - return V4L2_STD_NICAM; - if (strcasecmp(audio_std, "NICAM/A") == 0) - return V4L2_STD_NICAM_A; - if (strcasecmp(audio_std, "NICAM/B") == 0) - return V4L2_STD_NICAM_B; - - return 0; -} - -static void free_firmware(struct xc2028_data *priv) -{ - int i; - - if (!priv->firm) - return; - - for (i = 0; i < priv->firm_size; i++) - kfree(priv->firm[i].ptr); - - kfree(priv->firm); - - priv->firm = NULL; - priv->firm_size = 0; - - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); -} - -static int load_all_firmwares(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - const struct firmware *fw = NULL; - unsigned char *p, *endp; - int rc = 0; - int n, n_array; - char name[33]; - - tuner_dbg("%s called\n", __FUNCTION__); - - tuner_dbg("Reading firmware %s\n", priv->ctrl.fname); - rc = request_firmware(&fw, priv->ctrl.fname, - &priv->i2c_props.adap->dev); - if (rc < 0) { - if (rc == -ENOENT) - tuner_err("Error: firmware %s not found.\n", - priv->ctrl.fname); - else - tuner_err("Error %d while requesting firmware %s \n", - rc, priv->ctrl.fname); - - return rc; - } - p = fw->data; - endp = p + fw->size; - - if (fw->size < sizeof(name) - 1 + 2 + 2) { - tuner_err("Error: firmware file %s has invalid size!\n", - priv->ctrl.fname); - goto corrupt; - } - - memcpy(name, p, sizeof(name) - 1); - name[sizeof(name) - 1] = 0; - p += sizeof(name) - 1; - - priv->firm_version = le16_to_cpu(*(__u16 *) p); - p += 2; - - n_array = le16_to_cpu(*(__u16 *) p); - p += 2; - - tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", - n_array, priv->ctrl.fname, name, - priv->firm_version >> 8, priv->firm_version & 0xff); - - priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); - if (priv->firm == NULL) { - tuner_err("Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto err; - } - priv->firm_size = n_array; - - n = -1; - while (p < endp) { - __u32 type, size; - v4l2_std_id id; - __u16 int_freq = 0; - - n++; - if (n >= n_array) { - tuner_err("More firmware images in file than " - "were expected!\n"); - goto corrupt; - } - - /* Checks if there's enough bytes to read */ - if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) { - tuner_err("Firmware header is incomplete!\n"); - goto corrupt; - } - - type = le32_to_cpu(*(__u32 *) p); - p += sizeof(type); - - id = le64_to_cpu(*(v4l2_std_id *) p); - p += sizeof(id); - - if (type & HAS_IF) { - int_freq = le16_to_cpu(*(__u16 *) p); - p += sizeof(int_freq); - } - - size = le32_to_cpu(*(__u32 *) p); - p += sizeof(size); - - if ((!size) || (size + p > endp)) { - tuner_err("Firmware type "); - dump_firm_type(type); - printk("(%x), id %llx is corrupted " - "(size=%d, expected %d)\n", - type, (unsigned long long)id, - (unsigned)(endp - p), size); - goto corrupt; - } - - priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); - if (priv->firm[n].ptr == NULL) { - tuner_err("Not enough memory to load firmware file.\n"); - rc = -ENOMEM; - goto err; - } - tuner_dbg("Reading firmware type "); - if (debug) { - dump_firm_type_and_int_freq(type, int_freq); - printk("(%x), id %llx, size=%d.\n", - type, (unsigned long long)id, size); - } - - memcpy(priv->firm[n].ptr, p, size); - priv->firm[n].type = type; - priv->firm[n].id = id; - priv->firm[n].size = size; - priv->firm[n].int_freq = int_freq; - - p += size; - } - - if (n + 1 != priv->firm_size) { - tuner_err("Firmware file is incomplete!\n"); - goto corrupt; - } - - goto done; - -corrupt: - rc = -EINVAL; - tuner_err("Error: firmware file is corrupted!\n"); - -err: - tuner_info("Releasing partially loaded firmware file.\n"); - free_firmware(priv); - -done: - release_firmware(fw); - if (rc == 0) - tuner_dbg("Firmware files loaded.\n"); - - return rc; -} - -static int seek_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc2028_data *priv = fe->tuner_priv; - int i, best_i = -1, best_nr_matches = 0; - unsigned int ign_firm_type_mask = 0; - - tuner_dbg("%s called, want type=", __FUNCTION__); - if (debug) { - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); - } - - if (!priv->firm) { - tuner_err("Error! firmware not loaded\n"); - return -EINVAL; - } - - if (((type & ~SCODE) == 0) && (*id == 0)) - *id = V4L2_STD_PAL; - - if (type & BASE) - type &= BASE_TYPES; - else if (type & SCODE) { - type &= SCODE_TYPES; - ign_firm_type_mask = HAS_IF; - } else if (type & DTV_TYPES) - type &= DTV_TYPES; - else if (type & STD_SPECIFIC_TYPES) - type &= STD_SPECIFIC_TYPES; - - /* Seek for exact match */ - for (i = 0; i < priv->firm_size; i++) { - if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) && - (*id == priv->firm[i].id)) - goto found; - } - - /* Seek for generic video standard match */ - for (i = 0; i < priv->firm_size; i++) { - v4l2_std_id match_mask; - int nr_matches; - - if (type != (priv->firm[i].type & ~ign_firm_type_mask)) - continue; - - match_mask = *id & priv->firm[i].id; - if (!match_mask) - continue; - - if ((*id & match_mask) == *id) - goto found; /* Supports all the requested standards */ - - nr_matches = hweight64(match_mask); - if (nr_matches > best_nr_matches) { - best_nr_matches = nr_matches; - best_i = i; - } - } - - if (best_nr_matches > 0) { - tuner_dbg("Selecting best matching firmware (%d bits) for " - "type=", best_nr_matches); - dump_firm_type(type); - printk("(%x), id %016llx:\n", type, (unsigned long long)*id); - i = best_i; - goto found; - } - - /*FIXME: Would make sense to seek for type "hint" match ? */ - - i = -ENOENT; - goto ret; - -found: - *id = priv->firm[i].id; - -ret: - tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); - if (debug) { - dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); - } - return i; -} - -static int load_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id) -{ - struct xc2028_data *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p, *endp, buf[priv->ctrl.max_len]; - - tuner_dbg("%s called\n", __FUNCTION__); - - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - - tuner_info("Loading firmware for type="); - dump_firm_type(priv->firm[pos].type); - printk("(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); - - p = priv->firm[pos].ptr; - endp = p + priv->firm[pos].size; - - while (p < endp) { - __u16 size; - - /* Checks if there's enough bytes to read */ - if (p + sizeof(size) > endp) { - tuner_err("Firmware chunk size is wrong\n"); - return -EINVAL; - } - - size = le16_to_cpu(*(__u16 *) p); - p += sizeof(size); - - if (size == 0xffff) - return 0; - - if (!size) { - /* Special callback command received */ - rc = priv->tuner_callback(priv->video_dev, - XC2028_TUNER_RESET, 0); - if (rc < 0) { - tuner_err("Error at RESET code %d\n", - (*p) & 0x7f); - return -EINVAL; - } - continue; - } - if (size >= 0xff00) { - switch (size) { - case 0xff00: - rc = priv->tuner_callback(priv->video_dev, - XC2028_RESET_CLK, 0); - if (rc < 0) { - tuner_err("Error at RESET code %d\n", - (*p) & 0x7f); - return -EINVAL; - } - break; - default: - tuner_info("Invalid RESET code %d\n", - size & 0x7f); - return -EINVAL; - - } - continue; - } - - /* Checks for a sleep command */ - if (size & 0x8000) { - msleep(size & 0x7fff); - continue; - } - - if ((size + p > endp)) { - tuner_err("missing bytes: need %d, have %d\n", - size, (int)(endp - p)); - return -EINVAL; - } - - buf[0] = *p; - p++; - size--; - - /* Sends message chunks */ - while (size > 0) { - int len = (size < priv->ctrl.max_len - 1) ? - size : priv->ctrl.max_len - 1; - - memcpy(buf + 1, p, len); - - rc = i2c_send(priv, buf, len + 1); - if (rc < 0) { - tuner_err("%d returned from send\n", rc); - return -EINVAL; - } - - p += len; - size -= len; - } - } - return 0; -} - -static int load_scode(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id *id, __u16 int_freq, int scode) -{ - struct xc2028_data *priv = fe->tuner_priv; - int pos, rc; - unsigned char *p; - - tuner_dbg("%s called\n", __FUNCTION__); - - if (!int_freq) { - pos = seek_firmware(fe, type, id); - if (pos < 0) - return pos; - } else { - for (pos = 0; pos < priv->firm_size; pos++) { - if ((priv->firm[pos].int_freq == int_freq) && - (priv->firm[pos].type & HAS_IF)) - break; - } - if (pos == priv->firm_size) - return -ENOENT; - } - - p = priv->firm[pos].ptr; - - if (priv->firm[pos].type & HAS_IF) { - if (priv->firm[pos].size != 12 * 16 || scode >= 16) - return -EINVAL; - p += 12 * scode; - } else { - /* 16 SCODE entries per file; each SCODE entry is 12 bytes and - * has a 2-byte size header in the firmware format. */ - if (priv->firm[pos].size != 14 * 16 || scode >= 16 || - le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) - return -EINVAL; - p += 14 * scode + 2; - } - - tuner_info("Loading SCODE for type="); - dump_firm_type_and_int_freq(priv->firm[pos].type, - priv->firm[pos].int_freq); - printk("(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); - - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); - else - rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); - if (rc < 0) - return -EIO; - - rc = i2c_send(priv, p, 12); - if (rc < 0) - return -EIO; - - rc = send_seq(priv, {0x00, 0x8c}); - if (rc < 0) - return -EIO; - - return 0; -} - -static int check_firmware(struct dvb_frontend *fe, unsigned int type, - v4l2_std_id std, __u16 int_freq) -{ - struct xc2028_data *priv = fe->tuner_priv; - struct firmware_properties new_fw; - int rc = 0, is_retry = 0; - u16 version, hwmodel; - v4l2_std_id std0; - - tuner_dbg("%s called\n", __FUNCTION__); - - if (!priv->firm) { - if (!priv->ctrl.fname) { - tuner_info("xc2028/3028 firmware name not set!\n"); - return -EINVAL; - } - - rc = load_all_firmwares(fe); - if (rc < 0) - return rc; - } - - if (priv->ctrl.mts && !(type & FM)) - type |= MTS; - -retry: - new_fw.type = type; - new_fw.id = std; - new_fw.std_req = std; - new_fw.scode_table = SCODE | priv->ctrl.scode_table; - new_fw.scode_nr = 0; - new_fw.int_freq = int_freq; - - tuner_dbg("checking firmware, user requested type="); - if (debug) { - dump_firm_type(new_fw.type); - printk("(%x), id %016llx, ", new_fw.type, - (unsigned long long)new_fw.std_req); - if (!int_freq) { - printk("scode_tbl "); - dump_firm_type(priv->ctrl.scode_table); - printk("(%x), ", priv->ctrl.scode_table); - } else - printk("int_freq %d, ", new_fw.int_freq); - printk("scode_nr %d\n", new_fw.scode_nr); - } - - /* No need to reload base firmware if it matches */ - if (((BASE | new_fw.type) & BASE_TYPES) == - (priv->cur_fw.type & BASE_TYPES)) { - tuner_dbg("BASE firmware not changed.\n"); - goto skip_base; - } - - /* Updating BASE - forget about all currently loaded firmware */ - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - - /* Reset is needed before loading firmware */ - rc = priv->tuner_callback(priv->video_dev, - XC2028_TUNER_RESET, 0); - if (rc < 0) - goto fail; - - /* BASE firmwares are all std0 */ - std0 = 0; - rc = load_firmware(fe, BASE | new_fw.type, &std0); - if (rc < 0) { - tuner_err("Error %d while loading base firmware\n", - rc); - goto fail; - } - - /* Load INIT1, if needed */ - tuner_dbg("Load init1 firmware, if exists\n"); - - rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); - if (rc == -ENOENT) - rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, - &std0); - if (rc < 0 && rc != -ENOENT) { - tuner_err("Error %d while loading init1 firmware\n", - rc); - goto fail; - } - -skip_base: - /* - * No need to reload standard specific firmware if base firmware - * was not reloaded and requested video standards have not changed. - */ - if (priv->cur_fw.type == (BASE | new_fw.type) && - priv->cur_fw.std_req == std) { - tuner_dbg("Std-specific firmware already loaded.\n"); - goto skip_std_specific; - } - - /* Reloading std-specific firmware forces a SCODE update */ - priv->cur_fw.scode_table = 0; - - rc = load_firmware(fe, new_fw.type, &new_fw.id); - if (rc == -ENOENT) - rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); - - if (rc < 0) - goto fail; - -skip_std_specific: - if (priv->cur_fw.scode_table == new_fw.scode_table && - priv->cur_fw.scode_nr == new_fw.scode_nr) { - tuner_dbg("SCODE firmware already loaded.\n"); - goto check_device; - } - - /* Load SCODE firmware, if exists */ - tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); - - rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, - new_fw.int_freq, new_fw.scode_nr); - -check_device: - if (xc2028_get_reg(priv, 0x0004, &version) < 0 || - xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { - tuner_err("Unable to read tuner registers.\n"); - goto fail; - } - - tuner_info("Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", - hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, - (version & 0xf0) >> 4, version & 0xf); - - /* Check firmware version against what we downloaded. */ - if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { - tuner_err("Incorrect readback of firmware version.\n"); - goto fail; - } - - /* Check that the tuner hardware model remains consistent over time. */ - if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { - priv->hwmodel = hwmodel; - priv->hwvers = version & 0xff00; - } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || - priv->hwvers != (version & 0xff00)) { - tuner_err("Read invalid device hardware information - tuner " - "hung?\n"); - goto fail; - } - - memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); - - /* - * By setting BASE in cur_fw.type only after successfully loading all - * firmwares, we can: - * 1. Identify that BASE firmware with type=0 has been loaded; - * 2. Tell whether BASE firmware was just changed the next time through. - */ - priv->cur_fw.type |= BASE; - - return 0; - -fail: - memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - if (!is_retry) { - msleep(50); - is_retry = 1; - tuner_dbg("Retrying firmware load\n"); - goto retry; - } - - if (rc == -ENOENT) - rc = -EINVAL; - return rc; -} - -static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) -{ - struct xc2028_data *priv = fe->tuner_priv; - u16 frq_lock, signal = 0; - int rc; - - tuner_dbg("%s called\n", __FUNCTION__); - - mutex_lock(&priv->lock); - - /* Sync Lock Indicator */ - rc = xc2028_get_reg(priv, 0x0002, &frq_lock); - if (rc < 0 || frq_lock == 0) - goto ret; - - /* Frequency is locked. Return signal quality */ - - /* Get SNR of the video signal */ - rc = xc2028_get_reg(priv, 0x0040, &signal); - if (rc < 0) - signal = -frq_lock; - -ret: - mutex_unlock(&priv->lock); - - *strength = signal; - - return rc; -} - -#define DIV 15625 - -static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, - enum tuner_mode new_mode, - unsigned int type, - v4l2_std_id std, - u16 int_freq) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc = -EINVAL; - unsigned char buf[4]; - u32 div, offset = 0; - - tuner_dbg("%s called\n", __FUNCTION__); - - mutex_lock(&priv->lock); - - tuner_dbg("should set frequency %d kHz\n", freq / 1000); - - if (check_firmware(fe, type, std, int_freq) < 0) - goto ret; - - /* On some cases xc2028 can disable video output, if - * very weak signals are received. By sending a soft - * reset, this is re-enabled. So, it is better to always - * send a soft reset before changing channels, to be sure - * that xc2028 will be in a safe state. - * Maybe this might also be needed for DTV. - */ - if (new_mode == T_ANALOG_TV) { - rc = send_seq(priv, {0x00, 0x00}); - } else if (priv->cur_fw.type & ATSC) { - offset = 1750000; - } else { - offset = 2750000; - /* - * We must adjust the offset by 500kHz in two cases in order - * to correctly center the IF output: - * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly - * selected and a 7MHz channel is tuned; - * 2) When tuning a VHF channel with DTV78 firmware. - */ - if (((priv->cur_fw.type & DTV7) && - (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) || - ((priv->cur_fw.type & DTV78) && freq < 470000000)) - offset -= 500000; - } - - div = (freq - offset + DIV / 2) / DIV; - - /* CMD= Set frequency */ - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); - else - rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); - if (rc < 0) - goto ret; - - rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); - if (rc < 0) - goto ret; - - msleep(10); - - buf[0] = 0xff & (div >> 24); - buf[1] = 0xff & (div >> 16); - buf[2] = 0xff & (div >> 8); - buf[3] = 0xff & (div); - - rc = i2c_send(priv, buf, sizeof(buf)); - if (rc < 0) - goto ret; - msleep(100); - - priv->frequency = freq; - - tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n", - buf[0], buf[1], buf[2], buf[3], - freq / 1000000, (freq % 1000000) / 1000); - - rc = 0; - -ret: - mutex_unlock(&priv->lock); - - return rc; -} - -static int xc2028_set_analog_freq(struct dvb_frontend *fe, - struct analog_parameters *p) -{ - struct xc2028_data *priv = fe->tuner_priv; - unsigned int type=0; - - tuner_dbg("%s called\n", __FUNCTION__); - - if (p->mode == V4L2_TUNER_RADIO) { - type |= FM; - if (priv->ctrl.input1) - type |= INPUT1; - return generic_set_freq(fe, (625l * p->frequency) / 10, - T_ANALOG_TV, type, 0, 0); - } - - /* if std is not defined, choose one */ - if (!p->std) - p->std = V4L2_STD_MN; - - /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ - if (!(p->std & V4L2_STD_MN)) - type |= F8MHZ; - - /* Add audio hack to std mask */ - p->std |= parse_audio_std_option(); - - return generic_set_freq(fe, 62500l * p->frequency, - T_ANALOG_TV, type, p->std, 0); -} - -static int xc2028_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) -{ - struct xc2028_data *priv = fe->tuner_priv; - unsigned int type=0; - fe_bandwidth_t bw = BANDWIDTH_8_MHZ; - u16 demod = 0; - - tuner_dbg("%s called\n", __FUNCTION__); - - if (priv->ctrl.d2633) - type |= D2633; - else - type |= D2620; - - switch(fe->ops.info.type) { - case FE_OFDM: - bw = p->u.ofdm.bandwidth; - break; - case FE_QAM: - tuner_info("WARN: There are some reports that " - "QAM 6 MHz doesn't work.\n" - "If this works for you, please report by " - "e-mail to: v4l-dvb-maintainer@linuxtv.org\n"); - bw = BANDWIDTH_6_MHZ; - type |= QAM; - break; - case FE_ATSC: - bw = BANDWIDTH_6_MHZ; - /* The only ATSC firmware (at least on v2.7) is D2633, - so overrides ctrl->d2633 */ - type |= ATSC| D2633; - type &= ~D2620; - break; - /* DVB-S is not supported */ - default: - return -EINVAL; - } - - switch (bw) { - case BANDWIDTH_8_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 0; - else - priv->ctrl.uhfbw8 = 1; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; - type |= F8MHZ; - break; - case BANDWIDTH_7_MHZ: - if (p->frequency < 470000000) - priv->ctrl.vhfbw7 = 1; - else - priv->ctrl.uhfbw8 = 0; - type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; - type |= F8MHZ; - break; - case BANDWIDTH_6_MHZ: - type |= DTV6; - priv->ctrl.vhfbw7 = 0; - priv->ctrl.uhfbw8 = 0; - break; - default: - tuner_err("error: bandwidth not supported.\n"); - }; - - /* All S-code tables need a 200kHz shift */ - if (priv->ctrl.demod) - demod = priv->ctrl.demod + 200; - - return generic_set_freq(fe, p->frequency, - T_DIGITAL_TV, type, 0, demod); -} - -static int xc2028_sleep(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - int rc = 0; - - tuner_dbg("%s called\n", __FUNCTION__); - - mutex_lock(&priv->lock); - - if (priv->firm_version < 0x0202) - rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); - else - rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); - - priv->cur_fw.type = 0; /* need firmware reload */ - - mutex_unlock(&priv->lock); - - return rc; -} - - -static int xc2028_dvb_release(struct dvb_frontend *fe) -{ - struct xc2028_data *priv = fe->tuner_priv; - - tuner_dbg("%s called\n", __FUNCTION__); - - mutex_lock(&xc2028_list_mutex); - - priv->count--; - - if (!priv->count) { - list_del(&priv->xc2028_list); - - kfree(priv->ctrl.fname); - - free_firmware(priv); - kfree(priv); - fe->tuner_priv = NULL; - } - - mutex_unlock(&xc2028_list_mutex); - - return 0; -} - -static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct xc2028_data *priv = fe->tuner_priv; - - tuner_dbg("%s called\n", __FUNCTION__); - - *frequency = priv->frequency; - - return 0; -} - -static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) -{ - struct xc2028_data *priv = fe->tuner_priv; - struct xc2028_ctrl *p = priv_cfg; - int rc = 0; - - tuner_dbg("%s called\n", __FUNCTION__); - - mutex_lock(&priv->lock); - - kfree(priv->ctrl.fname); - free_firmware(priv); - - memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); - priv->ctrl.fname = NULL; - - if (p->fname) { - priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); - if (priv->ctrl.fname == NULL) - rc = -ENOMEM; - } - - if (priv->ctrl.max_len < 9) - priv->ctrl.max_len = 13; - - mutex_unlock(&priv->lock); - - return rc; -} - -static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { - .info = { - .name = "Xceive XC3028", - .frequency_min = 42000000, - .frequency_max = 864000000, - .frequency_step = 50000, - }, - - .set_config = xc2028_set_config, - .set_analog_params = xc2028_set_analog_freq, - .release = xc2028_dvb_release, - .get_frequency = xc2028_get_frequency, - .get_rf_strength = xc2028_signal, - .set_params = xc2028_set_params, - .sleep = xc2028_sleep, - -}; - -struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg) -{ - struct xc2028_data *priv; - void *video_dev; - - if (debug) - printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n"); - - if (NULL == cfg || NULL == cfg->video_dev) - return NULL; - - if (!fe) { - printk(KERN_ERR PREFIX ": No frontend!\n"); - return NULL; - } - - video_dev = cfg->video_dev; - - mutex_lock(&xc2028_list_mutex); - - list_for_each_entry(priv, &xc2028_list, xc2028_list) { - if (priv->video_dev == cfg->video_dev) { - video_dev = NULL; - break; - } - } - - if (video_dev) { - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - mutex_unlock(&xc2028_list_mutex); - return NULL; - } - - priv->i2c_props.addr = cfg->i2c_addr; - priv->i2c_props.adap = cfg->i2c_adap; - priv->video_dev = video_dev; - priv->tuner_callback = cfg->callback; - priv->ctrl.max_len = 13; - - mutex_init(&priv->lock); - - list_add_tail(&priv->xc2028_list, &xc2028_list); - } - - fe->tuner_priv = priv; - priv->count++; - - memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, - sizeof(xc2028_dvb_tuner_ops)); - - tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); - - if (cfg->ctrl) - xc2028_set_config(fe, cfg->ctrl); - - mutex_unlock(&xc2028_list_mutex); - - return fe; -} - -EXPORT_SYMBOL(xc2028_attach); - -MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); -MODULE_AUTHOR("Michel Ludwig "); -MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/media/video/tuner-xc2028.h b/trunk/drivers/media/video/tuner-xc2028.h deleted file mode 100644 index 3eb8420379a4..000000000000 --- a/trunk/drivers/media/video/tuner-xc2028.h +++ /dev/null @@ -1,63 +0,0 @@ -/* tuner-xc2028 - * - * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ - -#ifndef __TUNER_XC2028_H__ -#define __TUNER_XC2028_H__ - -#include "dvb_frontend.h" - -#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" - -/* Dmoduler IF (kHz) */ -#define XC3028_FE_DEFAULT 0 -#define XC3028_FE_LG60 6000 -#define XC3028_FE_ATI638 6380 -#define XC3028_FE_OREN538 5380 -#define XC3028_FE_OREN36 3600 -#define XC3028_FE_TOYOTA388 3880 -#define XC3028_FE_TOYOTA794 7940 -#define XC3028_FE_DIBCOM52 5200 -#define XC3028_FE_ZARLINK456 4560 -#define XC3028_FE_CHINA 5200 - -struct xc2028_ctrl { - char *fname; - int max_len; - unsigned int scode_table; - unsigned int mts :1; - unsigned int d2633 :1; - unsigned int input1:1; - unsigned int vhfbw7:1; - unsigned int uhfbw8:1; - unsigned int demod; -}; - -struct xc2028_config { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - void *video_dev; - struct xc2028_ctrl *ctrl; - int (*callback) (void *dev, int command, int arg); -}; - -/* xc2028 commands for callback */ -#define XC2028_TUNER_RESET 0 -#define XC2028_RESET_CLK 1 - -#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) -extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg); -#else -static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, - struct xc2028_config *cfg) -{ - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __FUNCTION__); - return NULL; -} -#endif - -#endif /* __TUNER_XC2028_H__ */ diff --git a/trunk/drivers/media/video/tvaudio.c b/trunk/drivers/media/video/tvaudio.c index a75560540e79..a19cdcc17ef7 100644 --- a/trunk/drivers/media/video/tvaudio.c +++ b/trunk/drivers/media/video/tvaudio.c @@ -31,7 +31,6 @@ #include #include #include -#include #include @@ -110,7 +109,7 @@ static struct CHIPDESC chiplist[]; /* current state of the chip */ struct CHIPSTATE { - struct i2c_client *c; + struct i2c_client c; /* index into CHIPDESC array */ int type; @@ -146,6 +145,10 @@ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; +static struct i2c_driver driver; +static struct i2c_client client_template; + + /* ---------------------------------------------------------------------- */ /* i2c I/O functions */ @@ -154,24 +157,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) unsigned char buffer[2]; if (-1 == subaddr) { - v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n", - chip->c->name, val); + v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n", + chip->c.name, val); chip->shadow.bytes[1] = val; buffer[0] = val; - if (1 != i2c_master_send(chip->c,buffer,1)) { - v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n", - chip->c->name, val); + if (1 != i2c_master_send(&chip->c,buffer,1)) { + v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n", + chip->c.name, val); return -1; } } else { - v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n", - chip->c->name, subaddr, val); + v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n", + chip->c.name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; - if (2 != i2c_master_send(chip->c,buffer,2)) { - v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n", - chip->c->name, subaddr, val); + if (2 != i2c_master_send(&chip->c,buffer,2)) { + v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n", + chip->c.name, subaddr, val); return -1; } } @@ -194,12 +197,12 @@ static int chip_read(struct CHIPSTATE *chip) { unsigned char buffer; - if (1 != i2c_master_recv(chip->c,&buffer,1)) { - v4l_warn(chip->c, "%s: I/O error (read)\n", - chip->c->name); + if (1 != i2c_master_recv(&chip->c,&buffer,1)) { + v4l_warn(&chip->c, "%s: I/O error (read)\n", + chip->c.name); return -1; } - v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer); + v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer); return buffer; } @@ -208,17 +211,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) unsigned char write[1]; unsigned char read[1]; struct i2c_msg msgs[2] = { - { chip->c->addr, 0, 1, write }, - { chip->c->addr, I2C_M_RD, 1, read } + { chip->c.addr, 0, 1, write }, + { chip->c.addr, I2C_M_RD, 1, read } }; write[0] = subaddr; - if (2 != i2c_transfer(chip->c->adapter,msgs,2)) { - v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name); + if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { + v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name); return -1; } - v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n", - chip->c->name, subaddr,read[0]); + v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n", + chip->c.name, subaddr,read[0]); return read[0]; } @@ -230,8 +233,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return 0; /* update our shadow register set; print bytes if (debug > 0) */ - v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:", - chip->c->name, name,cmd->bytes[0]); + v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:", + chip->c.name, name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { if (debug) printk(" 0x%x",cmd->bytes[i]); @@ -241,8 +244,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) printk("\n"); /* send data to the chip */ - if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) { - v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name); + if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { + v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name); return -1; } return 0; @@ -266,7 +269,7 @@ static int chip_thread(void *data) struct CHIPSTATE *chip = data; struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name); + v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name); set_freezable(); for (;;) { set_current_state(TASK_INTERRUPTIBLE); @@ -276,7 +279,7 @@ static int chip_thread(void *data) try_to_freeze(); if (kthread_should_stop()) break; - v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name); + v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name); /* don't do anything for radio or if mode != auto */ if (chip->radio || chip->mode != 0) @@ -289,7 +292,7 @@ static int chip_thread(void *data) mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); } - v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name); + v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name); return 0; } @@ -301,19 +304,17 @@ static void generic_checkmode(struct CHIPSTATE *chip) if (mode == chip->prevmode) return; - v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name); + v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name); chip->prevmode = mode; - if (mode & V4L2_TUNER_MODE_STEREO) - desc->setmode(chip,V4L2_TUNER_MODE_STEREO); - if (mode & V4L2_TUNER_MODE_LANG1_LANG2) - desc->setmode(chip,V4L2_TUNER_MODE_STEREO); - else if (mode & V4L2_TUNER_MODE_LANG1) - desc->setmode(chip,V4L2_TUNER_MODE_LANG1); - else if (mode & V4L2_TUNER_MODE_LANG2) - desc->setmode(chip,V4L2_TUNER_MODE_LANG2); + if (mode & VIDEO_SOUND_STEREO) + desc->setmode(chip,VIDEO_SOUND_STEREO); + else if (mode & VIDEO_SOUND_LANG1) + desc->setmode(chip,VIDEO_SOUND_LANG1); + else if (mode & VIDEO_SOUND_LANG2) + desc->setmode(chip,VIDEO_SOUND_LANG2); else - desc->setmode(chip,V4L2_TUNER_MODE_MONO); + desc->setmode(chip,VIDEO_SOUND_MONO); } /* ---------------------------------------------------------------------- */ @@ -344,13 +345,13 @@ static int tda9840_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; + mode = VIDEO_SOUND_MONO; if (val & TDA9840_DS_DUAL) - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; if (val & TDA9840_ST_STEREO) - mode |= V4L2_TUNER_MODE_STEREO; + mode |= VIDEO_SOUND_STEREO; - v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", + v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -361,16 +362,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode) int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; switch (mode) { - case V4L2_TUNER_MODE_MONO: + case VIDEO_SOUND_MONO: t |= TDA9840_MONO; break; - case V4L2_TUNER_MODE_STEREO: + case VIDEO_SOUND_STEREO: t |= TDA9840_STEREO; break; - case V4L2_TUNER_MODE_LANG1: + case VIDEO_SOUND_LANG1: t |= TDA9840_DUALA; break; - case V4L2_TUNER_MODE_LANG2: + case VIDEO_SOUND_LANG2: t |= TDA9840_DUALB; break; default: @@ -501,7 +502,7 @@ static int tda985x_getmode(struct CHIPSTATE *chip) chip_read(chip)) >> 4; /* Add mono mode regardless of SAP and stereo */ /* Allows forced mono */ - return mode | V4L2_TUNER_MODE_MONO; + return mode | VIDEO_SOUND_MONO; } static void tda985x_setmode(struct CHIPSTATE *chip, int mode) @@ -510,13 +511,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode) int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; switch (mode) { - case V4L2_TUNER_MODE_MONO: + case VIDEO_SOUND_MONO: c6 |= TDA985x_MONO; break; - case V4L2_TUNER_MODE_STEREO: + case VIDEO_SOUND_STEREO: c6 |= TDA985x_STEREO; break; - case V4L2_TUNER_MODE_LANG1: + case VIDEO_SOUND_LANG1: c6 |= TDA985x_SAP; break; default: @@ -649,12 +650,12 @@ static int tda9873_getmode(struct CHIPSTATE *chip) int val,mode; val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; + mode = VIDEO_SOUND_MONO; if (val & TDA9873_STEREO) - mode |= V4L2_TUNER_MODE_STEREO; + mode |= VIDEO_SOUND_STEREO; if (val & TDA9873_DUAL) - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; - v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", + mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -665,24 +666,24 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n"); + v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n"); return; } - v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); + v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { - case V4L2_TUNER_MODE_MONO: + case VIDEO_SOUND_MONO: sw_data |= TDA9873_TR_MONO; break; - case V4L2_TUNER_MODE_STEREO: + case VIDEO_SOUND_STEREO: sw_data |= TDA9873_TR_STEREO; break; - case V4L2_TUNER_MODE_LANG1: + case VIDEO_SOUND_LANG1: sw_data |= TDA9873_TR_DUALA; break; - case V4L2_TUNER_MODE_LANG2: + case VIDEO_SOUND_LANG2: sw_data |= TDA9873_TR_DUALB; break; default: @@ -691,7 +692,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) } chip_write(chip, TDA9873_SW, sw_data); - v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", + v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -830,7 +831,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip) chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ } - v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n", + v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n", tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } @@ -840,7 +841,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) int dsr,nsr,mode; int necr; /* just for debugging */ - mode = V4L2_TUNER_MODE_MONO; + mode = VIDEO_SOUND_MONO; if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) return mode; @@ -859,21 +860,21 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) * that sound has (temporarily) switched from NICAM to * mono FM (or AM) on 1st sound carrier due to high NICAM bit * error count. So in fact there is no stereo in this case :-( - * But changing the mode to V4L2_TUNER_MODE_MONO would switch + * But changing the mode to VIDEO_SOUND_MONO would switch * external 4052 multiplexer in audio_hook(). */ if(nsr & 0x02) /* NSR.S/MB=1 */ - mode |= V4L2_TUNER_MODE_STEREO; + mode |= VIDEO_SOUND_STEREO; if(nsr & 0x01) /* NSR.D/SB=1 */ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } else { if(dsr & 0x02) /* DSR.IDSTE=1 */ - mode |= V4L2_TUNER_MODE_STEREO; + mode |= VIDEO_SOUND_STEREO; if(dsr & 0x04) /* DSR.IDDUA=1 */ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; } - v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } @@ -901,14 +902,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) int mdacosr = (tda9874a_mode) ? 0x82:0x80; switch(mode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_STEREO: + case VIDEO_SOUND_MONO: + case VIDEO_SOUND_STEREO: break; - case V4L2_TUNER_MODE_LANG1: + case VIDEO_SOUND_LANG1: aosr = 0x80; /* auto-select, dual A/A */ mdacosr = (tda9874a_mode) ? 0x82:0x80; break; - case V4L2_TUNER_MODE_LANG2: + case VIDEO_SOUND_LANG2: aosr = 0xa0; /* auto-select, dual B/B */ mdacosr = (tda9874a_mode) ? 0x83:0x81; break; @@ -919,18 +920,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ int fmmr,aosr; switch(mode) { - case V4L2_TUNER_MODE_MONO: + case VIDEO_SOUND_MONO: fmmr = 0x00; /* mono */ aosr = 0x10; /* A/A */ break; - case V4L2_TUNER_MODE_STEREO: + case VIDEO_SOUND_STEREO: if(tda9874a_mode) { fmmr = 0x00; aosr = 0x00; /* handled by NICAM auto-mute */ @@ -939,11 +940,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) aosr = 0x00; } break; - case V4L2_TUNER_MODE_LANG1: + case VIDEO_SOUND_LANG1: fmmr = 0x02; /* dual */ aosr = 0x10; /* dual A/A */ break; - case V4L2_TUNER_MODE_LANG2: + case VIDEO_SOUND_LANG2: fmmr = 0x02; /* dual */ aosr = 0x20; /* dual B/B */ break; @@ -954,7 +955,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -968,10 +969,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) return 0; - v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); + v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); if((dic == 0x11)||(dic == 0x07)) { - v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); + v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); tda9874a_dic = dic; /* remember device id. */ return 1; } @@ -1094,7 +1095,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip) int inputmap[4] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1, /* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF}; - if (chip->c->adapter->id == I2C_HW_B_RIVA) { + if (chip->c.adapter->id == I2C_HW_B_RIVA) { memcpy (desc->inputmap, inputmap, sizeof (inputmap)); } return 0; @@ -1104,20 +1105,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) { int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1; - if (mode & V4L2_TUNER_MODE_LANG1) { + if (mode & VIDEO_SOUND_LANG1) { s1 |= TDA8425_S1_ML_SOUND_A; s1 |= TDA8425_S1_STEREO_PSEUDO; - } else if (mode & V4L2_TUNER_MODE_LANG2) { + } else if (mode & VIDEO_SOUND_LANG2) { s1 |= TDA8425_S1_ML_SOUND_B; s1 |= TDA8425_S1_STEREO_PSEUDO; } else { s1 |= TDA8425_S1_ML_STEREO; - if (mode & V4L2_TUNER_MODE_MONO) + if (mode & VIDEO_SOUND_MONO) s1 |= TDA8425_S1_STEREO_MONO; - if (mode & V4L2_TUNER_MODE_STEREO) + if (mode & VIDEO_SOUND_STEREO) s1 |= TDA8425_S1_STEREO_SPATIAL; } chip_write(chip,TDA8425_S1,s1); @@ -1176,13 +1177,13 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = V4L2_TUNER_MODE_MONO; + mode = VIDEO_SOUND_MONO; if (val & TA8874Z_B1){ - mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; }else if (!(val & TA8874Z_B0)){ - mode |= V4L2_TUNER_MODE_STEREO; + mode |= VIDEO_SOUND_STEREO; } - /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ + /* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; } @@ -1195,19 +1196,19 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; audiocmd *t = NULL; - v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); + v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ - case V4L2_TUNER_MODE_MONO: + case VIDEO_SOUND_MONO: t = &ta8874z_mono; break; - case V4L2_TUNER_MODE_STEREO: + case VIDEO_SOUND_STEREO: t = &ta8874z_stereo; break; - case V4L2_TUNER_MODE_LANG1: + case VIDEO_SOUND_LANG1: t = &ta8874z_main; break; - case V4L2_TUNER_MODE_LANG2: + case VIDEO_SOUND_LANG2: t = &ta8874z_sub; break; default: @@ -1461,55 +1462,51 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ /* i2c registration */ -static int chip_probe(struct i2c_client *client) +static int chip_attach(struct i2c_adapter *adap, int addr, int kind) { struct CHIPSTATE *chip; struct CHIPDESC *desc; - if (debug) { - printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); - printk(KERN_INFO "tvaudio: known chips: "); - for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); - printk("\n"); - } - chip = kzalloc(sizeof(*chip),GFP_KERNEL); if (!chip) return -ENOMEM; - chip->c = client; - i2c_set_clientdata(client, chip); + memcpy(&chip->c,&client_template,sizeof(struct i2c_client)); + chip->c.adapter = adap; + chip->c.addr = addr; + i2c_set_clientdata(&chip->c, chip); /* find description for the chip */ - v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1); + v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; - if (client->addr < desc->addr_lo || - client->addr > desc->addr_hi) + if (addr < desc->addr_lo || + addr > desc->addr_hi) continue; if (desc->checkit && !desc->checkit(chip)) continue; break; } if (desc->name == NULL) { - v4l_dbg(1, debug, client, "no matching chip description found\n"); + v4l_dbg(1, debug, &chip->c, "no matching chip description found\n"); return -EIO; } - v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name); + v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); if (desc->flags) { - v4l_dbg(1, debug, client, "matches:%s%s%s.\n", + v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n", (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); } /* fill required data structures */ - strcpy(client->name, desc->name); + strcpy(chip->c.name, desc->name); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; chip->audmode = V4L2_TUNER_MODE_LANG1; + /* register */ + i2c_attach_client(&chip->c); /* initialization */ if (desc->initialize != NULL) @@ -1536,17 +1533,28 @@ static int chip_probe(struct i2c_client *client) init_timer(&chip->wt); chip->wt.function = chip_thread_wake; chip->wt.data = (unsigned long)chip; - chip->thread = kthread_run(chip_thread, chip, chip->c->name); + chip->thread = kthread_run(chip_thread, chip, chip->c.name); if (IS_ERR(chip->thread)) { - v4l_warn(chip->c, "%s: failed to create kthread\n", - chip->c->name); + v4l_warn(&chip->c, "%s: failed to create kthread\n", + chip->c.name); chip->thread = NULL; } } return 0; } -static int chip_remove(struct i2c_client *client) +static int chip_probe(struct i2c_adapter *adap) +{ + /* don't attach on saa7146 based cards, + because dedicated drivers are used */ + if ((adap->id == I2C_HW_SAA7146)) + return 0; + if (adap->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adap, &addr_data, chip_attach); + return 0; +} + +static int chip_detach(struct i2c_client *client) { struct CHIPSTATE *chip = i2c_get_clientdata(client); @@ -1557,52 +1565,12 @@ static int chip_remove(struct i2c_client *client) chip->thread = NULL; } + i2c_detach_client(&chip->c); kfree(chip); return 0; } -static int tvaudio_get_ctrl(struct CHIPSTATE *chip, - struct v4l2_control *ctrl) -{ - struct CHIPDESC *desc = chiplist + chip->type; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value=chip->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (!desc->flags & CHIP_HAS_VOLUME) - break; - ctrl->value = max(chip->left,chip->right); - return 0; - case V4L2_CID_AUDIO_BALANCE: - { - int volume; - if (!desc->flags & CHIP_HAS_VOLUME) - break; - volume = max(chip->left,chip->right); - if (volume) - ctrl->value=(32768*min(chip->left,chip->right))/volume; - else - ctrl->value=32768; - return 0; - } - case V4L2_CID_AUDIO_BASS: - if (desc->flags & CHIP_HAS_BASSTREBLE) - break; - ctrl->value = chip->bass; - return 0; - case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) - return -EINVAL; - ctrl->value = chip->treble; - return 0; - } - return -EINVAL; -} - -static int tvaudio_set_ctrl(struct CHIPSTATE *chip, - struct v4l2_control *ctrl) +static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) { struct CHIPDESC *desc = chiplist + chip->type; @@ -1616,60 +1584,11 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, else chip_write_masked(chip,desc->inputreg, desc->inputmap[chip->input],desc->inputmask); - return 0; - case V4L2_CID_AUDIO_VOLUME: - { - int volume,balance; - - if (!desc->flags & CHIP_HAS_VOLUME) - break; - - volume = max(chip->left,chip->right); - if (volume) - balance=(32768*min(chip->left,chip->right))/volume; - else - balance=32768; - - volume=ctrl->value; - chip->left = (min(65536 - balance,32768) * volume) / 32768; - chip->right = (min(balance,volume *(__u16)32768)) / 32768; - - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - - return 0; - } - case V4L2_CID_AUDIO_BALANCE: - { - int volume, balance; - if (!desc->flags & CHIP_HAS_VOLUME) - break; - - volume = max(chip->left,chip->right); - balance = ctrl->value; - - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - - return 0; - } - case V4L2_CID_AUDIO_BASS: - if (desc->flags & CHIP_HAS_BASSTREBLE) - break; - chip->bass = ctrl->value; - chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); - - return 0; - case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) - return -EINVAL; - - chip->treble = ctrl->value; - chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); - - return 0; + break; + default: + return -EINVAL; } - return -EINVAL; + return 0; } @@ -1682,7 +1601,7 @@ static int chip_command(struct i2c_client *client, struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd); + v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd); switch (cmd) { case AUDC_SET_RADIO: @@ -1690,36 +1609,67 @@ static int chip_command(struct i2c_client *client, chip->watch_stereo = 0; /* del_timer(&chip->wt); */ break; + /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ - case VIDIOC_QUERYCTRL: + case VIDIOCGAUDIO: { - struct v4l2_queryctrl *qc = arg; - - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - if (!desc->flags & CHIP_HAS_VOLUME) - return -EINVAL; - break; - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - if (desc->flags & CHIP_HAS_BASSTREBLE) - return -EINVAL; - break; - default: - return -EINVAL; + struct video_audio *va = arg; + + if (desc->flags & CHIP_HAS_VOLUME) { + va->flags |= VIDEO_AUDIO_VOLUME; + va->volume = max(chip->left,chip->right); + if (va->volume) + va->balance = (32768*min(chip->left,chip->right))/ + va->volume; + else + va->balance = 32768; + } + if (desc->flags & CHIP_HAS_BASSTREBLE) { + va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; + va->bass = chip->bass; + va->treble = chip->treble; } - return v4l2_ctrl_query_fill_std(qc); + if (!chip->radio) { + if (desc->getmode) + va->mode = desc->getmode(chip); + else + va->mode = VIDEO_SOUND_MONO; + } + break; } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + if (desc->flags & CHIP_HAS_VOLUME) { + chip->left = (min(65536 - va->balance,32768) * + va->volume) / 32768; + chip->right = (min(va->balance,(__u16)32768) * + va->volume) / 32768; + chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); + chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + } + if (desc->flags & CHIP_HAS_BASSTREBLE) { + chip->bass = va->bass; + chip->treble = va->treble; + chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); + chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); + } + if (desc->setmode && va->mode) { + chip->watch_stereo = 0; + /* del_timer(&chip->wt); */ + chip->mode = va->mode; + desc->setmode(chip,va->mode); + } + break; + } + case VIDIOC_S_CTRL: return tvaudio_set_ctrl(chip, arg); - case VIDIOC_G_CTRL: - return tvaudio_get_ctrl(chip, arg); case VIDIOC_INT_G_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1728,6 +1678,7 @@ static int chip_command(struct i2c_client *client, rt->output = 0; break; } + case VIDIOC_INT_S_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1742,6 +1693,7 @@ static int chip_command(struct i2c_client *client, desc->inputmap[chip->input], desc->inputmask); break; } + case VIDIOC_S_TUNER: { struct v4l2_tuner *vt = arg; @@ -1751,13 +1703,17 @@ static int chip_command(struct i2c_client *client, break; switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: + mode = VIDEO_SOUND_MONO; + break; case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + mode = VIDEO_SOUND_STEREO; + break; case V4L2_TUNER_MODE_LANG1: - case V4L2_TUNER_MODE_LANG2: - mode = vt->audmode; + mode = VIDEO_SOUND_LANG1; break; - case V4L2_TUNER_MODE_LANG1_LANG2: - mode = V4L2_TUNER_MODE_STEREO; + case V4L2_TUNER_MODE_LANG2: + mode = VIDEO_SOUND_LANG2; break; default: return -EINVAL; @@ -1772,10 +1728,11 @@ static int chip_command(struct i2c_client *client, } break; } + case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; - int mode = V4L2_TUNER_MODE_MONO; + int mode = VIDEO_SOUND_MONO; if (chip->radio) break; @@ -1787,26 +1744,30 @@ static int chip_command(struct i2c_client *client, if (desc->getmode) mode = desc->getmode(chip); - if (mode & V4L2_TUNER_MODE_MONO) + if (mode & VIDEO_SOUND_MONO) vt->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (mode & V4L2_TUNER_MODE_STEREO) + if (mode & VIDEO_SOUND_STEREO) vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; /* Note: for SAP it should be mono/lang2 or stereo/lang2. When this module is converted fully to v4l2, then this should change for those chips that can detect SAP. */ - if (mode & V4L2_TUNER_MODE_LANG1) + if (mode & VIDEO_SOUND_LANG1) vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; } + + case VIDIOCSCHAN: case VIDIOC_S_STD: chip->radio = 0; break; + + case VIDIOCSFREQ: case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ if (desc->checkmode) { - desc->setmode(chip,V4L2_TUNER_MODE_MONO); - if (chip->prevmode != V4L2_TUNER_MODE_MONO) + desc->setmode(chip,VIDEO_SOUND_MONO); + if (chip->prevmode != VIDEO_SOUND_MONO) chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); /* the thread will call checkmode() later */ @@ -1819,25 +1780,44 @@ static int chip_command(struct i2c_client *client, return 0; } -static int chip_legacy_probe(struct i2c_adapter *adap) +static struct i2c_driver driver = { + .driver = { + .name = "tvaudio", + }, + .id = I2C_DRIVERID_TVAUDIO, + .attach_adapter = chip_probe, + .detach_client = chip_detach, + .command = chip_command, +}; + +static struct i2c_client client_template = { - /* don't attach on saa7146 based cards, - because dedicated drivers are used */ - if ((adap->id == I2C_HW_SAA7146)) - return 0; - if (adap->class & I2C_CLASS_TV_ANALOG) - return 1; - return 0; + .name = "(unset)", + .driver = &driver, +}; + +static int __init audiochip_init_module(void) +{ + struct CHIPDESC *desc; + + if (debug) { + printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); + printk(KERN_INFO "tvaudio: known chips: "); + for (desc = chiplist; desc->name != NULL; desc++) + printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); + printk("\n"); + } + + return i2c_add_driver(&driver); } -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "tvaudio", - .driverid = I2C_DRIVERID_TVAUDIO, - .command = chip_command, - .probe = chip_probe, - .remove = chip_remove, - .legacy_probe = chip_legacy_probe, -}; +static void __exit audiochip_cleanup_module(void) +{ + i2c_del_driver(&driver); +} + +module_init(audiochip_init_module); +module_exit(audiochip_cleanup_module); /* * Local variables: diff --git a/trunk/drivers/media/video/tveeprom.c b/trunk/drivers/media/video/tveeprom.c index 0b8fbad3c721..4b2c4034f5b3 100644 --- a/trunk/drivers/media/video/tveeprom.c +++ b/trunk/drivers/media/video/tveeprom.c @@ -46,12 +46,11 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); MODULE_AUTHOR("John Klar"); MODULE_LICENSE("GPL"); -static int debug; +static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -#define STRM(array, i) \ - (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown") +#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown") #define tveeprom_info(fmt, arg...) \ v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) @@ -59,8 +58,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) #define tveeprom_dbg(fmt, arg...) do { \ if (debug) \ - v4l_printk(KERN_DEBUG, "tveeprom", \ - c->adapter, c->addr, fmt , ## arg); \ + v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \ } while (0) /* @@ -96,172 +94,170 @@ static struct HAUPPAUGE_TUNER hauppauge_tuner[] = { /* 0-9 */ - { TUNER_ABSENT, "None" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_PHILIPS_PAL, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, - { TUNER_PHILIPS_PAL_DK, "Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, + { TUNER_ABSENT, "None" }, + { TUNER_ABSENT, "External" }, + { TUNER_ABSENT, "Unspecified" }, + { TUNER_PHILIPS_PAL, "Philips FI1216" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, + { TUNER_PHILIPS_PAL_DK,"Philips FI1256" }, + { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, /* 10-19 */ - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" }, - { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, + { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" }, + { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, + { TUNER_TEMIC_PAL, "Temic 4002FH5" }, + { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, + { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, /* 20-29 */ - { TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_PHILIPS_PAL_DK, "Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, + { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" }, + { TUNER_PHILIPS_PAL, "Philips FM1216" }, + { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_PHILIPS_PAL_DK,"Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, /* 30-39 */ - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, - { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, - { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, - { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ - { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, + { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, + { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, + { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ + { TUNER_ABSENT, "Philips FI1256MP" }, /* 40-49 */ - { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, - { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, - { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, + { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, + { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, - { TUNER_ABSENT, "Philips TD1536D FH 44"}, - { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, - { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, - { TUNER_LG_PAL, "LG TP18PSB11D"}, - { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, + { TUNER_ABSENT, "Philips TD1536D FH 44"}, + { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, + { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, + { TUNER_LG_PAL, "LG TP18PSB11D"}, + { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, /* 50-59 */ - { TUNER_LG_PAL_I, "LG TAPC-I701D"}, - { TUNER_ABSENT, "Temic 4042FI5"}, - { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, - { TUNER_ABSENT, "LG TPI8NSR11F"}, - { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, - { TUNER_ABSENT, "Philips FI1236 MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, - { TUNER_ABSENT, "Philips FM1216MP MK3"}, + { TUNER_LG_PAL_I, "LG TAPC-I701D"}, + { TUNER_ABSENT, "Temic 4042FI5"}, + { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, + { TUNER_ABSENT, "LG TPI8NSR11F"}, + { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, + { TUNER_ABSENT, "Philips FI1236 MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, + { TUNER_ABSENT, "Philips FM1216MP MK3"}, /* 60-69 */ - { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, - { TUNER_ABSENT, "LG M001D MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, - { TUNER_ABSENT, "LG M701D MK3"}, - { TUNER_ABSENT, "Temic 4146FM5"}, - { TUNER_ABSENT, "Temic 4136FY5"}, - { TUNER_ABSENT, "Temic 4106FH5"}, - { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, + { TUNER_ABSENT, "LG M001D MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, + { TUNER_ABSENT, "LG M701D MK3"}, + { TUNER_ABSENT, "Temic 4146FM5"}, + { TUNER_ABSENT, "Temic 4136FY5"}, + { TUNER_ABSENT, "Temic 4106FH5"}, + { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, /* 70-79 */ - { TUNER_ABSENT, "LG TALN H200T"}, - { TUNER_ABSENT, "LG TALN H250T"}, - { TUNER_ABSENT, "LG TALN M200T"}, - { TUNER_ABSENT, "LG TALN Z200T"}, - { TUNER_ABSENT, "LG TALN S200T"}, - { TUNER_ABSENT, "Thompson DTT7595"}, - { TUNER_ABSENT, "Thompson DTT7592"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, - { TUNER_ABSENT, "Thompson DTT757"}, + { TUNER_ABSENT, "LG TALN H200T"}, + { TUNER_ABSENT, "LG TALN H250T"}, + { TUNER_ABSENT, "LG TALN M200T"}, + { TUNER_ABSENT, "LG TALN Z200T"}, + { TUNER_ABSENT, "LG TALN S200T"}, + { TUNER_ABSENT, "Thompson DTT7595"}, + { TUNER_ABSENT, "Thompson DTT7592"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, + { TUNER_ABSENT, "Thompson DTT757"}, /* 80-89 */ - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, - { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, - { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, - { TUNER_TCL_2002N, "TCL 2002N 6A"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, - { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, - { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, + { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, + { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, + { TUNER_TCL_2002N, "TCL 2002N 6A"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, + { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, + { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, /* 90-99 */ - { TUNER_ABSENT, "LG TALN H202T"}, - { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, - { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, - { TUNER_ABSENT, "Philips FQ1286A MK4"}, - { TUNER_ABSENT, "Philips FQ1216ME MK5"}, - { TUNER_ABSENT, "Philips FQ1236 MK5"}, - { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, - { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, - { TUNER_ABSENT, "TCL 2002MI_3H"}, - { TUNER_TCL_2002N, "TCL 2002N 5H"}, + { TUNER_ABSENT, "LG TALN H202T"}, + { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, + { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, + { TUNER_ABSENT, "Philips FQ1286A MK4"}, + { TUNER_ABSENT, "Philips FQ1216ME MK5"}, + { TUNER_ABSENT, "Philips FQ1236 MK5"}, + { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, + { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, + { TUNER_ABSENT, "TCL 2002MI_3H"}, + { TUNER_TCL_2002N, "TCL 2002N 5H"}, /* 100-109 */ - { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, - { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, - { TUNER_ABSENT, "Panasonic ENV57H12D5"}, - { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, - { TUNER_ABSENT, "TCL MNM05-4"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, - { TUNER_ABSENT, "TCL MQNM05-4"}, - { TUNER_ABSENT, "LG TAPC-W701D"}, - { TUNER_ABSENT, "TCL 9886P-WM"}, - { TUNER_ABSENT, "TCL 1676NM-WM"}, + { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, + { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, + { TUNER_ABSENT, "Panasonic ENV57H12D5"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, + { TUNER_ABSENT, "TCL MNM05-4"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, + { TUNER_ABSENT, "TCL MQNM05-4"}, + { TUNER_ABSENT, "LG TAPC-W701D"}, + { TUNER_ABSENT, "TCL 9886P-WM"}, + { TUNER_ABSENT, "TCL 1676NM-WM"}, /* 110-119 */ - { TUNER_ABSENT, "Thompson DTT75105"}, - { TUNER_ABSENT, "Conexant_CX24109"}, - { TUNER_TCL_2002N, "TCL M2523_5N_E"}, - { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, - { TUNER_ABSENT, "Philips 8275A"}, - { TUNER_ABSENT, "Microtune MT2060"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, - { TUNER_ABSENT, "TCL M2523_3DI_E"}, - { TUNER_ABSENT, "Samsung THPD5222FG30A"}, + { TUNER_ABSENT, "Thompson DTT75105"}, + { TUNER_ABSENT, "Conexant_CX24109"}, + { TUNER_TCL_2002N, "TCL M2523_5N_E"}, + { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, + { TUNER_ABSENT, "Philips 8275A"}, + { TUNER_ABSENT, "Microtune MT2060"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, + { TUNER_ABSENT, "TCL M2523_3DI_E"}, + { TUNER_ABSENT, "Samsung THPD5222FG30A"}, /* 120-129 */ - { TUNER_XC2028, "Xceive XC3028"}, - { TUNER_ABSENT, "Philips FQ1216LME MK5"}, - { TUNER_ABSENT, "Philips FQD1216LME"}, - { TUNER_ABSENT, "Conexant CX24118A"}, - { TUNER_ABSENT, "TCL DMF11WIP"}, - { TUNER_ABSENT, "TCL MFNM05_4H_E"}, - { TUNER_ABSENT, "TCL MNM05_4H_E"}, - { TUNER_ABSENT, "TCL MPE05_2H_E"}, - { TUNER_ABSENT, "TCL MQNM05_4_U"}, - { TUNER_ABSENT, "TCL M2523_5NH_E"}, + { TUNER_ABSENT, "Xceive XC3028"}, + { TUNER_ABSENT, "Philips FQ1216LME MK5"}, + { TUNER_ABSENT, "Philips FQD1216LME"}, + { TUNER_ABSENT, "Conexant CX24118A"}, + { TUNER_ABSENT, "TCL DMF11WIP"}, + { TUNER_ABSENT, "TCL MFNM05_4H_E"}, + { TUNER_ABSENT, "TCL MNM05_4H_E"}, + { TUNER_ABSENT, "TCL MPE05_2H_E"}, + { TUNER_ABSENT, "TCL MQNM05_4_U"}, + { TUNER_ABSENT, "TCL M2523_5NH_E"}, /* 130-139 */ - { TUNER_ABSENT, "TCL M2523_3DBH_E"}, - { TUNER_ABSENT, "TCL M2523_3DIH_E"}, - { TUNER_ABSENT, "TCL MFPE05_2_U"}, - { TUNER_ABSENT, "Philips FMD1216MEX"}, - { TUNER_ABSENT, "Philips FRH2036B"}, - { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, - { TUNER_ABSENT, "MaxLinear MXL5005"}, - { TUNER_ABSENT, "MaxLinear MXL5003"}, - { TUNER_ABSENT, "Xceive XC2028"}, - { TUNER_ABSENT, "Microtune MT2131"}, + { TUNER_ABSENT, "TCL M2523_3DBH_E"}, + { TUNER_ABSENT, "TCL M2523_3DIH_E"}, + { TUNER_ABSENT, "TCL MFPE05_2_U"}, + { TUNER_ABSENT, "Philips FMD1216MEX"}, + { TUNER_ABSENT, "Philips FRH2036B"}, + { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, + { TUNER_ABSENT, "MaxLinear MXL5005"}, + { TUNER_ABSENT, "MaxLinear MXL5003"}, + { TUNER_ABSENT, "Xceive XC2028"}, + { TUNER_ABSENT, "Microtune MT2131"}, /* 140-149 */ - { TUNER_ABSENT, "Philips 8275A_8295"}, - { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, - { TUNER_ABSENT, "Microtune MT2266"}, - { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, - { TUNER_ABSENT, "LG TAPQ_H702F"}, - { TUNER_ABSENT, "TCL M09WPP_4N_E"}, - { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, - /* 150-159 */ - { TUNER_ABSENT, "Xceive XC5000"}, + { TUNER_ABSENT, "Philips 8275A_8295"}, + { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, + { TUNER_ABSENT, "Microtune MT2266"}, + { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, + { TUNER_ABSENT, "LG TAPQ_H702F"}, + { TUNER_ABSENT, "TCL M09WPP_4N_E"}, + { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, + { TUNER_ABSENT, "Philips 18271_8295"}, }; static struct HAUPPAUGE_AUDIOIC @@ -348,37 +344,37 @@ static const char *decoderIC[] = { static int hasRadioTuner(int tunerType) { switch (tunerType) { - case 18: /* PNPEnv_TUNER_FR1236_MK2 */ - case 23: /* PNPEnv_TUNER_FM1236 */ - case 38: /* PNPEnv_TUNER_FMR1236 */ - case 16: /* PNPEnv_TUNER_FR1216_MK2 */ - case 19: /* PNPEnv_TUNER_FR1246_MK2 */ - case 21: /* PNPEnv_TUNER_FM1216 */ - case 24: /* PNPEnv_TUNER_FM1246 */ - case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */ - case 22: /* PNPEnv_TUNER_FM1216MF */ - case 20: /* PNPEnv_TUNER_FR1256_MK2 */ - case 25: /* PNPEnv_TUNER_FM1256 */ - case 33: /* PNPEnv_TUNER_4039FR5 */ - case 42: /* PNPEnv_TUNER_4009FR5 */ - case 52: /* PNPEnv_TUNER_4049FM5 */ - case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */ - case 44: /* PNPEnv_TUNER_4009FN5 */ - case 31: /* PNPEnv_TUNER_TCPB9085P */ - case 30: /* PNPEnv_TUNER_TCPN9085D */ - case 46: /* PNPEnv_TUNER_TP18NSR01F */ - case 47: /* PNPEnv_TUNER_TP18PSB01D */ - case 49: /* PNPEnv_TUNER_TAPC_I001D */ - case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */ - case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */ - case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */ - case 58: /* PNPEnv_TUNER_FM1236_MK3 */ - case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */ - case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */ - case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */ - case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */ - case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */ - case 105: + case 18: //PNPEnv_TUNER_FR1236_MK2: + case 23: //PNPEnv_TUNER_FM1236: + case 38: //PNPEnv_TUNER_FMR1236: + case 16: //PNPEnv_TUNER_FR1216_MK2: + case 19: //PNPEnv_TUNER_FR1246_MK2: + case 21: //PNPEnv_TUNER_FM1216: + case 24: //PNPEnv_TUNER_FM1246: + case 17: //PNPEnv_TUNER_FR1216MF_MK2: + case 22: //PNPEnv_TUNER_FM1216MF: + case 20: //PNPEnv_TUNER_FR1256_MK2: + case 25: //PNPEnv_TUNER_FM1256: + case 33: //PNPEnv_TUNER_4039FR5: + case 42: //PNPEnv_TUNER_4009FR5: + case 52: //PNPEnv_TUNER_4049FM5: + case 54: //PNPEnv_TUNER_4049FM5_AltI2C: + case 44: //PNPEnv_TUNER_4009FN5: + case 31: //PNPEnv_TUNER_TCPB9085P: + case 30: //PNPEnv_TUNER_TCPN9085D: + case 46: //PNPEnv_TUNER_TP18NSR01F: + case 47: //PNPEnv_TUNER_TP18PSB01D: + case 49: //PNPEnv_TUNER_TAPC_I001D: + case 60: //PNPEnv_TUNER_TAPE_S001D_MK3: + case 57: //PNPEnv_TUNER_FM1216ME_MK3: + case 59: //PNPEnv_TUNER_FM1216MP_MK3: + case 58: //PNPEnv_TUNER_FM1236_MK3: + case 68: //PNPEnv_TUNER_TAPE_H001F_MK3: + case 61: //PNPEnv_TUNER_TAPE_M001D_MK3: + case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM: + case 89: //PNPEnv_TUNER_TCL_MFPE05_2: + case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4: + case 105: return 1; } return 0; @@ -396,8 +392,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ** ** In our (ivtv) case we're interested in the following: ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) - ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into - ** hauppauge_tuner_fmt) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) ** decoder proc: tag [09].01) @@ -410,9 +405,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ** # of inputs/outputs ??? */ - int i, j, len, done, beenhere, tag, start; + int i, j, len, done, beenhere, tag,start; - int tuner1 = 0, t_format1 = 0, audioic = -1; + int tuner1 = 0, t_format1 = 0, audioic=-1; char *t_name1 = NULL; const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; @@ -423,24 +418,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, memset(tvee, 0, sizeof(*tvee)); done = len = beenhere = 0; - /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ - if (eeprom_data[0] == 0x1a && - eeprom_data[1] == 0xeb && - eeprom_data[2] == 0x67 && - eeprom_data[3] == 0x95) - start = 0xa0; /* Generic em28xx offset */ - else if ((eeprom_data[0] & 0xe1) == 0x01 && - eeprom_data[1] == 0x00 && - eeprom_data[2] == 0x00 && - eeprom_data[8] == 0x84) - start = 8; /* Generic cx2388x offset */ - else if (eeprom_data[1] == 0x70 && - eeprom_data[2] == 0x00 && - eeprom_data[4] == 0x74 && - eeprom_data[8] == 0x84) - start = 8; /* Generic cx23418 offset (models 74xxx) */ + /* Hack for processing eeprom for em28xx and cx 2388x*/ + if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) && + (eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95)) + start=0xa0; /* Generic em28xx offset */ + else if (((eeprom_data[0] & 0xe1) == 0x01) && + (eeprom_data[1] == 0x00) && + (eeprom_data[2] == 0x00) && + (eeprom_data[8] == 0x84)) + start=8; /* Generic cx2388x offset */ else - start = 0; + start=0; for (i = start; !done && i < 256; i += len) { if (eeprom_data[i] == 0x84) { @@ -456,17 +444,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ++i; } else { tveeprom_warn("Encountered bad packet header [%02x]. " - "Corrupt or not a Hauppauge eeprom.\n", - eeprom_data[i]); + "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); return; } if (debug) { - tveeprom_info("Tag [%02x] + %d bytes:", - eeprom_data[i], len - 1); - for (j = 1; j < len; j++) - printk(KERN_CONT " %02x", eeprom_data[i + j]); - printk(KERN_CONT "\n"); + tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1); + for(j = 1; j < len; j++) { + printk(" %02x", eeprom_data[i + j]); + } + printk("\n"); } /* process by tag */ @@ -517,16 +504,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); - if ((eeprom_data[i + 8] & 0xf0) && - (tvee->serial_number < 0xffffff)) { - tvee->MAC_address[0] = 0x00; - tvee->MAC_address[1] = 0x0D; - tvee->MAC_address[2] = 0xFE; - tvee->MAC_address[3] = eeprom_data[i + 7]; - tvee->MAC_address[4] = eeprom_data[i + 6]; - tvee->MAC_address[5] = eeprom_data[i + 5]; - tvee->has_MAC_address = 1; - } + if ( (eeprom_data[i + 8] & 0xf0) && + (tvee->serial_number < 0xffffff) ) { + tvee->MAC_address[0] = 0x00; + tvee->MAC_address[1] = 0x0D; + tvee->MAC_address[2] = 0xFE; + tvee->MAC_address[3] = eeprom_data[i + 7]; + tvee->MAC_address[4] = eeprom_data[i + 6]; + tvee->MAC_address[5] = eeprom_data[i + 5]; + tvee->has_MAC_address = 1; + } break; case 0x05: @@ -550,7 +537,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i + 3] << 16) + (eeprom_data[i + 4] << 24); tvee->revision = - eeprom_data[i + 5] + + eeprom_data[i +5 ] + (eeprom_data[i + 6] << 8) + (eeprom_data[i + 7] << 16); break; @@ -570,16 +557,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, case 0x0a: /* tag 'Tuner' */ if (beenhere == 0) { - tuner1 = eeprom_data[i + 2]; - t_format1 = eeprom_data[i + 1]; + tuner1 = eeprom_data[i+2]; + t_format1 = eeprom_data[i+1]; beenhere = 1; } else { /* a second (radio) tuner may be present */ - tuner2 = eeprom_data[i + 2]; - t_format2 = eeprom_data[i + 1]; - /* not a TV tuner? */ - if (t_format2 == 0) + tuner2 = eeprom_data[i+2]; + t_format2 = eeprom_data[i+1]; + if (t_format2 == 0) { /* not a TV tuner? */ tvee->has_radio = 1; /* must be radio */ + } } break; @@ -607,8 +594,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, /* case 0x12: tag 'InfoBits' */ default: - tveeprom_dbg("Not sure what to do with tag [%02x]\n", - tag); + tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag); /* dump the rest of the packet? */ } } @@ -622,7 +608,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); - tvee->rev_str[3] = 32 + (tvee->revision & 0x3f); + tvee->rev_str[3] = 32 + ( tvee->revision & 0x3f); tvee->rev_str[4] = 0; } @@ -665,40 +651,44 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", tvee->model, tvee->rev_str, tvee->serial_number); - if (tvee->has_MAC_address == 1) + if (tvee->has_MAC_address == 1) { tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n", tvee->MAC_address[0], tvee->MAC_address[1], tvee->MAC_address[2], tvee->MAC_address[3], tvee->MAC_address[4], tvee->MAC_address[5]); + } tveeprom_info("tuner model is %s (idx %d, type %d)\n", t_name1, tuner1, tvee->tuner_type); tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], - t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], - t_fmt_name1[6], t_fmt_name1[7], t_format1); - if (tuner2) + t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], + t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], + t_format1); + if (tuner2) { tveeprom_info("second tuner model is %s (idx %d, type %d)\n", t_name2, tuner2, tvee->tuner2_type); - if (t_format2) + } + if (t_format2) { tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], - t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], - t_fmt_name2[6], t_fmt_name2[7], t_format2); - if (audioic < 0) { + t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], + t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], + t_format2); + } + if (audioic<0) { tveeprom_info("audio processor is unknown (no idx)\n"); - tvee->audio_processor = AUDIO_CHIP_UNKNOWN; + tvee->audio_processor=AUDIO_CHIP_UNKNOWN; } else { if (audioic < ARRAY_SIZE(audioIC)) tveeprom_info("audio processor is %s (idx %d)\n", - audioIC[audioic].name, audioic); + audioIC[audioic].name,audioic); else tveeprom_info("audio processor is unknown (idx %d)\n", audioic); } - if (tvee->decoder_processor) + if (tvee->decoder_processor) { tveeprom_info("decoder processor is %s (idx %d)\n", STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); + } if (tvee->has_ir == -1) tveeprom_info("has %sradio\n", tvee->has_radio ? "" : "no "); @@ -719,13 +709,11 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) int err; buf = 0; - err = i2c_master_send(c, &buf, 1); - if (err != 1) { + if (1 != (err = i2c_master_send(c, &buf, 1))) { tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); return -1; } - err = i2c_master_recv(c, eedata, len); - if (err != len) { + if (len != (err = i2c_master_recv(c, eedata, len))) { tveeprom_warn("i2c eeprom read error (err=%d)\n", err); return -1; } @@ -736,9 +724,9 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) for (i = 0; i < len; i++) { if (0 == (i % 16)) tveeprom_info("%02x:", i); - printk(KERN_CONT " %02x", eedata[i]); + printk(" %02x", eedata[i]); if (15 == (i % 16)) - printk(KERN_CONT "\n"); + printk("\n"); } } return 0; @@ -770,9 +758,9 @@ tveeprom_command(struct i2c_client *client, switch (cmd) { case 0: - buf = kzalloc(256, GFP_KERNEL); - tveeprom_read(client, buf, 256); - tveeprom_hauppauge_analog(client, &eeprom, buf); + buf = kzalloc(256,GFP_KERNEL); + tveeprom_read(client,buf,256); + tveeprom_hauppauge_analog(client, &eeprom,buf); kfree(buf); eeprom_props[0] = eeprom.tuner_type; eeprom_props[1] = eeprom.tuner_formats; @@ -806,7 +794,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter, } static int -tveeprom_attach_adapter(struct i2c_adapter *adapter) +tveeprom_attach_adapter (struct i2c_adapter *adapter) { if (adapter->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adapter, &addr_data, tveeprom_detect_client); @@ -814,7 +802,7 @@ tveeprom_attach_adapter(struct i2c_adapter *adapter) } static int -tveeprom_detach_client(struct i2c_client *client) +tveeprom_detach_client (struct i2c_client *client) { int err; diff --git a/trunk/drivers/media/video/upd64031a.c b/trunk/drivers/media/video/upd64031a.c index bd201397a2ac..0b2a961efd22 100644 --- a/trunk/drivers/media/video/upd64031a.c +++ b/trunk/drivers/media/video/upd64031a.c @@ -28,27 +28,30 @@ #include #include #include -#include #include -/* --------------------- read registers functions define -------------------- */ +// --------------------- read registers functions define ----------------------- /* bit masks */ #define GR_MODE_MASK 0xc0 #define DIRECT_3DYCS_CONNECT_MASK 0xc0 #define SYNC_CIRCUIT_MASK 0xa0 -/* -------------------------------------------------------------------------- */ +// ----------------------------------------------------------------------------- MODULE_DESCRIPTION("uPD64031A driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); +static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; enum { R00 = 0, R01, R02, R03, R04, @@ -96,7 +99,7 @@ static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val) buf[0] = reg; buf[1] = val; - v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val); + v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val); if (i2c_master_send(client, buf, 2) != 2) v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); } @@ -116,7 +119,7 @@ static void upd64031a_change(struct i2c_client *client) /* ------------------------------------------------------------------------ */ -static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) +static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct upd64031a_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -140,10 +143,8 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) state->gr_mode = (route->input & 3) << 6; state->direct_3dycs_connect = (route->input & 0xc) << 4; - state->ext_comp_sync = - (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1; - state->ext_vert_sync = - (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2; + state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1; + state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2; r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode; r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) | state->ext_comp_sync | state->ext_vert_sync; @@ -167,23 +168,20 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, - reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) { + if (cmd == VIDIOC_DBG_G_REGISTER) reg->val = upd64031a_read(client, reg->reg & 0xff); - break; - } - upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff); + else + upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff); break; } #endif case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, - V4L2_IDENT_UPD64031A, 0); + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0); default: break; @@ -195,43 +193,90 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64031a_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct upd64031a_state *state; int i; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) { + return -ENOMEM; + } + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "uPD64031A"); - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); - if (state == NULL) + if (state == NULL) { + kfree(client); return -ENOMEM; + } i2c_set_clientdata(client, state); memcpy(state->regs, upd64031a_init, sizeof(state->regs)); state->gr_mode = UPD64031A_GR_ON << 6; state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4; state->ext_comp_sync = state->ext_vert_sync = 0; - for (i = 0; i < TOT_REGS; i++) + for (i = 0; i < TOT_REGS; i++) { upd64031a_write(client, i, state->regs[i]); + } + + i2c_attach_client(client); + return 0; } -static int upd64031a_remove(struct i2c_client *client) +static int upd64031a_probe(struct i2c_adapter *adapter) { - kfree(i2c_get_clientdata(client)); + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, upd64031a_attach); return 0; } -/* ----------------------------------------------------------------------- */ +static int upd64031a_detach(struct i2c_client *client) +{ + int err; + err = i2c_detach_client(client); + if (err) + return err; -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "upd64031a", - .driverid = I2C_DRIVERID_UPD64031A, + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "upd64031a", + }, + .id = I2C_DRIVERID_UPD64031A, + .attach_adapter = upd64031a_probe, + .detach_client = upd64031a_detach, .command = upd64031a_command, - .probe = upd64031a_probe, - .remove = upd64031a_remove, }; + + +static int __init upd64031a_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit upd64031a_exit_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(upd64031a_init_module); +module_exit(upd64031a_exit_module); diff --git a/trunk/drivers/media/video/upd64083.c b/trunk/drivers/media/video/upd64083.c index 2d9a88f70c85..401bd21f46eb 100644 --- a/trunk/drivers/media/video/upd64083.c +++ b/trunk/drivers/media/video/upd64083.c @@ -17,8 +17,7 @@ * * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include @@ -28,18 +27,21 @@ #include #include #include -#include #include MODULE_DESCRIPTION("uPD64083 driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static int debug = 0; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); +static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; enum { R00 = 0, R01, R02, R03, R04, @@ -86,7 +88,7 @@ static void upd64083_write(struct i2c_client *client, u8 reg, u8 val) buf[0] = reg; buf[1] = val; - v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val); + v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val); if (i2c_master_send(client, buf, 2) != 2) v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); } @@ -107,7 +109,7 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg) /* ------------------------------------------------------------------------ */ -static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) +static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct upd64083_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -143,23 +145,20 @@ static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, - reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) { + if (cmd == VIDIOC_DBG_G_REGISTER) reg->val = upd64083_read(client, reg->reg & 0xff); - break; - } - upd64083_write(client, reg->reg & 0xff, reg->val & 0xff); + else + upd64083_write(client, reg->reg & 0xff, reg->val & 0xff); break; } #endif case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, - V4L2_IDENT_UPD64083, 0); + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0); default: break; @@ -172,43 +171,89 @@ static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64083_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct upd64083_state *state; int i; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) { + return -ENOMEM; + } + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "uPD64083"); - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); - if (state == NULL) + if (state == NULL) { + kfree(client); return -ENOMEM; + } i2c_set_clientdata(client, state); /* Initially assume that a ghost reduction chip is present */ state->mode = 0; /* YCS mode */ state->ext_y_adc = (1 << 5); memcpy(state->regs, upd64083_init, TOT_REGS); - for (i = 0; i < TOT_REGS; i++) + for (i = 0; i < TOT_REGS; i++) { upd64083_write(client, i, state->regs[i]); + } + i2c_attach_client(client); + return 0; } -static int upd64083_remove(struct i2c_client *client) +static int upd64083_probe(struct i2c_adapter *adapter) { - kfree(i2c_get_clientdata(client)); + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, upd64083_attach); return 0; } -/* ----------------------------------------------------------------------- */ +static int upd64083_detach(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) + return err; + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "upd64083", - .driverid = I2C_DRIVERID_UPD64083, +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "upd64083", + }, + .id = I2C_DRIVERID_UPD64083, + .attach_adapter = upd64083_probe, + .detach_client = upd64083_detach, .command = upd64083_command, - .probe = upd64083_probe, - .remove = upd64083_remove, }; + + +static int __init upd64083_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit upd64083_exit_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(upd64083_init_module); +module_exit(upd64083_exit_module); diff --git a/trunk/drivers/media/video/usbvision/usbvision-cards.c b/trunk/drivers/media/video/usbvision/usbvision-cards.c index 503b13beb922..f09eb102731b 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-cards.c +++ b/trunk/drivers/media/video/usbvision/usbvision-cards.c @@ -901,20 +901,6 @@ struct usbvision_device_data_st usbvision_device_data[] = { .Y_Offset = -1, .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM", }, - [PINNA_PCTV_USB_NTSC_FM_V3] = { - .Interface = -1, - .Codec = CODEC_SAA7111, - .VideoChannels = 3, - .VideoNorm = V4L2_STD_NTSC, - .AudioChannels = 1, - .Radio = 1, - .vbi = 1, - .Tuner = 1, - .TunerType = TUNER_PHILIPS_NTSC_M, - .X_Offset = -1, - .Y_Offset = -1, - .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V3", - }, [PINNA_PCTV_USB_PAL_FM_V2] = { .Interface = -1, .Codec = CODEC_SAA7113, @@ -1058,7 +1044,7 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN }, { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 }, { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL }, - { USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 }, + { USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 }, { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG }, { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I }, { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L }, @@ -1088,8 +1074,6 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM }, { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB }, { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM }, - { USB_DEVICE(0x2304, 0x0113), - .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 }, { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 }, { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 }, { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 }, diff --git a/trunk/drivers/media/video/usbvision/usbvision-cards.h b/trunk/drivers/media/video/usbvision/usbvision-cards.h index 9c6ad22960d8..512c5cee4145 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-cards.h +++ b/trunk/drivers/media/video/usbvision/usbvision-cards.h @@ -62,6 +62,5 @@ #define PINNA_LINX_VD_IN_CAB_PAL 61 #define PINNA_PCTV_BUNGEE_PAL_FM 62 #define HPG_WINTV 63 -#define PINNA_PCTV_USB_NTSC_FM_V3 64 extern const int usbvision_device_data_size; diff --git a/trunk/drivers/media/video/usbvision/usbvision-core.c b/trunk/drivers/media/video/usbvision/usbvision-core.c index 56775ab8b75d..c7d5f9ed22d7 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-core.c +++ b/trunk/drivers/media/video/usbvision/usbvision-core.c @@ -69,15 +69,6 @@ static int SwitchSVideoInput = 0; // To help people with Black and White outpu module_param(SwitchSVideoInput, int, 0444); MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)"); -static unsigned int adjust_X_Offset = -1; -module_param(adjust_X_Offset, int, 0644); -MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]"); - -static unsigned int adjust_Y_Offset = -1; -module_param(adjust_Y_Offset, int, 0644); -MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]"); - - #define ENABLE_HEXDUMP 0 /* Enable if you need it */ @@ -633,29 +624,25 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv); switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x07 & (gv >> 3)) | - (0xF8 & bv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = rv; - *f++ = gv; - *f++ = bv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = rv; - *f++ = gv; - *f++ = bv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x03 & (gv >> 3)) | - (0x7C & (bv << 2)); - break; + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); + *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = bv; + *f++ = gv; + *f++ = rv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = bv; + *f++ = gv; + *f++ = rv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); + *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); + break; } } clipmask_index += clipmask_add; @@ -669,29 +656,25 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv); switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x07 & (gv >> 3)) | - (0xF8 & bv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = rv; - *f++ = gv; - *f++ = bv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = rv; - *f++ = gv; - *f++ = bv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x03 & (gv >> 3)) | - (0x7C & (bv << 2)); - break; + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); + *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = bv; + *f++ = gv; + *f++ = rv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = bv; + *f++ = gv; + *f++ = rv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); + *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); + break; } } clipmask_index += clipmask_add; @@ -959,26 +942,22 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, *f++ = Y[Idx]; break; case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x03 & (gv >> 3)) | - (0x7C & (bv << 2)); + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); + *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); break; case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & rv) | - (0xE0 & (gv << 5)); - *f++ = (0x07 & (gv >> 3)) | - (0xF8 & bv); + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); + *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); break; case V4L2_PIX_FMT_RGB24: - *f++ = rv; - *f++ = gv; *f++ = bv; + *f++ = gv; + *f++ = rv; break; case V4L2_PIX_FMT_RGB32: - *f++ = rv; - *f++ = gv; *f++ = bv; + *f++ = gv; + *f++ = rv; f++; break; } @@ -1092,33 +1071,28 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_even++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; } } clipmask_even_index += clipmask_add; @@ -1136,33 +1110,28 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(r_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(b_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_even++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_even++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; } } clipmask_even_index += clipmask_add; @@ -1182,33 +1151,28 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_odd++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; } } clipmask_odd_index += clipmask_add; @@ -1226,33 +1190,28 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = - (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = - (0x07 & (g >> 3)) | - (0xF8 & LIMIT_RGB(b_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(r_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(b_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & LIMIT_RGB(r_)) | - (0xE0 & (g << 5)); - *f_odd++ = (0x03 & (g >> 3)) | - (0x7C & (LIMIT_RGB(b_) << 2)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_odd++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; } } clipmask_odd_index += clipmask_add; @@ -1602,10 +1561,13 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address, if (len > 8) { return -EFAULT; } +// down(&usbvision->ctrlUrbLock); if (usbvision->ctrlUrbBusy) { +// up(&usbvision->ctrlUrbLock); return -EBUSY; } usbvision->ctrlUrbBusy = 1; +// up(&usbvision->ctrlUrbLock); usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE; @@ -2138,21 +2100,11 @@ int usbvision_set_input(struct usb_usbvision *usbvision) value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8; } - if (adjust_X_Offset != -1) { - value[4] = adjust_X_Offset & 0xff; - value[5] = (adjust_X_Offset & 0x0300) >> 8; - } - if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) { value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff; value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8; } - if (adjust_Y_Offset != -1) { - value[6] = adjust_Y_Offset & 0xff; - value[7] = (adjust_Y_Offset & 0x0300) >> 8; - } - rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), USBVISION_OP_CODE, /* USBVISION specific code */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0, @@ -2290,18 +2242,14 @@ static void call_usbvision_power_off(struct work_struct *work) struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork); PDEBUG(DBG_FUNC, ""); - if(mutex_lock_interruptible(&usbvision->lock)) { - return; - } - - + down_interruptible(&usbvision->lock); if(usbvision->user == 0) { usbvision_i2c_unregister(usbvision); usbvision_power_off(usbvision); usbvision->initialized = 0; } - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); } static void usbvision_powerOffTimer(unsigned long data) diff --git a/trunk/drivers/media/video/usbvision/usbvision-video.c b/trunk/drivers/media/video/usbvision/usbvision-video.c index b52b826a30be..36e689fa16c0 100644 --- a/trunk/drivers/media/video/usbvision/usbvision-video.c +++ b/trunk/drivers/media/video/usbvision/usbvision-video.c @@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) /* If so far no errors then we shall start the camera */ if (!errCode) { - mutex_lock(&usbvision->lock); + down(&usbvision->lock); if (usbvision->power == 0) { usbvision_power_on(usbvision); usbvision_i2c_register(usbvision); @@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); } if (errCode) { @@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) (struct usb_usbvision *) video_get_drvdata(dev); PDEBUG(DBG_IO, "close"); - mutex_lock(&usbvision->lock); + down(&usbvision->lock); usbvision_audio_off(usbvision); usbvision_restart_isoc(usbvision); @@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input) if ((input >= usbvision->video_inputs) || (input < 0) ) return -EINVAL; - mutex_lock(&usbvision->lock); + down(&usbvision->lock); usbvision_muxsel(usbvision, input); usbvision_set_input(usbvision); usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return 0; } @@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) (struct usb_usbvision *) video_get_drvdata(dev); usbvision->tvnormId=*id; - mutex_lock(&usbvision->lock); + down(&usbvision->lock); call_i2c_clients(usbvision, VIDIOC_S_STD, &usbvision->tvnormId); - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); /* propagate the change to the decoder */ usbvision_muxsel(usbvision, usbvision->ctl_input); @@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, usbvision->curFrame = NULL; /* by now we are committed to the new data... */ - mutex_lock(&usbvision->lock); + down(&usbvision->lock); usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return 0; } @@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) PDEBUG(DBG_MMAP, "mmap"); - mutex_lock(&usbvision->lock); + down(&usbvision->lock); if (!USBVISION_IS_OPERATIONAL(usbvision)) { - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return -EFAULT; } if (!(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(usbvision->max_frame_size)) { - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return -EINVAL; } @@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (i == usbvision->num_frames) { PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range"); - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return -EINVAL; } @@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed"); - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) size -= PAGE_SIZE; } - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return 0; } @@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) PDEBUG(DBG_IO, "%s:", __FUNCTION__); - mutex_lock(&usbvision->lock); + down(&usbvision->lock); if (usbvision->user) { err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__); @@ -1290,8 +1290,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) errCode = usbvision_set_alternate(usbvision); if (errCode < 0) { usbvision->last_error = errCode; - errCode = -EBUSY; - goto out; + return -EBUSY; } // If so far no errors then we shall start the radio @@ -1308,8 +1307,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } -out: - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); return errCode; } @@ -1323,7 +1321,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) PDEBUG(DBG_IO, ""); - mutex_lock(&usbvision->lock); + down(&usbvision->lock); /* Set packet size to 0 */ usbvision->ifaceAlt=0; @@ -1339,7 +1337,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -1643,7 +1641,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) usbvision->dev = dev; - mutex_init(&usbvision->lock); /* available */ + init_MUTEX(&usbvision->lock); /* to 1 == available */ // prepare control urb for control messages during interrupts usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); @@ -1651,6 +1649,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) goto err_exit; } init_waitqueue_head(&usbvision->ctrlUrb_wq); + init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */ usbvision_init_powerOffTimer(usbvision); @@ -1677,13 +1676,13 @@ static void usbvision_release(struct usb_usbvision *usbvision) { PDEBUG(DBG_PROBE, ""); - mutex_lock(&usbvision->lock); + down(&usbvision->lock); usbvision_reset_powerOffTimer(usbvision); usbvision->initialized = 0; - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); usbvision_remove_sysfs(usbvision->vdev); usbvision_unregister_video(usbvision); @@ -1797,7 +1796,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, } PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); - mutex_lock(&usbvision->lock); + down(&usbvision->lock); /* compute alternate max packet sizes */ uif = dev->actconfig->interface[0]; @@ -1808,7 +1807,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->num_alt,GFP_KERNEL); if (usbvision->alt_max_pkt_size == NULL) { err("usbvision: out of memory!\n"); - mutex_unlock(&usbvision->lock); return -ENOMEM; } @@ -1842,7 +1840,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->streaming = Stream_Off; usbvision_register_video(usbvision); usbvision_configure_video(usbvision); - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); usb_set_intfdata (intf, usbvision); @@ -1873,7 +1871,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) } usb_set_intfdata (intf, NULL); - mutex_lock(&usbvision->lock); + down(&usbvision->lock); // At this time we ask to cancel outstanding URBs usbvision_stop_isoc(usbvision); @@ -1887,7 +1885,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usb_put_dev(usbvision->dev); usbvision->dev = NULL; // USB device is no more - mutex_unlock(&usbvision->lock); + up(&usbvision->lock); if (usbvision->user) { printk(KERN_INFO "%s: In use, disconnect pending\n", diff --git a/trunk/drivers/media/video/usbvision/usbvision.h b/trunk/drivers/media/video/usbvision/usbvision.h index 20d7ec624999..c5b6c501c869 100644 --- a/trunk/drivers/media/video/usbvision/usbvision.h +++ b/trunk/drivers/media/video/usbvision/usbvision.h @@ -34,13 +34,16 @@ #include #include #include -#include #include #include #include #define USBVISION_DEBUG /* Turn on debug messages */ +#ifndef VID_HARDWARE_USBVISION + #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */ +#endif + #define USBVISION_PWR_REG 0x00 #define USBVISION_SSPND_EN (1 << 1) #define USBVISION_RES2 (1 << 2) @@ -370,6 +373,7 @@ struct usb_usbvision { int ctrlUrbBusy; struct usb_ctrlrequest ctrlUrbSetup; wait_queue_head_t ctrlUrb_wq; // Processes waiting + struct semaphore ctrlUrbLock; /* configuration part */ int have_tuner; @@ -392,7 +396,7 @@ struct usb_usbvision { unsigned char iface; /* Video interface number */ unsigned char ifaceAlt; /* Alt settings */ unsigned char Vin_Reg2_Preset; - struct mutex lock; + struct semaphore lock; struct timer_list powerOffTimer; struct work_struct powerOffWork; int power; /* is the device powered on? */ diff --git a/trunk/drivers/media/video/v4l2-common.c b/trunk/drivers/media/video/v4l2-common.c index c056ff6d810c..1141b4bf41ce 100644 --- a/trunk/drivers/media/video/v4l2-common.c +++ b/trunk/drivers/media/video/v4l2-common.c @@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", - [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", + [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", @@ -1013,34 +1013,6 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip) /* ----------------------------------------------------------------- */ -/* Helper function for I2C legacy drivers */ - -int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, - const char *name, int (*probe)(struct i2c_client *)) -{ - struct i2c_client *client; - int err; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = driver; - strlcpy(client->name, name, sizeof(client->name)); - - err = probe(client); - if (err == 0) { - i2c_attach_client(client); - } else { - kfree(client); - } - return err != -ENOMEM ? 0 : err; -} - -/* ----------------------------------------------------------------- */ - EXPORT_SYMBOL(v4l2_norm_to_name); EXPORT_SYMBOL(v4l2_video_std_construct); @@ -1066,8 +1038,6 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client); EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); EXPORT_SYMBOL(v4l2_chip_match_host); -EXPORT_SYMBOL(v4l2_i2c_attach); - /* * Local variables: * c-basic-offset: 8 diff --git a/trunk/drivers/media/video/v4l2-int-device.c b/trunk/drivers/media/video/v4l2-int-device.c index a545dcaf857f..8b4ef530a3a8 100644 --- a/trunk/drivers/media/video/v4l2-int-device.c +++ b/trunk/drivers/media/video/v4l2-int-device.c @@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void) if (!try_module_get(m->module)) continue; - s->u.slave->master = m; - if (m->u.master->attach(s)) { - s->u.slave->master = NULL; + if (m->u.master->attach(m, s)) { module_put(m->module); continue; } + + s->u.slave->master = m; } } } diff --git a/trunk/drivers/media/video/videobuf-core.c b/trunk/drivers/media/video/videobuf-core.c index 80a14da9acef..c8a5cb57963b 100644 --- a/trunk/drivers/media/video/videobuf-core.c +++ b/trunk/drivers/media/video/videobuf-core.c @@ -22,32 +22,29 @@ #include #define MAGIC_BUFFER 0x20070728 -#define MAGIC_CHECK(is, should) do { \ - if (unlikely((is) != (should))) { \ - printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \ - BUG(); } } while (0) +#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ + { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } -static int debug; +static int debug = 0; module_param(debug, int, 0644); MODULE_DESCRIPTION("helper module to manage video4linux buffers"); MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); -#define dprintk(level, fmt, arg...) do { \ - if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0) +#define dprintk(level, fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "vbuf: " fmt , ## arg) /* --------------------------------------------------------------------- */ #define CALL(q, f, arg...) \ - ((q->int_ops->f) ? q->int_ops->f(arg) : 0) + ( (q->int_ops->f)? q->int_ops->f(arg) : 0) -void *videobuf_alloc(struct videobuf_queue *q) +void* videobuf_alloc(struct videobuf_queue* q) { struct videobuf_buffer *vb; - BUG_ON(q->msize < sizeof(*vb)); + BUG_ON (q->msizeint_ops || !q->int_ops->alloc) { printk(KERN_ERR "No specific ops defined!\n"); @@ -69,21 +66,20 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) int retval = 0; DECLARE_WAITQUEUE(wait, current); - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); add_wait_queue(&vb->done, &wait); - while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) { + while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { if (non_blocking) { retval = -EAGAIN; break; } set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (vb->state == VIDEOBUF_ACTIVE || - vb->state == VIDEOBUF_QUEUED) + if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) schedule(); set_current_state(TASK_RUNNING); if (intr && signal_pending(current)) { - dprintk(1, "buffer waiton: -EINTR\n"); + dprintk(1,"buffer waiton: -EINTR\n"); retval = -EINTR; break; } @@ -92,33 +88,27 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) return retval; } -int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, +int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf) { - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); - /* This is required to avoid OOPS on some cases, - since mmap_mapper() method should be called before _iolock. + /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper() + method should be called before _iolock. On some cases, the mmap_mapper() is called only after scheduling. + + However, this way is just too dirty! Better to wait for some event. */ - if (vb->memory == V4L2_MEMORY_MMAP) { - wait_event_timeout(vb->done, q->is_mmapped, - msecs_to_jiffies(100)); - if (!q->is_mmapped) { - printk(KERN_ERR - "Error: mmap_mapper() never called!\n"); - return -EINVAL; - } - } + schedule_timeout(HZ); - return CALL(q, iolock, q, vb, fbuf); + return CALL(q,iolock,q,vb,fbuf); } /* --------------------------------------------------------------------- */ -void videobuf_queue_core_init(struct videobuf_queue *q, +void videobuf_queue_core_init(struct videobuf_queue* q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, @@ -128,7 +118,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q, void *priv, struct videobuf_qtype_ops *int_ops) { - memset(q, 0, sizeof(*q)); + memset(q,0,sizeof(*q)); q->irqlock = irqlock; q->dev = dev; q->type = type; @@ -139,13 +129,13 @@ void videobuf_queue_core_init(struct videobuf_queue *q, q->int_ops = int_ops; /* All buffer operations are mandatory */ - BUG_ON(!q->ops->buf_setup); - BUG_ON(!q->ops->buf_prepare); - BUG_ON(!q->ops->buf_queue); - BUG_ON(!q->ops->buf_release); + BUG_ON (!q->ops->buf_setup); + BUG_ON (!q->ops->buf_prepare); + BUG_ON (!q->ops->buf_queue); + BUG_ON (!q->ops->buf_release); /* Having implementations for abstract methods are mandatory */ - BUG_ON(!q->int_ops); + BUG_ON (!q->int_ops); mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); @@ -156,33 +146,33 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) { int i; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); if (q->streaming) { - dprintk(1, "busy: streaming active\n"); + dprintk(1,"busy: streaming active\n"); return 1; } if (q->reading) { - dprintk(1, "busy: pending read #1\n"); + dprintk(1,"busy: pending read #1\n"); return 1; } if (q->read_buf) { - dprintk(1, "busy: pending read #2\n"); + dprintk(1,"busy: pending read #2\n"); return 1; } for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; if (q->bufs[i]->map) { - dprintk(1, "busy: buffer #%d mapped\n", i); + dprintk(1,"busy: buffer #%d mapped\n",i); return 1; } - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { - dprintk(1, "busy: buffer #%d queued\n", i); + if (q->bufs[i]->state == STATE_QUEUED) { + dprintk(1,"busy: buffer #%d queued\n",i); return 1; } - if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { - dprintk(1, "busy: buffer #%d avtive\n", i); + if (q->bufs[i]->state == STATE_ACTIVE) { + dprintk(1,"busy: buffer #%d avtive\n",i); return 1; } } @@ -192,28 +182,28 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) /* Locking: Caller holds q->lock */ void videobuf_queue_cancel(struct videobuf_queue *q) { - unsigned long flags = 0; + unsigned long flags=0; int i; /* remove queued buffers from list */ if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock,flags); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (q->bufs[i]->state == VIDEOBUF_QUEUED) { + if (q->bufs[i]->state == STATE_QUEUED) { list_del(&q->bufs[i]->queue); - q->bufs[i]->state = VIDEOBUF_ERROR; + q->bufs[i]->state = STATE_ERROR; } } if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock,flags); /* free all buffers + clear queue */ for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(q, q->bufs[i]); + q->ops->buf_release(q,q->bufs[i]); } INIT_LIST_HEAD(&q->stream); } @@ -243,8 +233,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q) static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, struct videobuf_buffer *vb, enum v4l2_buf_type type) { - MAGIC_CHECK(vb->magic, MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); b->index = vb->i; b->type = type; @@ -269,17 +259,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { - case VIDEOBUF_PREPARED: - case VIDEOBUF_QUEUED: - case VIDEOBUF_ACTIVE: + case STATE_PREPARED: + case STATE_QUEUED: + case STATE_ACTIVE: b->flags |= V4L2_BUF_FLAG_QUEUED; break; - case VIDEOBUF_DONE: - case VIDEOBUF_ERROR: + case STATE_DONE: + case STATE_ERROR: b->flags |= V4L2_BUF_FLAG_DONE; break; - case VIDEOBUF_NEEDS_INIT: - case VIDEOBUF_IDLE: + case STATE_NEEDS_INIT: + case STATE_IDLE: /* nothing */ break; } @@ -304,20 +294,16 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) if (!q) return 0; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - - - rc = CALL(q, mmap_free, q); - - q->is_mmapped = 0; + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); - if (rc < 0) + rc = CALL(q,mmap_free,q); + if (rc<0) return rc; for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(q, q->bufs[i]); + q->ops->buf_release(q,q->bufs[i]); kfree(q->bufs[i]); q->bufs[i] = NULL; } @@ -342,7 +328,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int i; int err; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); err = __videobuf_mmap_free(q); if (0 != err) @@ -373,7 +359,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q, if (!i) return -ENOMEM; - dprintk(1, "mmap setup: %d buffers, %d bytes each\n", + dprintk(1,"mmap setup: %d buffers, %d bytes each\n", i, bsize); return i; @@ -393,35 +379,35 @@ int videobuf_mmap_setup(struct videobuf_queue *q, int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req) { - unsigned int size, count; + unsigned int size,count; int retval; if (req->count < 1) { - dprintk(1, "reqbufs: count invalid (%d)\n", req->count); + dprintk(1,"reqbufs: count invalid (%d)\n",req->count); return -EINVAL; } if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR && req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1, "reqbufs: memory type invalid\n"); + dprintk(1,"reqbufs: memory type invalid\n"); return -EINVAL; } mutex_lock(&q->lock); if (req->type != q->type) { - dprintk(1, "reqbufs: queue type invalid\n"); + dprintk(1,"reqbufs: queue type invalid\n"); retval = -EINVAL; goto done; } if (q->streaming) { - dprintk(1, "reqbufs: streaming already exists\n"); + dprintk(1,"reqbufs: streaming already exists\n"); retval = -EBUSY; goto done; } if (!list_empty(&q->stream)) { - dprintk(1, "reqbufs: stream running\n"); + dprintk(1,"reqbufs: stream running\n"); retval = -EBUSY; goto done; } @@ -430,14 +416,14 @@ int videobuf_reqbufs(struct videobuf_queue *q, if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; size = 0; - q->ops->buf_setup(q, &count, &size); + q->ops->buf_setup(q,&count,&size); size = PAGE_ALIGN(size); - dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n", + dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", count, size, (count*size)>>PAGE_SHIFT); - retval = __videobuf_mmap_setup(q, count, size, req->memory); + retval = __videobuf_mmap_setup(q,count,size,req->memory); if (retval < 0) { - dprintk(1, "reqbufs: mmap setup returned %d\n", retval); + dprintk(1,"reqbufs: mmap setup returned %d\n",retval); goto done; } @@ -454,19 +440,19 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) mutex_lock(&q->lock); if (unlikely(b->type != q->type)) { - dprintk(1, "querybuf: Wrong type.\n"); + dprintk(1,"querybuf: Wrong type.\n"); goto done; } if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { - dprintk(1, "querybuf: index out of range.\n"); + dprintk(1,"querybuf: index out of range.\n"); goto done; } if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1, "querybuf: buffer is null.\n"); + dprintk(1,"querybuf: buffer is null.\n"); goto done; } - videobuf_status(q, b, q->bufs[b->index], q->type); + videobuf_status(q,b,q->bufs[b->index],q->type); ret = 0; done: @@ -479,10 +465,10 @@ int videobuf_qbuf(struct videobuf_queue *q, { struct videobuf_buffer *buf; enum v4l2_field field; - unsigned long flags = 0; + unsigned long flags=0; int retval; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); if (b->memory == V4L2_MEMORY_MMAP) down_read(¤t->mm->mmap_sem); @@ -490,36 +476,36 @@ int videobuf_qbuf(struct videobuf_queue *q, mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { - dprintk(1, "qbuf: Reading running...\n"); + dprintk(1,"qbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { - dprintk(1, "qbuf: Wrong type.\n"); + dprintk(1,"qbuf: Wrong type.\n"); goto done; } if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { - dprintk(1, "qbuf: index out of range.\n"); + dprintk(1,"qbuf: index out of range.\n"); goto done; } buf = q->bufs[b->index]; if (NULL == buf) { - dprintk(1, "qbuf: buffer is null.\n"); + dprintk(1,"qbuf: buffer is null.\n"); goto done; } - MAGIC_CHECK(buf->magic, MAGIC_BUFFER); + MAGIC_CHECK(buf->magic,MAGIC_BUFFER); if (buf->memory != b->memory) { - dprintk(1, "qbuf: memory type is wrong.\n"); + dprintk(1,"qbuf: memory type is wrong.\n"); goto done; } - if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { - dprintk(1, "qbuf: buffer is already queued or active.\n"); + if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { + dprintk(1,"qbuf: buffer is already queued or active.\n"); goto done; } if (b->flags & V4L2_BUF_FLAG_INPUT) { if (b->input >= q->inputs) { - dprintk(1, "qbuf: wrong input.\n"); + dprintk(1,"qbuf: wrong input.\n"); goto done; } buf->input = b->input; @@ -530,46 +516,44 @@ int videobuf_qbuf(struct videobuf_queue *q, switch (b->memory) { case V4L2_MEMORY_MMAP: if (0 == buf->baddr) { - dprintk(1, "qbuf: mmap requested " - "but buffer addr is zero!\n"); + dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); goto done; } break; case V4L2_MEMORY_USERPTR: if (b->length < buf->bsize) { - dprintk(1, "qbuf: buffer length is not enough\n"); + dprintk(1,"qbuf: buffer length is not enough\n"); goto done; } - if (VIDEOBUF_NEEDS_INIT != buf->state && - buf->baddr != b->m.userptr) - q->ops->buf_release(q, buf); + if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) + q->ops->buf_release(q,buf); buf->baddr = b->m.userptr; break; case V4L2_MEMORY_OVERLAY: buf->boff = b->m.offset; break; default: - dprintk(1, "qbuf: wrong memory type\n"); + dprintk(1,"qbuf: wrong memory type\n"); goto done; } - dprintk(1, "qbuf: requesting next field\n"); + dprintk(1,"qbuf: requesting next field\n"); field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, buf, field); + retval = q->ops->buf_prepare(q,buf,field); if (0 != retval) { - dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); + dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); goto done; } - list_add_tail(&buf->stream, &q->stream); + list_add_tail(&buf->stream,&q->stream); if (q->streaming) { if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, buf); + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock,flags); } - dprintk(1, "qbuf: succeded\n"); + dprintk(1,"qbuf: succeded\n"); retval = 0; done: @@ -587,49 +571,49 @@ int videobuf_dqbuf(struct videobuf_queue *q, struct videobuf_buffer *buf; int retval; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { - dprintk(1, "dqbuf: Reading running...\n"); + dprintk(1,"dqbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { - dprintk(1, "dqbuf: Wrong type.\n"); + dprintk(1,"dqbuf: Wrong type.\n"); goto done; } if (list_empty(&q->stream)) { - dprintk(1, "dqbuf: stream running\n"); + dprintk(1,"dqbuf: stream running\n"); goto done; } buf = list_entry(q->stream.next, struct videobuf_buffer, stream); retval = videobuf_waiton(buf, nonblocking, 1); if (retval < 0) { - dprintk(1, "dqbuf: waiton returned %d\n", retval); + dprintk(1,"dqbuf: waiton returned %d\n",retval); goto done; } switch (buf->state) { - case VIDEOBUF_ERROR: - dprintk(1, "dqbuf: state is error\n"); + case STATE_ERROR: + dprintk(1,"dqbuf: state is error\n"); retval = -EIO; - CALL(q, sync, q, buf); - buf->state = VIDEOBUF_IDLE; + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; break; - case VIDEOBUF_DONE: - dprintk(1, "dqbuf: state is done\n"); - CALL(q, sync, q, buf); - buf->state = VIDEOBUF_IDLE; + case STATE_DONE: + dprintk(1,"dqbuf: state is done\n"); + CALL(q,sync,q, buf); + buf->state = STATE_IDLE; break; default: - dprintk(1, "dqbuf: state invalid\n"); + dprintk(1,"dqbuf: state invalid\n"); retval = -EINVAL; goto done; } list_del(&buf->stream); - memset(b, 0, sizeof(*b)); - videobuf_status(q, b, buf, q->type); + memset(b,0,sizeof(*b)); + videobuf_status(q,b,buf,q->type); done: mutex_unlock(&q->lock); @@ -639,7 +623,7 @@ int videobuf_dqbuf(struct videobuf_queue *q, int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; - unsigned long flags = 0; + unsigned long flags=0; int retval; mutex_lock(&q->lock); @@ -651,12 +635,12 @@ int videobuf_streamon(struct videobuf_queue *q) goto done; q->streaming = 1; if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock,flags); list_for_each_entry(buf, &q->stream, stream) - if (buf->state == VIDEOBUF_PREPARED) - q->ops->buf_queue(q, buf); + if (buf->state == STATE_PREPARED) + q->ops->buf_queue(q,buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock,flags); done: mutex_unlock(&q->lock); @@ -692,10 +676,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, size_t count, loff_t *ppos) { enum v4l2_field field; - unsigned long flags = 0; + unsigned long flags=0; int retval; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); /* setup stuff */ q->read_buf = videobuf_alloc(q); @@ -707,20 +691,20 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, q->read_buf->bsize = count; field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); + retval = q->ops->buf_prepare(q,q->read_buf,field); if (0 != retval) goto done; /* start capture & wait */ if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); - retval = videobuf_waiton(q->read_buf, 0, 0); + spin_unlock_irqrestore(q->irqlock,flags); + retval = videobuf_waiton(q->read_buf,0,0); if (0 == retval) { - CALL(q, sync, q, q->read_buf); - if (VIDEOBUF_ERROR == q->read_buf->state) + CALL(q,sync,q,q->read_buf); + if (STATE_ERROR == q->read_buf->state) retval = -EIO; else retval = q->read_buf->size; @@ -728,7 +712,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, done: /* cleanup */ - q->ops->buf_release(q, q->read_buf); + q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); q->read_buf = NULL; return retval; @@ -739,21 +723,21 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, int nonblocking) { enum v4l2_field field; - unsigned long flags = 0; + unsigned long flags=0; unsigned size, nbufs; int retval; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); mutex_lock(&q->lock); nbufs = 1; size = 0; - q->ops->buf_setup(q, &nbufs, &size); + q->ops->buf_setup(q,&nbufs,&size); if (NULL == q->read_buf && count >= size && !nonblocking) { - retval = videobuf_read_zerocopy(q, data, count, ppos); + retval = videobuf_read_zerocopy(q,data,count,ppos); if (retval >= 0 || retval == -EIO) /* ok, all done */ goto done; @@ -765,25 +749,25 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, retval = -ENOMEM; q->read_buf = videobuf_alloc(q); - dprintk(1, "video alloc=0x%p\n", q->read_buf); + dprintk(1,"video alloc=0x%p\n", q->read_buf); if (NULL == q->read_buf) goto done; q->read_buf->memory = V4L2_MEMORY_USERPTR; q->read_buf->bsize = count; /* preferred size */ field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q, q->read_buf, field); + retval = q->ops->buf_prepare(q,q->read_buf,field); if (0 != retval) { - kfree(q->read_buf); + kfree (q->read_buf); q->read_buf = NULL; goto done; } if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q, q->read_buf); + q->ops->buf_queue(q,q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock,flags); q->read_off = 0; } @@ -792,11 +776,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, if (0 != retval) goto done; - CALL(q, sync, q, q->read_buf); + CALL(q,sync,q,q->read_buf); - if (VIDEOBUF_ERROR == q->read_buf->state) { + if (STATE_ERROR == q->read_buf->state) { /* catch I/O errors */ - q->ops->buf_release(q, q->read_buf); + q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); q->read_buf = NULL; retval = -EIO; @@ -804,14 +788,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Copy to userspace */ - retval = CALL(q, video_copy_to_user, q, data, count, nonblocking); - if (retval < 0) + retval=CALL(q,video_copy_to_user,q,data,count,nonblocking); + if (retval<0) goto done; q->read_off += retval; if (q->read_off == q->read_buf->size) { /* all data copied, cleanup */ - q->ops->buf_release(q, q->read_buf); + q->ops->buf_release(q,q->read_buf); kfree(q->read_buf); q->read_buf = NULL; } @@ -822,14 +806,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Locking: Caller holds q->lock */ -static int __videobuf_read_start(struct videobuf_queue *q) +int __videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; - unsigned long flags = 0; + unsigned long flags=0; unsigned int count = 0, size = 0; int err, i; - q->ops->buf_setup(q, &count, &size); + q->ops->buf_setup(q,&count,&size); if (count < 2) count = 2; if (count > VIDEO_MAX_FRAME) @@ -844,17 +828,17 @@ static int __videobuf_read_start(struct videobuf_queue *q) for (i = 0; i < count; i++) { field = videobuf_next_field(q); - err = q->ops->buf_prepare(q, q->bufs[i], field); + err = q->ops->buf_prepare(q,q->bufs[i],field); if (err) return err; list_add_tail(&q->bufs[i]->stream, &q->stream); } if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); + spin_lock_irqsave(q->irqlock,flags); for (i = 0; i < count; i++) - q->ops->buf_queue(q, q->bufs[i]); + q->ops->buf_queue(q,q->bufs[i]); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock,flags); q->reading = 1; return 0; } @@ -875,7 +859,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q) } q->read_buf = NULL; q->reading = 0; - + } int videobuf_read_start(struct videobuf_queue *q) @@ -915,11 +899,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, int vbihack, int nonblocking) { int rc, retval; - unsigned long flags = 0; + unsigned long flags=0; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); - dprintk(2, "%s\n", __FUNCTION__); + dprintk(2,"%s\n",__FUNCTION__); mutex_lock(&q->lock); retval = -EBUSY; if (q->streaming) @@ -947,8 +931,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, break; } - if (q->read_buf->state == VIDEOBUF_DONE) { - rc = CALL(q, copy_stream, q, data + retval, count, + if (q->read_buf->state == STATE_DONE) { + rc = CALL (q,copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { retval = rc; @@ -969,10 +953,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, list_add_tail(&q->read_buf->stream, &q->stream); if (q->irqlock) - spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q, q->read_buf); + spin_lock_irqsave(q->irqlock,flags); + q->ops->buf_queue(q,q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock, flags); + spin_unlock_irqrestore(q->irqlock,flags); q->read_buf = NULL; } if (retval < 0) @@ -1015,8 +999,8 @@ unsigned int videobuf_poll_stream(struct file *file, if (0 == rc) { poll_wait(file, &buf->done, wait); - if (buf->state == VIDEOBUF_DONE || - buf->state == VIDEOBUF_ERROR) + if (buf->state == STATE_DONE || + buf->state == STATE_ERROR) rc = POLLIN|POLLRDNORM; } mutex_unlock(&q->lock); @@ -1028,11 +1012,10 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, { int retval; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); mutex_lock(&q->lock); - retval = CALL(q, mmap_mapper, q, vma); - q->is_mmapped = 1; + retval=CALL(q,mmap_mapper,q,vma); mutex_unlock(&q->lock); return retval; @@ -1043,15 +1026,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q, struct video_mbuf *mbuf, int count) { struct v4l2_requestbuffers req; - int rc, i; + int rc,i; - MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); - memset(&req, 0, sizeof(req)); + memset(&req,0,sizeof(req)); req.type = q->type; req.count = count; req.memory = V4L2_MEMORY_MMAP; - rc = videobuf_reqbufs(q, &req); + rc = videobuf_reqbufs(q,&req); if (rc < 0) return rc; @@ -1096,3 +1079,9 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream); EXPORT_SYMBOL_GPL(videobuf_mmap_setup); EXPORT_SYMBOL_GPL(videobuf_mmap_free); EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/trunk/drivers/media/video/videobuf-dma-sg.c b/trunk/drivers/media/video/videobuf-dma-sg.c index 98efd7ab1f50..44ee408e145f 100644 --- a/trunk/drivers/media/video/videobuf-dma-sg.c +++ b/trunk/drivers/media/video/videobuf-dma-sg.c @@ -385,27 +385,30 @@ videobuf_vm_close(struct vm_area_struct *vma) * now ...). Bounce buffers don't work very well for the data rates * video capture has. */ -static int -videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +static struct page* +videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, + int *type) { struct page *page; - dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n", - (unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end); + dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", + vaddr,vma->vm_start,vma->vm_end); + if (vaddr > vma->vm_end) + return NOPAGE_SIGBUS; page = alloc_page(GFP_USER | __GFP_DMA32); if (!page) - return VM_FAULT_OOM; - clear_user_page(page_address(page), (unsigned long)vmf->virtual_address, - page); - vmf->page = page; - return 0; + return NOPAGE_OOM; + clear_user_page(page_address(page), vaddr, page); + if (type) + *type = VM_FAULT_MINOR; + return page; } static struct vm_operations_struct videobuf_vm_ops = { .open = videobuf_vm_open, .close = videobuf_vm_close, - .fault = videobuf_vm_fault, + .nopage = videobuf_vm_nopage, }; /* --------------------------------------------------------------------- diff --git a/trunk/drivers/media/video/videobuf-dvb.c b/trunk/drivers/media/video/videobuf-dvb.c index b73aba65d21d..880317e04a02 100644 --- a/trunk/drivers/media/video/videobuf-dvb.c +++ b/trunk/drivers/media/video/videobuf-dvb.c @@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data) /* feed buffer data to demux */ dma=videobuf_to_dma(buf); - if (buf->state == VIDEOBUF_DONE) + if (buf->state == STATE_DONE) dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); diff --git a/trunk/drivers/media/video/videobuf-vmalloc.c b/trunk/drivers/media/video/videobuf-vmalloc.c index 9b3898347ca5..e01259438bb2 100644 --- a/trunk/drivers/media/video/videobuf-vmalloc.c +++ b/trunk/drivers/media/video/videobuf-vmalloc.c @@ -41,7 +41,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); #define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) + printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) /***************************************************************************/ diff --git a/trunk/drivers/media/video/videodev.c b/trunk/drivers/media/video/videodev.c index 28655f8983c6..9611c3990285 100644 --- a/trunk/drivers/media/video/videodev.c +++ b/trunk/drivers/media/video/videodev.c @@ -973,7 +973,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, *id = vfd->current_norm; - dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); + dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); ret=0; break; @@ -982,7 +982,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *id = arg,norm; - dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); + dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); norm = (*id) & vfd->tvnorms; if ( vfd->tvnorms && !norm) /* Check if std is supported */ @@ -1008,7 +1008,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, break; ret=vfd->vidioc_querystd(file, fh, arg); if (!ret) - dbgarg (cmd, "detected std=%08Lx\n", + dbgarg (cmd, "detected std=%Lu\n", (unsigned long long)*p); break; } @@ -1028,7 +1028,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!ret) dbgarg (cmd, "index=%d, name=%s, type=%d, " "audioset=%d, " - "tuner=%d, std=%08Lx, status=%d\n", + "tuner=%d, std=%Ld, status=%d\n", p->index,p->name,p->type,p->audioset, p->tuner, (unsigned long long)p->std, diff --git a/trunk/drivers/media/video/vivi.c b/trunk/drivers/media/video/vivi.c index 1db067c02815..9b54ff9d2e36 100644 --- a/trunk/drivers/media/video/vivi.c +++ b/trunk/drivers/media/video/vivi.c @@ -44,18 +44,21 @@ #define WAKE_DENOMINATOR 1001 #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ +/* These timers are for 1 fps - used only for testing */ +//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */ +//#define BUFFER_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ + #include "font.h" #define VIVI_MAJOR_VERSION 0 #define VIVI_MINOR_VERSION 4 #define VIVI_RELEASE 0 -#define VIVI_VERSION \ - KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) +#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) /* Declare static vars that will be used as parameters */ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ +static struct video_device vivi; /* Video device */ static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ -static int n_devs = 1; /* Number of virtual devices */ /* supported controls */ static struct v4l2_queryctrl vivi_qctrl[] = { @@ -68,7 +71,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = { .default_value = 65535, .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, - }, { + },{ .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", @@ -109,9 +112,9 @@ static struct v4l2_queryctrl vivi_qctrl[] = { static int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; -#define dprintk(dev, level, fmt, arg...) \ +#define dprintk(level,fmt, arg...) \ do { \ - if (dev->vfd->debug >= (level)) \ + if (vivi.debug >= (level)) \ printk(KERN_DEBUG "vivi: " fmt , ## arg); \ } while (0) @@ -163,21 +166,17 @@ struct vivi_dev { struct list_head vivi_devlist; struct mutex lock; - spinlock_t slock; int users; /* various device info */ - struct video_device *vfd; + struct video_device vfd; struct vivi_dmaqueue vidq; /* Several counters */ - int h, m, s, ms; - unsigned long jiffies; + int h,m,s,us,jiffies; char timestr[13]; - - int mv_count; /* Controls bars movement */ }; struct vivi_fh { @@ -185,7 +184,7 @@ struct vivi_fh { /* video capture */ struct vivi_fmt *fmt; - unsigned int width, height; + unsigned int width,height; struct videobuf_queue vb_vidq; enum v4l2_buf_type type; @@ -204,113 +203,109 @@ enum colors { GREEN, MAGENTA, RED, - BLUE, - BLACK, + BLUE }; static u8 bars[8][3] = { /* R G B */ - {204, 204, 204}, /* white */ - {208, 208, 0}, /* ambar */ - { 0, 206, 206}, /* cyan */ - { 0, 239, 0}, /* green */ - {239, 0, 239}, /* magenta */ - {205, 0, 0}, /* red */ - { 0, 0, 255}, /* blue */ - { 0, 0, 0}, /* black */ + {204,204,204}, /* white */ + {208,208, 0}, /* ambar */ + { 0,206,206}, /* cyan */ + { 0,239, 0}, /* green */ + {239, 0,239}, /* magenta */ + {205, 0, 0}, /* red */ + { 0, 0,255}, /* blue */ + { 0, 0, 0} }; -#define TO_Y(r, g, b) \ - (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) +#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b + 32768)>>16)+16) /* RGB to V(Cr) Color transform */ -#define TO_V(r, g, b) \ - (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) +#define TO_V(r,g,b) (((28784*r -24103*g -4681*b + 32768)>>16)+128) /* RGB to U(Cb) Color transform */ -#define TO_U(r, g, b) \ - (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) +#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128) #define TSTAMP_MIN_Y 24 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 -static void gen_line(char *basep, int inipos, int wmax, - int hmax, int line, int count, char *timestr) +static void gen_line(char *basep,int inipos,int wmax, + int hmax, int line, int count, char *timestr) { - int w, i, j, y; - int pos = inipos; - char *p, *s; - u8 chr, r, g, b, color; + int w,i,j,pos=inipos,y; + char *p,*s; + u8 chr,r,g,b,color; /* We will just duplicate the second pixel at the packet */ - wmax /= 2; + wmax/=2; /* Generate a standard color bar pattern */ - for (w = 0; w < wmax; w++) { - int colorpos = ((w + count) * 8/(wmax + 1)) % 8; - r = bars[colorpos][0]; - g = bars[colorpos][1]; - b = bars[colorpos][2]; + for (w=0;w= hmax) + if (TSTAMP_MAX_Y>=hmax) goto end; - if (TSTAMP_MIN_X + strlen(timestr) >= wmax) + if (TSTAMP_MIN_X+strlen(timestr)>=wmax) goto end; /* Print stream time */ - if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { - j = TSTAMP_MIN_X; - for (s = timestr; *s; s++) { - chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; - for (i = 0; i < 7; i++) { - if (chr & 1 << (7 - i)) { - /* Font color*/ - r = 0; - g = 198; - b = 0; - } else { - /* Background color */ - r = bars[BLACK][0]; - g = bars[BLACK][1]; - b = bars[BLACK][2]; + if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) { + j=TSTAMP_MIN_X; + for (s=timestr;*s;s++) { + chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; + for (i=0;i<7;i++) { + if (chr&1<<(7-i)) { /* Font color*/ + r=bars[BLUE][0]; + g=bars[BLUE][1]; + b=bars[BLUE][2]; + r=g=b=0; + g=198; + } else { /* Background color */ + r=bars[WHITE][0]; + g=bars[WHITE][1]; + b=bars[WHITE][2]; + r=g=b=0; } - pos = inipos + j * 2; - for (color = 0; color < 4; color++) { - p = basep + pos; + pos=inipos+j*2; + for (color=0;color<4;color++) { + p=basep+pos; - y = TO_Y(r, g, b); + y=TO_Y(r,g,b); switch (color) { - case 0: - case 2: - *p = TO_Y(r, g, b); /* Luma */ - break; - case 1: - *p = TO_U(r, g, b); /* Cb */ - break; - case 3: - *p = TO_V(r, g, b); /* Cr */ - break; + case 0: + case 2: + *p=TO_Y(r,g,b); /* Luminance */ + break; + case 1: + *p=TO_U(r,g,b); /* Cb */ + break; + case 3: + *p=TO_V(r,g,b); /* Cr */ + break; } pos++; } @@ -319,60 +314,63 @@ static void gen_line(char *basep, int inipos, int wmax, } } + end: return; } -static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) +static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) { - int h , pos = 0; + int h,pos=0; int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; - char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL); - void *vbuf = videobuf_to_vmalloc(&buf->vb); + char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL); + void *vbuf=videobuf_to_vmalloc (&buf->vb); + /* FIXME: move to dev struct */ + static int mv_count=0; if (!tmpbuf) return; - for (h = 0; h < hmax; h++) { - gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count, + for (h=0;htimestr); /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0) - dprintk(dev, 2, "vivifill copy_to_user failed.\n"); + if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) + dprintk(2,"vivifill copy_to_user failed.\n"); pos += wmax*2; } - dev->mv_count++; + mv_count++; kfree(tmpbuf); /* Updates stream time */ - dev->ms += jiffies_to_msecs(jiffies-dev->jiffies); - dev->jiffies = jiffies; - if (dev->ms >= 1000) { - dev->ms -= 1000; + dev->us+=jiffies_to_usecs(jiffies-dev->jiffies); + dev->jiffies=jiffies; + if (dev->us>=1000000) { + dev->us-=1000000; dev->s++; - if (dev->s >= 60) { - dev->s -= 60; + if (dev->s>=60) { + dev->s-=60; dev->m++; - if (dev->m > 60) { - dev->m -= 60; + if (dev->m>60) { + dev->m-=60; dev->h++; - if (dev->h > 24) - dev->h -= 24; + if (dev->h>24) + dev->h-=24; } } } - sprintf(dev->timestr, "%02d:%02d:%02d:%03d", - dev->h, dev->m, dev->s, dev->ms); + sprintf(dev->timestr,"%02d:%02d:%02d:%03d", + dev->h,dev->m,dev->s,(dev->us+500)/1000); - dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", - dev->timestr, (unsigned long)tmpbuf, pos); + dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, + (unsigned long)tmpbuf,pos); /* Advice that buffer was filled */ - buf->vb.state = VIDEOBUF_DONE; + buf->vb.state = STATE_DONE; buf->vb.field_count++; do_gettimeofday(&ts); buf->vb.ts = ts; @@ -386,15 +384,14 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q); static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) { struct vivi_buffer *buf; - struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); + struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq); int bc; - spin_lock(&dev->slock); /* Announces videobuf that all went ok */ for (bc = 0;; bc++) { if (list_empty(&dma_q->active)) { - dprintk(dev, 1, "No active queue to serve\n"); + dprintk(1,"No active queue to serve\n"); break; } @@ -404,89 +401,65 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) /* Nobody is waiting something to be done, just return */ if (!waitqueue_active(&buf->vb.done)) { mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); - spin_unlock(&dev->slock); return; } do_gettimeofday(&buf->vb.ts); - dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); + dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i); /* Fill buffer */ - vivi_fillbuff(dev, buf); + vivi_fillbuff(dev,buf); if (list_empty(&dma_q->active)) { del_timer(&dma_q->timeout); } else { - mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT); + mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); } } if (bc != 1) - dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n", - __FUNCTION__, bc); - spin_unlock(&dev->slock); + dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); } -#define frames_to_ms(frames) \ - ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) - static void vivi_sleep(struct vivi_dmaqueue *dma_q) { - struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); - int timeout, running_time; + int timeout; DECLARE_WAITQUEUE(wait, current); - dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, - (unsigned long)dma_q); + dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); add_wait_queue(&dma_q->wq, &wait); - if (kthread_should_stop()) - goto stop_task; - - running_time = jiffies - dma_q->ini_jiffies; - dma_q->frame++; - - /* Calculate time to wake up */ - timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time; - - if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) { - int old = dma_q->frame; - int nframes; + if (!kthread_should_stop()) { + dma_q->frame++; - dma_q->frame = (jiffies_to_msecs(running_time) / - frames_to_ms(1)) + 1; + /* Calculate time to wake up */ + timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; - timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - - running_time; + if (timeout <= 0) { + int old=dma_q->frame; + dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1; - if (unlikely (timeout <= 0)) - timeout = 1; + timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; - nframes = (dma_q->frame > old)? - dma_q->frame - old : old - dma_q->frame; + dprintk(1,"underrun, losed %d frames. " + "Now, frame is %d. Waking on %d jiffies\n", + dma_q->frame-old,dma_q->frame,timeout); + } else + dprintk(1,"will sleep for %i jiffies\n",timeout); - dprintk(dev, 1, "%ld: %s %d frames. " - "Current frame is %d. Will sleep for %d jiffies\n", - jiffies, - (dma_q->frame > old)? "Underrun, losed" : "Overrun of", - nframes, dma_q->frame, timeout); - } else - dprintk(dev, 1, "will sleep for %d jiffies\n", timeout); + vivi_thread_tick(dma_q); - vivi_thread_tick(dma_q); - - schedule_timeout_interruptible(timeout); + schedule_timeout_interruptible (timeout); + } -stop_task: remove_wait_queue(&dma_q->wq, &wait); try_to_freeze(); } static int vivi_thread(void *data) { - struct vivi_dmaqueue *dma_q = data; - struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); + struct vivi_dmaqueue *dma_q=data; - dprintk(dev, 1, "thread started\n"); + dprintk(1,"thread started\n"); mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); set_freezable(); @@ -497,18 +470,16 @@ static int vivi_thread(void *data) if (kthread_should_stop()) break; } - dprintk(dev, 1, "thread: exit\n"); + dprintk(1, "thread: exit\n"); return 0; } static int vivi_start_thread(struct vivi_dmaqueue *dma_q) { - struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); + dma_q->frame=0; + dma_q->ini_jiffies=jiffies; - dma_q->frame = 0; - dma_q->ini_jiffies = jiffies; - - dprintk(dev, 1, "%s\n", __FUNCTION__); + dprintk(1,"%s\n",__FUNCTION__); dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi"); @@ -519,43 +490,39 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q) /* Wakes thread */ wake_up_interruptible(&dma_q->wq); - dprintk(dev, 1, "returning from %s\n", __FUNCTION__); + dprintk(1,"returning from %s\n",__FUNCTION__); return 0; } static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) { - struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); - - dprintk(dev, 1, "%s\n", __FUNCTION__); + dprintk(1,"%s\n",__FUNCTION__); /* shutdown control thread */ if (dma_q->kthread) { kthread_stop(dma_q->kthread); - dma_q->kthread = NULL; + dma_q->kthread=NULL; } } static int restart_video_queue(struct vivi_dmaqueue *dma_q) { - struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); struct vivi_buffer *buf, *prev; - dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, - (unsigned long)dma_q); + dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); if (!list_empty(&dma_q->active)) { - buf = list_entry(dma_q->active.next, - struct vivi_buffer, vb.queue); - dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n", + buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue); + dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); - dprintk(dev, 1, "Restarting video dma\n"); + dprintk(1,"Restarting video dma\n"); vivi_stop_thread(dma_q); +// vivi_start_thread(dma_q); /* cancel all outstanding capture / vbi requests */ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; + buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); } mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); @@ -567,31 +534,28 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) for (;;) { if (list_empty(&dma_q->queued)) return 0; - buf = list_entry(dma_q->queued.next, - struct vivi_buffer, vb.queue); + buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue); if (NULL == prev) { list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &dma_q->active); + list_add_tail(&buf->vb.queue,&dma_q->active); - dprintk(dev, 1, "Restarting video dma\n"); + dprintk(1,"Restarting video dma\n"); vivi_stop_thread(dma_q); vivi_start_thread(dma_q); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(dev, 2, - "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); + dprintk(2,"[%p/%d] restart_queue - first active\n", + buf,buf->vb.i); } else if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &dma_q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(dev, 2, - "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); + list_add_tail(&buf->vb.queue,&dma_q->active); + buf->vb.state = STATE_ACTIVE; + dprintk(2,"[%p/%d] restart_queue - move to active\n", + buf,buf->vb.i); } else { return 0; } @@ -601,23 +565,19 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) static void vivi_vid_timeout(unsigned long data) { - struct vivi_dev *dev = (struct vivi_dev *)data; + struct vivi_dev *dev = (struct vivi_dev*)data; struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_buffer *buf; - spin_lock(&dev->slock); - while (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, - struct vivi_buffer, vb.queue); + buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; + buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); - printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); + printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); } - restart_video_queue(vidq); - spin_unlock(&dev->slock); + restart_video_queue(vidq); } /* ------------------------------------------------------------------ @@ -626,8 +586,7 @@ static void vivi_vid_timeout(unsigned long data) static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { - struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = fh->dev; + struct vivi_fh *fh = vq->priv_data; *size = fh->width*fh->height*2; @@ -637,25 +596,21 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) while (*size * *count > vid_limit * 1024 * 1024) (*count)--; - dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__, - *count, *size); + dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size); return 0; } static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { - struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = fh->dev; - - dprintk(dev, 1, "%s\n", __FUNCTION__); + dprintk(1,"%s\n",__FUNCTION__); if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb, 0, 0); + videobuf_waiton(&buf->vb,0,0); videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + buf->vb.state = STATE_NEEDS_INIT; } #define norm_maxw() 1024 @@ -665,11 +620,10 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = fh->dev; - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); + struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); int rc, init_buffer = 0; - dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field); + dprintk(1,"%s, field=%d\n",__FUNCTION__,field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || @@ -690,81 +644,75 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, init_buffer = 1; } - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) + if (STATE_NEEDS_INIT == buf->vb.state) { + if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL))) goto fail; } - buf->vb.state = VIDEOBUF_PREPARED; + buf->vb.state = STATE_PREPARED; return 0; fail: - free_buffer(vq, buf); + free_buffer(vq,buf); return rc; } static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = fh->dev; - struct vivi_dmaqueue *vidq = &dev->vidq; + struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); + struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; + struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_buffer *prev; if (!list_empty(&vidq->queued)) { - dprintk(dev, 1, "adding vb queue=0x%08lx\n", - (unsigned long)&buf->vb.queue); - list_add_tail(&buf->vb.queue, &vidq->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n", + dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue); + list_add_tail(&buf->vb.queue,&vidq->queued); + buf->vb.state = STATE_QUEUED; + dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&vidq->active)) { - list_add_tail(&buf->vb.queue, &vidq->active); + list_add_tail(&buf->vb.queue,&vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; + buf->vb.state = STATE_ACTIVE; mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n", + dprintk(2,"[%p/%d] buffer_queue - first active\n", buf, buf->vb.i); vivi_start_thread(vidq); } else { - prev = list_entry(vidq->active.prev, - struct vivi_buffer, vb.queue); + prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue); if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = VIDEOBUF_ACTIVE; - dprintk(dev, 2, - "[%p/%d] buffer_queue - append to active\n", + list_add_tail(&buf->vb.queue,&vidq->active); + buf->vb.state = STATE_ACTIVE; + dprintk(2,"[%p/%d] buffer_queue - append to active\n", buf, buf->vb.i); } else { - list_add_tail(&buf->vb.queue, &vidq->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(dev, 2, - "[%p/%d] buffer_queue - first queued\n", + list_add_tail(&buf->vb.queue,&vidq->queued); + buf->vb.state = STATE_QUEUED; + dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } } } -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); + struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = (struct vivi_dev *)fh->dev; + struct vivi_dev *dev = (struct vivi_dev*)fh->dev; struct vivi_dmaqueue *vidq = &dev->vidq; - dprintk(dev, 1, "%s\n", __FUNCTION__); + dprintk(1,"%s\n",__FUNCTION__); vivi_stop_thread(vidq); - free_buffer(vq, buf); + free_buffer(vq,buf); } static struct videobuf_queue_ops vivi_video_qops = { @@ -777,7 +725,7 @@ static struct videobuf_queue_ops vivi_video_qops = { /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ -static int vidioc_querycap(struct file *file, void *priv, +static int vidioc_querycap (struct file *file, void *priv, struct v4l2_capability *cap) { strcpy(cap->driver, "vivi"); @@ -789,21 +737,21 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap(struct file *file, void *priv, +static int vidioc_enum_fmt_cap (struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index > 0) return -EINVAL; - strlcpy(f->description, format.name, sizeof(f->description)); + strlcpy(f->description,format.name,sizeof(f->description)); f->pixelformat = format.fourcc; return 0; } -static int vidioc_g_fmt_cap(struct file *file, void *priv, +static int vidioc_g_fmt_cap (struct file *file, void *priv, struct v4l2_format *f) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; f->fmt.pix.width = fh->width; f->fmt.pix.height = fh->height; @@ -817,29 +765,26 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv, return (0); } -static int vidioc_try_fmt_cap(struct file *file, void *priv, +static int vidioc_try_fmt_cap (struct file *file, void *priv, struct v4l2_format *f) { - struct vivi_fh *fh = priv; - struct vivi_dev *dev = fh->dev; struct vivi_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; if (format.fourcc != f->fmt.pix.pixelformat) { - dprintk(dev, 1, "Fourcc format (0x%08x) invalid. " - "Driver accepts only 0x%08x\n", - f->fmt.pix.pixelformat, format.fourcc); + dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts " + "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc); return -EINVAL; } - fmt = &format; + fmt=&format; field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_INTERLACED; + field=V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { - dprintk(dev, 1, "Field type invalid.\n"); + dprintk(1,"Field type invalid.\n"); return -EINVAL; } @@ -865,11 +810,11 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, } /*FIXME: This seems to be generic enough to be at videodev2 */ -static int vidioc_s_fmt_cap(struct file *file, void *priv, +static int vidioc_s_fmt_cap (struct file *file, void *priv, struct v4l2_format *f) { - struct vivi_fh *fh = priv; - int ret = vidioc_try_fmt_cap(file, fh, f); + struct vivi_fh *fh=priv; + int ret = vidioc_try_fmt_cap(file,fh,f); if (ret < 0) return (ret); @@ -882,48 +827,47 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, return (0); } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) +static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; return (videobuf_reqbufs(&fh->vb_vidq, p)); } -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; return (videobuf_querybuf(&fh->vb_vidq, p)); } -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; return (videobuf_qbuf(&fh->vb_vidq, p)); } -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; return (videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK)); } #ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; - return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); + return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8); } #endif static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -935,7 +879,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct vivi_fh *fh = priv; + struct vivi_fh *fh=priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -945,32 +889,32 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->vb_vidq); } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) +static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i) { return 0; } /* only one input in this sample driver */ -static int vidioc_enum_input(struct file *file, void *priv, +static int vidioc_enum_input (struct file *file, void *priv, struct v4l2_input *inp) { if (inp->index != 0) return -EINVAL; inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_525_60; - strcpy(inp->name, "Camera"); + inp->std = V4L2_STD_NTSC_M; + strcpy(inp->name,"Camera"); return (0); } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) { *i = 0; return (0); } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +static int vidioc_s_input (struct file *file, void *priv, unsigned int i) { if (i > 0) return -EINVAL; @@ -979,8 +923,8 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) } /* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int vidioc_queryctrl (struct file *file, void *priv, + struct v4l2_queryctrl *qc) { int i; @@ -994,31 +938,33 @@ static int vidioc_queryctrl(struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +static int vidioc_g_ctrl (struct file *file, void *priv, + struct v4l2_control *ctrl) { int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { - ctrl->value = qctl_regs[i]; + ctrl->value=qctl_regs[i]; return (0); } return -EINVAL; } -static int vidioc_s_ctrl(struct file *file, void *priv, +static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { - if (ctrl->value < vivi_qctrl[i].minimum - || ctrl->value > vivi_qctrl[i].maximum) { + if (ctrl->value < + vivi_qctrl[i].minimum + || ctrl->value > + vivi_qctrl[i].maximum) { return (-ERANGE); } - qctl_regs[i] = ctrl->value; + qctl_regs[i]=ctrl->value; return (0); } return -EINVAL; @@ -1037,22 +983,24 @@ static int vivi_open(struct inode *inode, struct file *file) struct vivi_fh *fh; int i; - printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor); + printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); list_for_each_entry(dev, &vivi_devlist, vivi_devlist) - if (dev->vfd->minor == minor) + if (dev->vfd.minor == minor) goto found; return -ENODEV; - found: + + + /* If more than one user, mutex should be added */ dev->users++; - dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor, + dprintk(1, "open minor=%d type=%s users=%d\n", minor, v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); + fh = kzalloc(sizeof(*fh),GFP_KERNEL); if (NULL == fh) { dev->users--; return -ENOMEM; @@ -1068,21 +1016,27 @@ static int vivi_open(struct inode *inode, struct file *file) /* Put all controls at a sane state */ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) - qctl_regs[i] = vivi_qctrl[i].default_value; + qctl_regs[i] =vivi_qctrl[i].default_value; + + dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", + (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq); + dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued)); + dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active)); /* Resets frame counters */ - dev->h = 0; - dev->m = 0; - dev->s = 0; - dev->ms = 0; - dev->mv_count = 0; - dev->jiffies = jiffies; - sprintf(dev->timestr, "%02d:%02d:%02d:%03d", - dev->h, dev->m, dev->s, dev->ms); + dev->h=0; + dev->m=0; + dev->s=0; + dev->us=0; + dev->jiffies=jiffies; + sprintf(dev->timestr,"%02d:%02d:%02d:%03d", + dev->h,dev->m,dev->s,(dev->us+500)/1000); videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, - NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, - sizeof(struct vivi_buffer), fh); + NULL, NULL, + fh->type, + V4L2_FIELD_INTERLACED, + sizeof(struct vivi_buffer),fh); return 0; } @@ -1090,9 +1044,9 @@ static int vivi_open(struct inode *inode, struct file *file) static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - struct vivi_fh *fh = file->private_data; + struct vivi_fh *fh = file->private_data; - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } @@ -1103,10 +1057,9 @@ static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; - struct vivi_dev *dev = fh->dev; struct videobuf_queue *q = &fh->vb_vidq; - dprintk(dev, 1, "%s\n", __FUNCTION__); + dprintk(1,"%s\n",__FUNCTION__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; @@ -1114,7 +1067,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) return videobuf_poll_stream(file, q, wait); } -static int vivi_close(struct inode *inode, struct file *file) +static int vivi_release(struct inode *inode, struct file *file) { struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; @@ -1126,48 +1079,26 @@ static int vivi_close(struct inode *inode, struct file *file) videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); - kfree(fh); + kfree (fh); dev->users--; - dprintk(dev, 1, "close called (minor=%d, users=%d)\n", - minor, dev->users); + printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users); return 0; } -static int vivi_release(void) -{ - struct vivi_dev *dev; - struct list_head *list; - - while (!list_empty(&vivi_devlist)) { - list = vivi_devlist.next; - list_del(list); - dev = list_entry(list, struct vivi_dev, vivi_devlist); - - if (-1 != dev->vfd->minor) - video_unregister_device(dev->vfd); - else - video_device_release(dev->vfd); - - kfree(dev); - } - - return 0; -} - -static int vivi_mmap(struct file *file, struct vm_area_struct *vma) +static int +vivi_mmap(struct file *file, struct vm_area_struct * vma) { - struct vivi_fh *fh = file->private_data; - struct vivi_dev *dev = fh->dev; + struct vivi_fh *fh = file->private_data; int ret; - dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); + dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma); - ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); + ret=videobuf_mmap_mapper(&fh->vb_vidq, vma); - dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", + dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, ret); @@ -1178,7 +1109,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma) static const struct file_operations vivi_fops = { .owner = THIS_MODULE, .open = vivi_open, - .release = vivi_close, + .release = vivi_release, .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ @@ -1186,12 +1117,12 @@ static const struct file_operations vivi_fops = { .llseek = no_llseek, }; -static struct video_device vivi_template = { +static struct video_device vivi = { .name = "vivi", .type = VID_TYPE_CAPTURE, .fops = &vivi_fops, .minor = -1, - .release = video_device_release, +// .release = video_device_release, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, @@ -1214,7 +1145,7 @@ static struct video_device vivi_template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif - .tvnorms = V4L2_STD_525_60, + .tvnorms = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M, }; /* ----------------------------------------------------------------- @@ -1223,61 +1154,43 @@ static struct video_device vivi_template = { static int __init vivi_init(void) { - int ret = -ENOMEM, i; + int ret; struct vivi_dev *dev; - struct video_device *vfd; - - for (i = 0; i < n_devs; i++) { - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) - break; - list_add_tail(&dev->vivi_devlist, &vivi_devlist); - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - init_waitqueue_head(&dev->vidq.wq); - - /* initialize locks */ - mutex_init(&dev->lock); - spin_lock_init(&dev->slock); - - dev->vidq.timeout.function = vivi_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - - vfd = video_device_alloc(); - if (NULL == vfd) - break; - - *vfd = vivi_template; - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); - if (ret < 0) - break; + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + return -ENOMEM; + list_add_tail(&dev->vivi_devlist,&vivi_devlist); - snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", - vivi_template.name, vfd->minor); + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + init_waitqueue_head(&dev->vidq.wq); - if (video_nr >= 0) - video_nr++; + /* initialize locks */ + mutex_init(&dev->lock); - dev->vfd = vfd; - } + dev->vidq.timeout.function = vivi_vid_timeout; + dev->vidq.timeout.data = (unsigned long)dev; + init_timer(&dev->vidq.timeout); - if (ret < 0) { - vivi_release(); - printk(KERN_INFO "Error %d while loading vivi driver\n", ret); - } else - printk(KERN_INFO "Video Technology Magazine Virtual Video " - "Capture Board successfully loaded.\n"); + ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr); + printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret); return ret; } static void __exit vivi_exit(void) { - vivi_release(); + struct vivi_dev *h; + struct list_head *list; + + while (!list_empty(&vivi_devlist)) { + list = vivi_devlist.next; + list_del(list); + h = list_entry(list, struct vivi_dev, vivi_devlist); + kfree (h); + } + video_unregister_device(&vivi); } module_init(vivi_init); @@ -1288,13 +1201,10 @@ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); MODULE_LICENSE("Dual BSD/GPL"); module_param(video_nr, int, 0); -MODULE_PARM_DESC(video_nr, "video iminor start number"); -module_param(n_devs, int, 0); -MODULE_PARM_DESC(n_devs, "number of video devices to create"); +module_param_named(debug,vivi.debug, int, 0644); +MODULE_PARM_DESC(debug,"activates debug info"); -module_param_named(debug, vivi_template.debug, int, 0444); -MODULE_PARM_DESC(debug, "activates debug info"); +module_param(vid_limit,int,0644); +MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); -module_param(vid_limit, int, 0644); -MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); diff --git a/trunk/drivers/media/video/vp27smpx.c b/trunk/drivers/media/video/vp27smpx.c index 282c81403c97..63002e0ac764 100644 --- a/trunk/drivers/media/video/vp27smpx.c +++ b/trunk/drivers/media/video/vp27smpx.c @@ -30,12 +30,15 @@ #include #include #include -#include MODULE_DESCRIPTION("vp27smpx driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); +static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ @@ -50,26 +53,28 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) u8 data[3] = { 0x00, 0x00, 0x04 }; switch (audmode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - data[1] = 0x01; - break; - case V4L2_TUNER_MODE_LANG2: - data[1] = 0x02; - break; + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + data[1] = 0x01; + break; + case V4L2_TUNER_MODE_LANG2: + data[1] = 0x02; + break; } - if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) - v4l_err(client, "%s: I/O error setting audmode\n", - client->name); - else + if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) { + v4l_err(client, "%s: I/O error setting audmode\n", client->name); + } + else { state->audmode = audmode; + } } -static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) +static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, + void *arg) { struct vp27smpx_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; @@ -98,8 +103,7 @@ static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, - V4L2_IDENT_VP27SMPX, 0); + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Audio Mode: %u%s\n", state->audmode, @@ -121,43 +125,88 @@ static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int vp27smpx_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct vp27smpx_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); - if (state == NULL) + if (state == NULL) { + kfree(client); return -ENOMEM; + } state->audmode = V4L2_TUNER_MODE_STEREO; i2c_set_clientdata(client, state); /* initialize vp27smpx */ vp27smpx_set_audmode(client, state->audmode); + i2c_attach_client(client); + return 0; } -static int vp27smpx_remove(struct i2c_client *client) +static int vp27smpx_probe(struct i2c_adapter *adapter) { - kfree(i2c_get_clientdata(client)); + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, vp27smpx_attach); + return 0; +} + +static int vp27smpx_detach(struct i2c_client *client) +{ + struct vp27smpx_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(state); + kfree(client); + return 0; } /* ----------------------------------------------------------------------- */ -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "vp27smpx", - .driverid = I2C_DRIVERID_VP27SMPX, - .command = vp27smpx_command, - .probe = vp27smpx_probe, - .remove = vp27smpx_remove, +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "vp27smpx", + }, + .id = I2C_DRIVERID_VP27SMPX, + .attach_adapter = vp27smpx_probe, + .detach_client = vp27smpx_detach, + .command = vp27smpx_command, }; + +static int __init vp27smpx_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit vp27smpx_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(vp27smpx_init_module); +module_exit(vp27smpx_cleanup_module); diff --git a/trunk/drivers/media/video/wm8739.c b/trunk/drivers/media/video/wm8739.c index 31795b4f8b63..1bf4cbec6a87 100644 --- a/trunk/drivers/media/video/wm8739.c +++ b/trunk/drivers/media/video/wm8739.c @@ -30,19 +30,21 @@ #include #include #include -#include MODULE_DESCRIPTION("wm8739 driver"); MODULE_AUTHOR("T. Adachi, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug; +static int debug = 0; +static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END }; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); +I2C_CLIENT_INSMOD; + /* ------------------------------------------------------------------------ */ enum { @@ -73,10 +75,12 @@ static int wm8739_write(struct i2c_client *client, int reg, u16 val) v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val); - for (i = 0; i < 3; i++) - if (i2c_smbus_write_byte_data(client, - (reg << 1) | (val >> 8), val & 0xff) == 0) + for (i = 0; i < 3; i++) { + if (i2c_smbus_write_byte_data(client, (reg << 1) | + (val >> 8), val & 0xff) == 0) { return 0; + } + } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } @@ -163,7 +167,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { .default_value = 58880, .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, - }, { + },{ .id = V4L2_CID_AUDIO_MUTE, .name = "Mute", .minimum = 0, @@ -172,7 +176,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { .default_value = 1, .flags = 0, .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { + },{ .id = V4L2_CID_AUDIO_BALANCE, .name = "Balance", .minimum = 0, @@ -186,7 +190,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { /* ------------------------------------------------------------------------ */ -static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) +static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct wm8739_state *state = i2c_get_clientdata(client); @@ -196,26 +200,21 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) u32 audiofreq = *(u32 *)arg; state->clock_freq = audiofreq; - /* de-activate */ - wm8739_write(client, R9, 0x000); + wm8739_write(client, R9, 0x000); /* de-activate */ switch (audiofreq) { case 44100: - /* 256fps, fs=44.1k */ - wm8739_write(client, R8, 0x020); + wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k */ break; case 48000: - /* 256fps, fs=48k */ - wm8739_write(client, R8, 0x000); + wm8739_write(client, R8, 0x000); /* 256fps, fs=48k */ break; case 32000: - /* 256fps, fs=32k */ - wm8739_write(client, R8, 0x018); + wm8739_write(client, R8, 0x018); /* 256fps, fs=32k */ break; default: break; } - /* activate */ - wm8739_write(client, R9, 0x001); + wm8739_write(client, R9, 0x001); /* activate */ break; } @@ -239,8 +238,7 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) } case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, - arg, V4L2_IDENT_WM8739, 0); + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); @@ -261,16 +259,27 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int wm8739_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct wm8739_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "wm8739"); - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); if (state == NULL) { @@ -286,37 +295,67 @@ static int wm8739_probe(struct i2c_client *client) state->clock_freq = 48000; i2c_set_clientdata(client, state); - /* Initialize wm8739 */ - - /* reset */ - wm8739_write(client, R15, 0x00); - /* filter setting, high path, offet clear */ - wm8739_write(client, R5, 0x000); - /* ADC, OSC, Power Off mode Disable */ - wm8739_write(client, R6, 0x000); - /* Digital Audio interface format: - Enable Master mode, 24 bit, MSB first/left justified */ - wm8739_write(client, R7, 0x049); - /* sampling control: normal, 256fs, 48KHz sampling rate */ - wm8739_write(client, R8, 0x000); - /* activate */ - wm8739_write(client, R9, 0x001); - /* set volume/mute */ - wm8739_set_audio(client); + /* initialize wm8739 */ + wm8739_write(client, R15, 0x00); /* reset */ + wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */ + wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */ + wm8739_write(client, R7, 0x049); /* Digital Audio interface format */ + /* Enable Master mode */ + /* 24 bit, MSB first/left justified */ + wm8739_write(client, R8, 0x000); /* sampling control */ + /* normal, 256fs, 48KHz sampling rate */ + wm8739_write(client, R9, 0x001); /* activate */ + wm8739_set_audio(client); /* set volume/mute */ + + i2c_attach_client(client); + + return 0; +} + +static int wm8739_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, wm8739_attach); return 0; } -static int wm8739_remove(struct i2c_client *client) +static int wm8739_detach(struct i2c_client *client) { - kfree(i2c_get_clientdata(client)); + struct wm8739_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) + return err; + + kfree(state); + kfree(client); return 0; } -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "wm8739", - .driverid = I2C_DRIVERID_WM8739, +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "wm8739", + }, + .id = I2C_DRIVERID_WM8739, + .attach_adapter = wm8739_probe, + .detach_client = wm8739_detach, .command = wm8739_command, - .probe = wm8739_probe, - .remove = wm8739_remove, }; + +static int __init wm8739_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit wm8739_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(wm8739_init_module); +module_exit(wm8739_cleanup_module); diff --git a/trunk/drivers/media/video/wm8775.c b/trunk/drivers/media/video/wm8775.c index 869f9e7946b6..9f7e894ef962 100644 --- a/trunk/drivers/media/video/wm8775.c +++ b/trunk/drivers/media/video/wm8775.c @@ -34,7 +34,6 @@ #include #include #include -#include MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); @@ -45,7 +44,6 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; - /* ----------------------------------------------------------------------- */ enum { @@ -68,15 +66,18 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val) return -1; } - for (i = 0; i < 3; i++) - if (i2c_smbus_write_byte_data(client, - (reg << 1) | (val >> 8), val & 0xff) == 0) + for (i = 0; i < 3; i++) { + if (i2c_smbus_write_byte_data(client, (reg << 1) | + (val >> 8), val & 0xff) == 0) { return 0; + } + } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } -static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) +static int wm8775_command(struct i2c_client *client, unsigned int cmd, + void *arg) { struct wm8775_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -125,8 +126,7 @@ static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, - arg, V4L2_IDENT_WM8775, 0); + return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Input: %d%s\n", state->input, @@ -159,67 +159,105 @@ static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int wm8775_probe(struct i2c_client *client) +static struct i2c_driver i2c_driver; + +static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *client; struct wm8775_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "wm8775"); - v4l_info(client, "chip found @ 0x%x (%s)\n", - client->addr << 1, client->adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); - if (state == NULL) + if (state == NULL) { + kfree(client); return -ENOMEM; + } state->input = 2; state->muted = 0; i2c_set_clientdata(client, state); - /* Initialize wm8775 */ - - /* RESET */ - wm8775_write(client, R23, 0x000); - /* Disable zero cross detect timeout */ - wm8775_write(client, R7, 0x000); - /* Left justified, 24-bit mode */ - wm8775_write(client, R11, 0x021); - /* Master mode, clock ratio 256fs */ - wm8775_write(client, R12, 0x102); - /* Powered up */ - wm8775_write(client, R13, 0x000); - /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(client, R14, 0x1d4); - /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(client, R15, 0x1d4); - /* ALC Stereo, ALC target level -1dB FS max gain +8dB */ - wm8775_write(client, R16, 0x1bf); - /* Enable gain control, use zero cross detection, - ALC hold time 42.6 ms */ - wm8775_write(client, R17, 0x185); - /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ - wm8775_write(client, R18, 0x0a2); - /* Enable noise gate, threshold -72dBfs */ - wm8775_write(client, R19, 0x005); - /* Transient window 4ms, lower PGA gain limit -1dB */ - wm8775_write(client, R20, 0x07a); - /* LRBOTH = 1, use input 2. */ - wm8775_write(client, R21, 0x102); + /* initialize wm8775 */ + wm8775_write(client, R23, 0x000); /* RESET */ + wm8775_write(client, R7, 0x000); /* Disable zero cross detect timeout */ + wm8775_write(client, R11, 0x021); /* Left justified, 24-bit mode */ + wm8775_write(client, R12, 0x102); /* Master mode, clock ratio 256fs */ + wm8775_write(client, R13, 0x000); /* Powered up */ + wm8775_write(client, R14, 0x1d4); /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(client, R15, 0x1d4); /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(client, R16, 0x1bf); /* ALC Stereo, ALC target level -1dB FS */ + /* max gain +8dB */ + wm8775_write(client, R17, 0x185); /* Enable gain control, use zero cross */ + /* detection, ALC hold time 42.6 ms */ + wm8775_write(client, R18, 0x0a2); /* ALC gain ramp up delay 34 s, */ + /* ALC gain ramp down delay 33 ms */ + wm8775_write(client, R19, 0x005); /* Enable noise gate, threshold -72dBfs */ + wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */ + /* limit -1dB */ + wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */ + i2c_attach_client(client); + return 0; } -static int wm8775_remove(struct i2c_client *client) +static int wm8775_probe(struct i2c_adapter *adapter) { - kfree(i2c_get_clientdata(client)); + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, wm8775_attach); return 0; } -static struct v4l2_i2c_driver_data v4l2_i2c_data = { - .name = "wm8775", - .driverid = I2C_DRIVERID_WM8775, - .command = wm8775_command, - .probe = wm8775_probe, - .remove = wm8775_remove, +static int wm8775_detach(struct i2c_client *client) +{ + struct wm8775_state *state = i2c_get_clientdata(client); + int err; + + err = i2c_detach_client(client); + if (err) { + return err; + } + kfree(state); + kfree(client); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "wm8775", + }, + .id = I2C_DRIVERID_WM8775, + .attach_adapter = wm8775_probe, + .detach_client = wm8775_detach, + .command = wm8775_command, }; + +static int __init wm8775_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit wm8775_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(wm8775_init_module); +module_exit(wm8775_cleanup_module); diff --git a/trunk/drivers/media/video/zr364xx.c b/trunk/drivers/media/video/zr364xx.c index 1fdbb46de7f3..6f1892585cbb 100644 --- a/trunk/drivers/media/video/zr364xx.c +++ b/trunk/drivers/media/video/zr364xx.c @@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) } -static const struct file_operations zr364xx_fops = { +static struct file_operations zr364xx_fops = { .owner = THIS_MODULE, .open = zr364xx_open, .release = zr364xx_release, diff --git a/trunk/drivers/net/mlx4/fw.c b/trunk/drivers/net/mlx4/fw.c index 535a4461d88c..50648738d679 100644 --- a/trunk/drivers/net/mlx4/fw.c +++ b/trunk/drivers/net/mlx4/fw.c @@ -202,7 +202,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET); dev_cap->reserved_eqs = 1 << (field & 0xf); MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET); - dev_cap->max_eqs = 1 << (field & 0xf); + dev_cap->max_eqs = 1 << (field & 0x7); MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET); dev_cap->reserved_mtts = 1 << (field >> 4); MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET); diff --git a/trunk/drivers/s390/char/sclp_config.c b/trunk/drivers/s390/char/sclp_config.c index 9dc77f14fa52..5322e5e54a98 100644 --- a/trunk/drivers/s390/char/sclp_config.c +++ b/trunk/drivers/s390/char/sclp_config.c @@ -29,12 +29,12 @@ static void sclp_cpu_capability_notify(struct work_struct *work) struct sys_device *sysdev; printk(KERN_WARNING TAG "cpu capability changed.\n"); - get_online_cpus(); + lock_cpu_hotplug(); for_each_online_cpu(cpu) { sysdev = get_cpu_sysdev(cpu); kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); } - put_online_cpus(); + unlock_cpu_hotplug(); } static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) diff --git a/trunk/drivers/scsi/ide-scsi.c b/trunk/drivers/scsi/ide-scsi.c index 02e91893064d..9706de9d98d5 100644 --- a/trunk/drivers/scsi/ide-scsi.c +++ b/trunk/drivers/scsi/ide-scsi.c @@ -395,12 +395,14 @@ static int idescsi_expiry(ide_drive_t *drive) static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); - ide_hwif_t *hwif = drive->hwif; - idescsi_pc_t *pc = scsi->pc; + idescsi_pc_t *pc=scsi->pc; struct request *rq = pc->rq; + atapi_bcount_t bcount; + atapi_status_t status; + atapi_ireason_t ireason; + atapi_feature_t feature; + unsigned int temp; - u16 bcount; - u8 stat, ireason; #if IDESCSI_DEBUG_LOG printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n"); @@ -423,29 +425,30 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) (void) HWIF(drive)->ide_dma_end(drive); } + feature.all = 0; /* Clear the interrupt */ - stat = drive->hwif->INB(IDE_STATUS_REG); + status.all = HWIF(drive)->INB(IDE_STATUS_REG); - if ((stat & DRQ_STAT) == 0) { + if (!status.b.drq) { /* No more interrupts */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); local_irq_enable_in_hardirq(); - if (stat & ERR_STAT) + if (status.b.check) rq->errors++; idescsi_end_request (drive, 1, 0); return ide_stopped; } - bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | - hwif->INB(IDE_BCOUNTL_REG); - ireason = hwif->INB(IDE_IREASON_REG); + bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); + bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); + ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); - if (ireason & CD) { + if (ireason.b.cod) { printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n"); return ide_do_reset (drive); } - if (ireason & IO) { - temp = pc->actually_transferred + bcount; + if (ireason.b.io) { + temp = pc->actually_transferred + bcount.all; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-scsi: The scsi wants to " @@ -458,13 +461,11 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) idescsi_input_buffers(drive, pc, temp); else drive->hwif->atapi_input_bytes(drive, pc->current_position, temp); - printk(KERN_ERR "ide-scsi: transferred" - " %d of %d bytes\n", - temp, bcount); + printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all); } pc->actually_transferred += temp; pc->current_position += temp; - idescsi_discard_data(drive, bcount - temp); + idescsi_discard_data(drive, bcount.all - temp); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; } @@ -473,24 +474,22 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) #endif /* IDESCSI_DEBUG_LOG */ } } - if (ireason & IO) { + if (ireason.b.io) { clear_bit(PC_WRITING, &pc->flags); if (pc->sg) - idescsi_input_buffers(drive, pc, bcount); + idescsi_input_buffers(drive, pc, bcount.all); else - hwif->atapi_input_bytes(drive, pc->current_position, - bcount); + HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all); } else { set_bit(PC_WRITING, &pc->flags); if (pc->sg) - idescsi_output_buffers(drive, pc, bcount); + idescsi_output_buffers (drive, pc, bcount.all); else - hwif->atapi_output_bytes(drive, pc->current_position, - bcount); + HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all); } /* Update the current position */ - pc->actually_transferred += bcount; - pc->current_position += bcount; + pc->actually_transferred += bcount.all; + pc->current_position += bcount.all; /* And set the interrupt handler again */ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); @@ -502,16 +501,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; idescsi_scsi_t *scsi = drive_to_idescsi(drive); idescsi_pc_t *pc = scsi->pc; + atapi_ireason_t ireason; ide_startstop_t startstop; - u8 ireason; if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk(KERN_ERR "ide-scsi: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason = hwif->INB(IDE_IREASON_REG); - if ((ireason & CD) == 0 || (ireason & IO)) { + ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); + if (!ireason.b.cod || ireason.b.io) { printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while " "issuing a packet command\n"); return ide_do_reset (drive); @@ -574,26 +573,30 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); ide_hwif_t *hwif = drive->hwif; - u16 bcount; - u8 dma = 0; + atapi_feature_t feature; + atapi_bcount_t bcount; scsi->pc=pc; /* Set the current packet command */ pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; - /* Request to transfer the entire buffer at once */ - bcount = min(pc->request_transfer, 63 * 1024); + bcount.all = min(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ + feature.all = 0; if (drive->using_dma && !idescsi_map_sg(drive, pc)) { hwif->sg_mapped = 1; - dma = !hwif->dma_setup(drive); + feature.b.dma = !hwif->dma_setup(drive); hwif->sg_mapped = 0; } SELECT_DRIVE(drive); + if (IDE_CONTROL_REG) + HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); - ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma); + HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG); + HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG); + HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG); - if (dma) + if (feature.b.dma) set_bit(PC_DMA_OK, &pc->flags); if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { diff --git a/trunk/drivers/scsi/ipr.c b/trunk/drivers/scsi/ipr.c index aa0df0a4b22a..0841df01bc19 100644 --- a/trunk/drivers/scsi/ipr.c +++ b/trunk/drivers/scsi/ipr.c @@ -5142,7 +5142,6 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, struct ipr_ioadl_desc *last_ioadl = NULL; int len = qc->nbytes + qc->pad_len; struct scatterlist *sg; - unsigned int si; if (len == 0) return; @@ -5160,7 +5159,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); } - for_each_sg(qc->sg, sg, qc->n_elem, si) { + ata_for_each_sg(sg, qc) { ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg)); ioadl->address = cpu_to_be32(sg_dma_address(sg)); @@ -5223,12 +5222,12 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; break; - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: + case ATA_PROT_ATAPI: + case ATA_PROT_ATAPI_NODATA: regs->flags |= IPR_ATA_FLAG_PACKET_CMD; break; - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: regs->flags |= IPR_ATA_FLAG_PACKET_CMD; regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; break; diff --git a/trunk/drivers/scsi/libsas/sas_ata.c b/trunk/drivers/scsi/libsas/sas_ata.c index 827cfb132f21..0829b55c64d2 100644 --- a/trunk/drivers/scsi/libsas/sas_ata.c +++ b/trunk/drivers/scsi/libsas/sas_ata.c @@ -158,8 +158,8 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) struct Scsi_Host *host = sas_ha->core.shost; struct sas_internal *i = to_sas_internal(host->transportt); struct scatterlist *sg; + unsigned int num = 0; unsigned int xfer = 0; - unsigned int si; task = sas_alloc_task(GFP_ATOMIC); if (!task) @@ -176,20 +176,22 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis); task->uldd_task = qc; - if (ata_is_atapi(qc->tf.protocol)) { + if (is_atapi_taskfile(&qc->tf)) { memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); task->total_xfer_len = qc->nbytes + qc->pad_len; task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem; } else { - for_each_sg(qc->sg, sg, qc->n_elem, si) + ata_for_each_sg(sg, qc) { + num++; xfer += sg->length; + } task->total_xfer_len = xfer; - task->num_scatter = si; + task->num_scatter = num; } task->data_dir = qc->dma_dir; - task->scatter = qc->sg; + task->scatter = qc->__sg; task->ata_task.retry_count = 1; task->task_state_flags = SAS_TASK_STATE_PENDING; qc->lldd_task = task; @@ -198,7 +200,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) case ATA_PROT_NCQ: task->ata_task.use_ncq = 1; /* fall through */ - case ATAPI_PROT_DMA: + case ATA_PROT_ATAPI_DMA: case ATA_PROT_DMA: task->ata_task.dma_xfer = 1; break; diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index b6df18f1f677..781b47d2f9f2 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -440,8 +440,14 @@ config OCFS2_FS Tools web page: http://oss.oracle.com/projects/ocfs2-tools OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/ - For more information on OCFS2, see the file - . + Note: Features which OCFS2 does not support yet: + - extended attributes + - quotas + - cluster aware flock + - Directory change notification (F_NOTIFY) + - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease) + - POSIX ACLs + - readpages / writepages (not user visible) config OCFS2_DEBUG_MASKLOG bool "OCFS2 logging support" @@ -1022,8 +1028,8 @@ config HUGETLB_PAGE def_bool HUGETLBFS config CONFIGFS_FS - tristate "Userspace-driven configuration filesystem" - depends on SYSFS + tristate "Userspace-driven configuration filesystem (EXPERIMENTAL)" + depends on SYSFS && EXPERIMENTAL help configfs is a ram-based filesystem that provides the converse of sysfs's functionality. Where sysfs is a filesystem-based @@ -2124,3 +2130,4 @@ source "fs/nls/Kconfig" source "fs/dlm/Kconfig" endmenu + diff --git a/trunk/fs/configfs/dir.c b/trunk/fs/configfs/dir.c index a48dc7dd8765..50ed691098bc 100644 --- a/trunk/fs/configfs/dir.c +++ b/trunk/fs/configfs/dir.c @@ -546,7 +546,7 @@ static int populate_groups(struct config_group *group) * That said, taking our i_mutex is closer to mkdir * emulation, and shouldn't hurt. */ - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); + mutex_lock(&dentry->d_inode->i_mutex); for (i = 0; group->default_groups[i]; i++) { new_group = group->default_groups[i]; @@ -1405,8 +1405,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) sd = configfs_sb->s_root->d_fsdata; link_group(to_config_group(sd->s_element), group); - mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, - I_MUTEX_PARENT); + mutex_lock(&configfs_sb->s_root->d_inode->i_mutex); name.name = group->cg_item.ci_name; name.len = strlen(name.name); diff --git a/trunk/fs/configfs/file.c b/trunk/fs/configfs/file.c index 397cb503a180..a3658f9a082c 100644 --- a/trunk/fs/configfs/file.c +++ b/trunk/fs/configfs/file.c @@ -320,7 +320,7 @@ int configfs_add_file(struct dentry * dir, const struct configfs_attribute * att umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG; int error = 0; - mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_NORMAL); + mutex_lock(&dir->d_inode->i_mutex); error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type); mutex_unlock(&dir->d_inode->i_mutex); diff --git a/trunk/fs/ocfs2/Makefile b/trunk/fs/ocfs2/Makefile index 4d4ce48bb42c..9fb8132f19b0 100644 --- a/trunk/fs/ocfs2/Makefile +++ b/trunk/fs/ocfs2/Makefile @@ -19,17 +19,16 @@ ocfs2-objs := \ ioctl.o \ journal.o \ localalloc.o \ - locks.o \ mmap.o \ namei.o \ - resize.o \ slot_map.o \ suballoc.o \ super.o \ symlink.o \ sysfile.o \ uptodate.o \ - ver.o + ver.o \ + vote.o obj-$(CONFIG_OCFS2_FS) += cluster/ obj-$(CONFIG_OCFS2_FS) += dlm/ diff --git a/trunk/fs/ocfs2/alloc.c b/trunk/fs/ocfs2/alloc.c index e6df06ac6405..23c8cda43f19 100644 --- a/trunk/fs/ocfs2/alloc.c +++ b/trunk/fs/ocfs2/alloc.c @@ -4731,7 +4731,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb) mutex_lock(&data_alloc_inode->i_mutex); - status = ocfs2_inode_lock(data_alloc_inode, &data_alloc_bh, 1); + status = ocfs2_meta_lock(data_alloc_inode, &data_alloc_bh, 1); if (status < 0) { mlog_errno(status); goto out_mutex; @@ -4753,7 +4753,7 @@ int __ocfs2_flush_truncate_log(struct ocfs2_super *osb) out_unlock: brelse(data_alloc_bh); - ocfs2_inode_unlock(data_alloc_inode, 1); + ocfs2_meta_unlock(data_alloc_inode, 1); out_mutex: mutex_unlock(&data_alloc_inode->i_mutex); @@ -5077,7 +5077,7 @@ static int ocfs2_free_cached_items(struct ocfs2_super *osb, mutex_lock(&inode->i_mutex); - ret = ocfs2_inode_lock(inode, &di_bh, 1); + ret = ocfs2_meta_lock(inode, &di_bh, 1); if (ret) { mlog_errno(ret); goto out_mutex; @@ -5118,7 +5118,7 @@ static int ocfs2_free_cached_items(struct ocfs2_super *osb, ocfs2_commit_trans(osb, handle); out_unlock: - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); brelse(di_bh); out_mutex: mutex_unlock(&inode->i_mutex); diff --git a/trunk/fs/ocfs2/aops.c b/trunk/fs/ocfs2/aops.c index bc7b4cbbe8ec..56f7790cad46 100644 --- a/trunk/fs/ocfs2/aops.c +++ b/trunk/fs/ocfs2/aops.c @@ -26,7 +26,6 @@ #include #include #include -#include #define MLOG_MASK_PREFIX ML_FILE_IO #include @@ -140,8 +139,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, { int err = 0; unsigned int ext_flags; - u64 max_blocks = bh_result->b_size >> inode->i_blkbits; - u64 p_blkno, count, past_eof; + u64 p_blkno, past_eof; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); mlog_entry("(0x%p, %llu, 0x%p, %d)\n", inode, @@ -157,7 +155,7 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, goto bail; } - err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &count, + err = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, NULL, &ext_flags); if (err) { mlog(ML_ERROR, "Error %d from get_blocks(0x%p, %llu, 1, " @@ -166,9 +164,6 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, goto bail; } - if (max_blocks < count) - count = max_blocks; - /* * ocfs2 never allocates in this function - the only time we * need to use BH_New is when we're extending i_size on a file @@ -183,8 +178,6 @@ static int ocfs2_get_block(struct inode *inode, sector_t iblock, if (p_blkno && !(ext_flags & OCFS2_EXT_UNWRITTEN)) map_bh(bh_result, inode->i_sb, p_blkno); - bh_result->b_size = count << inode->i_blkbits; - if (!ocfs2_sparse_alloc(osb)) { if (p_blkno == 0) { err = -EIO; @@ -217,7 +210,7 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page, struct buffer_head *di_bh) { void *kaddr; - loff_t size; + unsigned int size; struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) { @@ -231,9 +224,8 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page, if (size > PAGE_CACHE_SIZE || size > ocfs2_max_inline_data(inode->i_sb)) { ocfs2_error(inode->i_sb, - "Inode %llu has with inline data has bad size: %Lu", - (unsigned long long)OCFS2_I(inode)->ip_blkno, - (unsigned long long)size); + "Inode %llu has with inline data has bad size: %u", + (unsigned long long)OCFS2_I(inode)->ip_blkno, size); return -EROFS; } @@ -283,7 +275,7 @@ static int ocfs2_readpage(struct file *file, struct page *page) mlog_entry("(0x%p, %lu)\n", file, (page ? page->index : 0)); - ret = ocfs2_inode_lock_with_page(inode, NULL, 0, page); + ret = ocfs2_meta_lock_with_page(inode, NULL, 0, page); if (ret != 0) { if (ret == AOP_TRUNCATED_PAGE) unlock = 0; @@ -293,7 +285,7 @@ static int ocfs2_readpage(struct file *file, struct page *page) if (down_read_trylock(&oi->ip_alloc_sem) == 0) { ret = AOP_TRUNCATED_PAGE; - goto out_inode_unlock; + goto out_meta_unlock; } /* @@ -313,16 +305,25 @@ static int ocfs2_readpage(struct file *file, struct page *page) goto out_alloc; } + ret = ocfs2_data_lock_with_page(inode, 0, page); + if (ret != 0) { + if (ret == AOP_TRUNCATED_PAGE) + unlock = 0; + mlog_errno(ret); + goto out_alloc; + } + if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) ret = ocfs2_readpage_inline(inode, page); else ret = block_read_full_page(page, ocfs2_get_block); unlock = 0; + ocfs2_data_unlock(inode, 0); out_alloc: up_read(&OCFS2_I(inode)->ip_alloc_sem); -out_inode_unlock: - ocfs2_inode_unlock(inode, 0); +out_meta_unlock: + ocfs2_meta_unlock(inode, 0); out: if (unlock) unlock_page(page); @@ -330,62 +331,6 @@ static int ocfs2_readpage(struct file *file, struct page *page) return ret; } -/* - * This is used only for read-ahead. Failures or difficult to handle - * situations are safe to ignore. - * - * Right now, we don't bother with BH_Boundary - in-inode extent lists - * are quite large (243 extents on 4k blocks), so most inodes don't - * grow out to a tree. If need be, detecting boundary extents could - * trivially be added in a future version of ocfs2_get_block(). - */ -static int ocfs2_readpages(struct file *filp, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - int ret, err = -EIO; - struct inode *inode = mapping->host; - struct ocfs2_inode_info *oi = OCFS2_I(inode); - loff_t start; - struct page *last; - - /* - * Use the nonblocking flag for the dlm code to avoid page - * lock inversion, but don't bother with retrying. - */ - ret = ocfs2_inode_lock_full(inode, NULL, 0, OCFS2_LOCK_NONBLOCK); - if (ret) - return err; - - if (down_read_trylock(&oi->ip_alloc_sem) == 0) { - ocfs2_inode_unlock(inode, 0); - return err; - } - - /* - * Don't bother with inline-data. There isn't anything - * to read-ahead in that case anyway... - */ - if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) - goto out_unlock; - - /* - * Check whether a remote node truncated this file - we just - * drop out in that case as it's not worth handling here. - */ - last = list_entry(pages->prev, struct page, lru); - start = (loff_t)last->index << PAGE_CACHE_SHIFT; - if (start >= i_size_read(inode)) - goto out_unlock; - - err = mpage_readpages(mapping, pages, nr_pages, ocfs2_get_block); - -out_unlock: - up_read(&oi->ip_alloc_sem); - ocfs2_inode_unlock(inode, 0); - - return err; -} - /* Note: Because we don't support holes, our allocation has * already happened (allocation writes zeros to the file data) * so we don't have to worry about ordered writes in @@ -507,7 +452,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) * accessed concurrently from multiple nodes. */ if (!INODE_JOURNAL(inode)) { - err = ocfs2_inode_lock(inode, NULL, 0); + err = ocfs2_meta_lock(inode, NULL, 0); if (err) { if (err != -ENOENT) mlog_errno(err); @@ -522,7 +467,7 @@ static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block) if (!INODE_JOURNAL(inode)) { up_read(&OCFS2_I(inode)->ip_alloc_sem); - ocfs2_inode_unlock(inode, 0); + ocfs2_meta_unlock(inode, 0); } if (err) { @@ -693,12 +638,34 @@ static ssize_t ocfs2_direct_IO(int rw, if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) return 0; + if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { + /* + * We get PR data locks even for O_DIRECT. This + * allows concurrent O_DIRECT I/O but doesn't let + * O_DIRECT with extending and buffered zeroing writes + * race. If they did race then the buffered zeroing + * could be written back after the O_DIRECT I/O. It's + * one thing to tell people not to mix buffered and + * O_DIRECT writes, but expecting them to understand + * that file extension is also an implicit buffered + * write is too much. By getting the PR we force + * writeback of the buffered zeroing before + * proceeding. + */ + ret = ocfs2_data_lock(inode, 0); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + ocfs2_data_unlock(inode, 0); + } + ret = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev, iov, offset, nr_segs, ocfs2_direct_IO_get_blocks, ocfs2_dio_end_io); - +out: mlog_exit(ret); return ret; } @@ -1787,7 +1754,7 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping, struct buffer_head *di_bh = NULL; struct inode *inode = mapping->host; - ret = ocfs2_inode_lock(inode, &di_bh, 1); + ret = ocfs2_meta_lock(inode, &di_bh, 1); if (ret) { mlog_errno(ret); return ret; @@ -1802,22 +1769,30 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping, */ down_write(&OCFS2_I(inode)->ip_alloc_sem); + ret = ocfs2_data_lock(inode, 1); + if (ret) { + mlog_errno(ret); + goto out_fail; + } + ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep, fsdata, di_bh, NULL); if (ret) { mlog_errno(ret); - goto out_fail; + goto out_fail_data; } brelse(di_bh); return 0; +out_fail_data: + ocfs2_data_unlock(inode, 1); out_fail: up_write(&OCFS2_I(inode)->ip_alloc_sem); brelse(di_bh); - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); return ret; } @@ -1933,15 +1908,15 @@ static int ocfs2_write_end(struct file *file, struct address_space *mapping, ret = ocfs2_write_end_nolock(mapping, pos, len, copied, page, fsdata); + ocfs2_data_unlock(inode, 1); up_write(&OCFS2_I(inode)->ip_alloc_sem); - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); return ret; } const struct address_space_operations ocfs2_aops = { .readpage = ocfs2_readpage, - .readpages = ocfs2_readpages, .writepage = ocfs2_writepage, .write_begin = ocfs2_write_begin, .write_end = ocfs2_write_end, diff --git a/trunk/fs/ocfs2/buffer_head_io.c b/trunk/fs/ocfs2/buffer_head_io.c index f136639f5b41..c9037414f4f6 100644 --- a/trunk/fs/ocfs2/buffer_head_io.c +++ b/trunk/fs/ocfs2/buffer_head_io.c @@ -79,7 +79,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh, * information for this bh as it's not marked locally * uptodate. */ ret = -EIO; - put_bh(bh); + brelse(bh); } mutex_unlock(&OCFS2_I(inode)->ip_io_mutex); @@ -256,7 +256,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr, * for this bh as it's not marked locally * uptodate. */ status = -EIO; - put_bh(bh); + brelse(bh); bhs[i] = NULL; continue; } @@ -280,64 +280,3 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr, mlog_exit(status); return status; } - -/* Check whether the blkno is the super block or one of the backups. */ -static void ocfs2_check_super_or_backup(struct super_block *sb, - sector_t blkno) -{ - int i; - u64 backup_blkno; - - if (blkno == OCFS2_SUPER_BLOCK_BLKNO) - return; - - for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) { - backup_blkno = ocfs2_backup_super_blkno(sb, i); - if (backup_blkno == blkno) - return; - } - - BUG(); -} - -/* - * Write super block and backups doesn't need to collaborate with journal, - * so we don't need to lock ip_io_mutex and inode doesn't need to bea passed - * into this function. - */ -int ocfs2_write_super_or_backup(struct ocfs2_super *osb, - struct buffer_head *bh) -{ - int ret = 0; - - mlog_entry_void(); - - BUG_ON(buffer_jbd(bh)); - ocfs2_check_super_or_backup(osb->sb, bh->b_blocknr); - - if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) { - ret = -EROFS; - goto out; - } - - lock_buffer(bh); - set_buffer_uptodate(bh); - - /* remove from dirty list before I/O. */ - clear_buffer_dirty(bh); - - get_bh(bh); /* for end_buffer_write_sync() */ - bh->b_end_io = end_buffer_write_sync; - submit_bh(WRITE, bh); - - wait_on_buffer(bh); - - if (!buffer_uptodate(bh)) { - ret = -EIO; - put_bh(bh); - } - -out: - mlog_exit(ret); - return ret; -} diff --git a/trunk/fs/ocfs2/buffer_head_io.h b/trunk/fs/ocfs2/buffer_head_io.h index c2e78614c3e5..6cc20930fac3 100644 --- a/trunk/fs/ocfs2/buffer_head_io.h +++ b/trunk/fs/ocfs2/buffer_head_io.h @@ -47,8 +47,6 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, int flags, struct inode *inode); -int ocfs2_write_super_or_backup(struct ocfs2_super *osb, - struct buffer_head *bh); #define OCFS2_BH_CACHED 1 #define OCFS2_BH_READAHEAD 8 diff --git a/trunk/fs/ocfs2/cluster/heartbeat.h b/trunk/fs/ocfs2/cluster/heartbeat.h index e511339886b3..35397dd5ecdb 100644 --- a/trunk/fs/ocfs2/cluster/heartbeat.h +++ b/trunk/fs/ocfs2/cluster/heartbeat.h @@ -35,7 +35,7 @@ #define O2HB_LIVE_THRESHOLD 2 /* number of equal samples to be seen as dead */ extern unsigned int o2hb_dead_threshold; -#define O2HB_DEFAULT_DEAD_THRESHOLD 31 +#define O2HB_DEFAULT_DEAD_THRESHOLD 7 /* Otherwise MAX_WRITE_TIMEOUT will be zero... */ #define O2HB_MIN_DEAD_THRESHOLD 2 #define O2HB_MAX_WRITE_TIMEOUT_MS (O2HB_REGION_TIMEOUT_MS * (o2hb_dead_threshold - 1)) diff --git a/trunk/fs/ocfs2/cluster/tcp.h b/trunk/fs/ocfs2/cluster/tcp.h index f36f66aab3dd..da880fc215f0 100644 --- a/trunk/fs/ocfs2/cluster/tcp.h +++ b/trunk/fs/ocfs2/cluster/tcp.h @@ -60,8 +60,8 @@ typedef void (o2net_post_msg_handler_func)(int status, void *data, /* same as hb delay, we're waiting for another node to recognize our hb */ #define O2NET_RECONNECT_DELAY_MS_DEFAULT 2000 -#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT 2000 -#define O2NET_IDLE_TIMEOUT_MS_DEFAULT 30000 +#define O2NET_KEEPALIVE_DELAY_MS_DEFAULT 5000 +#define O2NET_IDLE_TIMEOUT_MS_DEFAULT 10000 /* TODO: figure this out.... */ diff --git a/trunk/fs/ocfs2/cluster/tcp_internal.h b/trunk/fs/ocfs2/cluster/tcp_internal.h index b2e832aca567..9606111fe89d 100644 --- a/trunk/fs/ocfs2/cluster/tcp_internal.h +++ b/trunk/fs/ocfs2/cluster/tcp_internal.h @@ -38,12 +38,6 @@ * locking semantics of the file system using the protocol. It should * be somewhere else, I'm sure, but right now it isn't. * - * New in version 10: - * - Meta/data locks combined - * - * New in version 9: - * - All votes removed - * * New in version 8: * - Replace delete inode votes with a cluster lock * @@ -66,7 +60,7 @@ * - full 64 bit i_size in the metadata lock lvbs * - introduction of "rw" lock and pushing meta/data locking down */ -#define O2NET_PROTOCOL_VERSION 10ULL +#define O2NET_PROTOCOL_VERSION 8ULL struct o2net_handshake { __be64 protocol_version; __be64 connector_id; diff --git a/trunk/fs/ocfs2/cluster/ver.c b/trunk/fs/ocfs2/cluster/ver.c index a56eee6abad3..7286c48bb30d 100644 --- a/trunk/fs/ocfs2/cluster/ver.c +++ b/trunk/fs/ocfs2/cluster/ver.c @@ -28,7 +28,7 @@ #include "ver.h" -#define CLUSTER_BUILD_VERSION "1.5.0" +#define CLUSTER_BUILD_VERSION "1.3.3" #define VERSION_STR "OCFS2 Node Manager " CLUSTER_BUILD_VERSION diff --git a/trunk/fs/ocfs2/dcache.c b/trunk/fs/ocfs2/dcache.c index b1cc7c381e88..9923278ea6d4 100644 --- a/trunk/fs/ocfs2/dcache.c +++ b/trunk/fs/ocfs2/dcache.c @@ -128,9 +128,9 @@ static int ocfs2_match_dentry(struct dentry *dentry, /* * Walk the inode alias list, and find a dentry which has a given * parent. ocfs2_dentry_attach_lock() wants to find _any_ alias as it - * is looking for a dentry_lock reference. The downconvert thread is - * looking to unhash aliases, so we allow it to skip any that already - * have that property. + * is looking for a dentry_lock reference. The vote thread is looking + * to unhash aliases, so we allow it to skip any that already have + * that property. */ struct dentry *ocfs2_find_local_alias(struct inode *inode, u64 parent_blkno, @@ -266,7 +266,7 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry, dl->dl_count = 0; /* * Does this have to happen below, for all attaches, in case - * the struct inode gets blown away by the downconvert thread? + * the struct inode gets blown away by votes? */ dl->dl_inode = igrab(inode); dl->dl_parent_blkno = parent_blkno; diff --git a/trunk/fs/ocfs2/dir.c b/trunk/fs/ocfs2/dir.c index 6b0107f21344..63b28fdceb4a 100644 --- a/trunk/fs/ocfs2/dir.c +++ b/trunk/fs/ocfs2/dir.c @@ -846,14 +846,14 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) mlog_entry("dirino=%llu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); - error = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level); + error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); if (lock_level && error >= 0) { /* We release EX lock which used to update atime * and get PR lock again to reduce contention * on commonly accessed directories. */ - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); lock_level = 0; - error = ocfs2_inode_lock(inode, NULL, 0); + error = ocfs2_meta_lock(inode, NULL, 0); } if (error < 0) { if (error != -ENOENT) @@ -865,7 +865,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos, dirent, filldir, NULL); - ocfs2_inode_unlock(inode, lock_level); + ocfs2_meta_unlock(inode, lock_level); bail_nolock: mlog_exit(error); diff --git a/trunk/fs/ocfs2/dlm/dlmfsver.c b/trunk/fs/ocfs2/dlm/dlmfsver.c index a733b3321f83..d2be3ad841f9 100644 --- a/trunk/fs/ocfs2/dlm/dlmfsver.c +++ b/trunk/fs/ocfs2/dlm/dlmfsver.c @@ -28,7 +28,7 @@ #include "dlmfsver.h" -#define DLM_BUILD_VERSION "1.5.0" +#define DLM_BUILD_VERSION "1.3.3" #define VERSION_STR "OCFS2 DLMFS " DLM_BUILD_VERSION diff --git a/trunk/fs/ocfs2/dlm/dlmrecovery.c b/trunk/fs/ocfs2/dlm/dlmrecovery.c index 91f747b8a538..2fde7bf91434 100644 --- a/trunk/fs/ocfs2/dlm/dlmrecovery.c +++ b/trunk/fs/ocfs2/dlm/dlmrecovery.c @@ -2270,12 +2270,6 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx) } } - /* Clean up join state on node death. */ - if (dlm->joining_node == idx) { - mlog(0, "Clearing join state for node %u\n", idx); - __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); - } - /* check to see if the node is already considered dead */ if (!test_bit(idx, dlm->live_nodes_map)) { mlog(0, "for domain %s, node %d is already dead. " @@ -2294,6 +2288,12 @@ static void __dlm_hb_node_down(struct dlm_ctxt *dlm, int idx) clear_bit(idx, dlm->live_nodes_map); + /* Clean up join state on node death. */ + if (dlm->joining_node == idx) { + mlog(0, "Clearing join state for node %u\n", idx); + __dlm_set_joining_node(dlm, DLM_LOCK_RES_OWNER_UNKNOWN); + } + /* make sure local cleanup occurs before the heartbeat events */ if (!test_bit(idx, dlm->recovery_map)) dlm_do_local_recovery_cleanup(dlm, idx); @@ -2321,13 +2321,6 @@ void dlm_hb_node_down_cb(struct o2nm_node *node, int idx, void *data) if (!dlm_grab(dlm)) return; - /* - * This will notify any dlm users that a node in our domain - * went away without notifying us first. - */ - if (test_bit(idx, dlm->domain_map)) - dlm_fire_domain_eviction_callbacks(dlm, idx); - spin_lock(&dlm->spinlock); __dlm_hb_node_down(dlm, idx); spin_unlock(&dlm->spinlock); diff --git a/trunk/fs/ocfs2/dlm/dlmver.c b/trunk/fs/ocfs2/dlm/dlmver.c index dfc0da4d158d..7ef2653f8f41 100644 --- a/trunk/fs/ocfs2/dlm/dlmver.c +++ b/trunk/fs/ocfs2/dlm/dlmver.c @@ -28,7 +28,7 @@ #include "dlmver.h" -#define DLM_BUILD_VERSION "1.5.0" +#define DLM_BUILD_VERSION "1.3.3" #define VERSION_STR "OCFS2 DLM " DLM_BUILD_VERSION diff --git a/trunk/fs/ocfs2/dlmglue.c b/trunk/fs/ocfs2/dlmglue.c index 3867244fb144..4e97dcceaf8f 100644 --- a/trunk/fs/ocfs2/dlmglue.c +++ b/trunk/fs/ocfs2/dlmglue.c @@ -55,6 +55,7 @@ #include "slot_map.h" #include "super.h" #include "uptodate.h" +#include "vote.h" #include "buffer_head_io.h" @@ -68,7 +69,6 @@ struct ocfs2_mask_waiter { static struct ocfs2_super *ocfs2_get_dentry_osb(struct ocfs2_lock_res *lockres); static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres); -static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres); /* * Return value from ->downconvert_worker functions. @@ -153,10 +153,10 @@ struct ocfs2_lock_res_ops { struct ocfs2_super * (*get_osb)(struct ocfs2_lock_res *); /* - * Optionally called in the downconvert thread after a - * successful downconvert. The lockres will not be referenced - * after this callback is called, so it is safe to free - * memory, etc. + * Optionally called in the downconvert (or "vote") thread + * after a successful downconvert. The lockres will not be + * referenced after this callback is called, so it is safe to + * free memory, etc. * * The exact semantics of when this is called are controlled * by ->downconvert_worker() @@ -225,14 +225,19 @@ static struct ocfs2_lock_res_ops ocfs2_inode_rw_lops = { .flags = 0, }; -static struct ocfs2_lock_res_ops ocfs2_inode_inode_lops = { +static struct ocfs2_lock_res_ops ocfs2_inode_meta_lops = { .get_osb = ocfs2_get_inode_osb, .check_downconvert = ocfs2_check_meta_downconvert, .set_lvb = ocfs2_set_meta_lvb, - .downconvert_worker = ocfs2_data_convert_worker, .flags = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB, }; +static struct ocfs2_lock_res_ops ocfs2_inode_data_lops = { + .get_osb = ocfs2_get_inode_osb, + .downconvert_worker = ocfs2_data_convert_worker, + .flags = 0, +}; + static struct ocfs2_lock_res_ops ocfs2_super_lops = { .flags = LOCK_TYPE_REQUIRES_REFRESH, }; @@ -253,14 +258,10 @@ static struct ocfs2_lock_res_ops ocfs2_inode_open_lops = { .flags = 0, }; -static struct ocfs2_lock_res_ops ocfs2_flock_lops = { - .get_osb = ocfs2_get_file_osb, - .flags = 0, -}; - static inline int ocfs2_is_inode_lock(struct ocfs2_lock_res *lockres) { return lockres->l_type == OCFS2_LOCK_TYPE_META || + lockres->l_type == OCFS2_LOCK_TYPE_DATA || lockres->l_type == OCFS2_LOCK_TYPE_RW || lockres->l_type == OCFS2_LOCK_TYPE_OPEN; } @@ -309,24 +310,12 @@ static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres, "resource %s: %s\n", dlm_errname(_stat), _func, \ _lockres->l_name, dlm_errmsg(_stat)); \ } while (0) -static int ocfs2_downconvert_thread(void *arg); -static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb, - struct ocfs2_lock_res *lockres); -static int ocfs2_inode_lock_update(struct inode *inode, +static void ocfs2_vote_on_unlock(struct ocfs2_super *osb, + struct ocfs2_lock_res *lockres); +static int ocfs2_meta_lock_update(struct inode *inode, struct buffer_head **bh); static void ocfs2_drop_osb_locks(struct ocfs2_super *osb); static inline int ocfs2_highest_compat_lock_level(int level); -static void ocfs2_prepare_downconvert(struct ocfs2_lock_res *lockres, - int new_level); -static int ocfs2_downconvert_lock(struct ocfs2_super *osb, - struct ocfs2_lock_res *lockres, - int new_level, - int lvb); -static int ocfs2_prepare_cancel_convert(struct ocfs2_super *osb, - struct ocfs2_lock_res *lockres); -static int ocfs2_cancel_convert(struct ocfs2_super *osb, - struct ocfs2_lock_res *lockres); - static void ocfs2_build_lock_name(enum ocfs2_lock_type type, u64 blkno, @@ -413,7 +402,10 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res, ops = &ocfs2_inode_rw_lops; break; case OCFS2_LOCK_TYPE_META: - ops = &ocfs2_inode_inode_lops; + ops = &ocfs2_inode_meta_lops; + break; + case OCFS2_LOCK_TYPE_DATA: + ops = &ocfs2_inode_data_lops; break; case OCFS2_LOCK_TYPE_OPEN: ops = &ocfs2_inode_open_lops; @@ -436,13 +428,6 @@ static struct ocfs2_super *ocfs2_get_inode_osb(struct ocfs2_lock_res *lockres) return OCFS2_SB(inode->i_sb); } -static struct ocfs2_super *ocfs2_get_file_osb(struct ocfs2_lock_res *lockres) -{ - struct ocfs2_file_private *fp = lockres->l_priv; - - return OCFS2_SB(fp->fp_file->f_mapping->host->i_sb); -} - static __u64 ocfs2_get_dentry_lock_ino(struct ocfs2_lock_res *lockres) { __be64 inode_blkno_be; @@ -523,21 +508,6 @@ static void ocfs2_rename_lock_res_init(struct ocfs2_lock_res *res, &ocfs2_rename_lops, osb); } -void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, - struct ocfs2_file_private *fp) -{ - struct inode *inode = fp->fp_file->f_mapping->host; - struct ocfs2_inode_info *oi = OCFS2_I(inode); - - ocfs2_lock_res_init_once(lockres); - ocfs2_build_lock_name(OCFS2_LOCK_TYPE_FLOCK, oi->ip_blkno, - inode->i_generation, lockres->l_name); - ocfs2_lock_res_init_common(OCFS2_SB(inode->i_sb), lockres, - OCFS2_LOCK_TYPE_FLOCK, &ocfs2_flock_lops, - fp); - lockres->l_flags |= OCFS2_LOCK_NOCACHE; -} - void ocfs2_lock_res_free(struct ocfs2_lock_res *res) { mlog_entry_void(); @@ -754,13 +724,6 @@ static void ocfs2_blocking_ast(void *opaque, int level) lockres->l_name, level, lockres->l_level, ocfs2_lock_type_string(lockres->l_type)); - /* - * We can skip the bast for locks which don't enable caching - - * they'll be dropped at the earliest possible time anyway. - */ - if (lockres->l_flags & OCFS2_LOCK_NOCACHE) - return; - spin_lock_irqsave(&lockres->l_lock, flags); needs_downconvert = ocfs2_generic_handle_bast(lockres, level); if (needs_downconvert) @@ -769,7 +732,7 @@ static void ocfs2_blocking_ast(void *opaque, int level) wake_up(&lockres->l_event); - ocfs2_wake_downconvert_thread(osb); + ocfs2_kick_vote_thread(osb); } static void ocfs2_locking_ast(void *opaque) @@ -972,21 +935,6 @@ static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres, } -static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw, - struct ocfs2_lock_res *lockres) -{ - int ret; - - ret = wait_for_completion_interruptible(&mw->mw_complete); - if (ret) - lockres_remove_mask_waiter(lockres, mw); - else - ret = mw->mw_status; - /* Re-arm the completion in case we want to wait on it again */ - INIT_COMPLETION(mw->mw_complete); - return ret; -} - static int ocfs2_cluster_lock(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres, int level, @@ -1141,7 +1089,7 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb, mlog_entry_void(); spin_lock_irqsave(&lockres->l_lock, flags); ocfs2_dec_holders(lockres, level); - ocfs2_downconvert_on_unlock(osb, lockres); + ocfs2_vote_on_unlock(osb, lockres); spin_unlock_irqrestore(&lockres->l_lock, flags); mlog_exit_void(); } @@ -1199,7 +1147,13 @@ int ocfs2_create_new_inode_locks(struct inode *inode) * We don't want to use LKM_LOCAL on a meta data lock as they * don't use a generation in their lock names. */ - ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_inode_lockres, 1, 0); + ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_meta_lockres, 1, 0); + if (ret) { + mlog_errno(ret); + goto bail; + } + + ret = ocfs2_create_new_lock(osb, &OCFS2_I(inode)->ip_data_lockres, 1, 1); if (ret) { mlog_errno(ret); goto bail; @@ -1357,221 +1311,76 @@ void ocfs2_open_unlock(struct inode *inode) mlog_exit_void(); } -static int ocfs2_flock_handle_signal(struct ocfs2_lock_res *lockres, - int level) -{ - int ret; - struct ocfs2_super *osb = ocfs2_get_lockres_osb(lockres); - unsigned long flags; - struct ocfs2_mask_waiter mw; - - ocfs2_init_mask_waiter(&mw); - -retry_cancel: - spin_lock_irqsave(&lockres->l_lock, flags); - if (lockres->l_flags & OCFS2_LOCK_BUSY) { - ret = ocfs2_prepare_cancel_convert(osb, lockres); - if (ret) { - spin_unlock_irqrestore(&lockres->l_lock, flags); - ret = ocfs2_cancel_convert(osb, lockres); - if (ret < 0) { - mlog_errno(ret); - goto out; - } - goto retry_cancel; - } - lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0); - spin_unlock_irqrestore(&lockres->l_lock, flags); - - ocfs2_wait_for_mask(&mw); - goto retry_cancel; - } - - ret = -ERESTARTSYS; - /* - * We may still have gotten the lock, in which case there's no - * point to restarting the syscall. - */ - if (lockres->l_level == level) - ret = 0; - - mlog(0, "Cancel returning %d. flags: 0x%lx, level: %d, act: %d\n", ret, - lockres->l_flags, lockres->l_level, lockres->l_action); - - spin_unlock_irqrestore(&lockres->l_lock, flags); - -out: - return ret; -} - -/* - * ocfs2_file_lock() and ocfs2_file_unlock() map to a single pair of - * flock() calls. The locking approach this requires is sufficiently - * different from all other cluster lock types that we implement a - * seperate path to the "low-level" dlm calls. In particular: - * - * - No optimization of lock levels is done - we take at exactly - * what's been requested. - * - * - No lock caching is employed. We immediately downconvert to - * no-lock at unlock time. This also means flock locks never go on - * the blocking list). - * - * - Since userspace can trivially deadlock itself with flock, we make - * sure to allow cancellation of a misbehaving applications flock() - * request. - * - * - Access to any flock lockres doesn't require concurrency, so we - * can simplify the code by requiring the caller to guarantee - * serialization of dlmglue flock calls. - */ -int ocfs2_file_lock(struct file *file, int ex, int trylock) +int ocfs2_data_lock_full(struct inode *inode, + int write, + int arg_flags) { - int ret, level = ex ? LKM_EXMODE : LKM_PRMODE; - unsigned int lkm_flags = trylock ? LKM_NOQUEUE : 0; - unsigned long flags; - struct ocfs2_file_private *fp = file->private_data; - struct ocfs2_lock_res *lockres = &fp->fp_flock; - struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb); - struct ocfs2_mask_waiter mw; - - ocfs2_init_mask_waiter(&mw); + int status = 0, level; + struct ocfs2_lock_res *lockres; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - if ((lockres->l_flags & OCFS2_LOCK_BUSY) || - (lockres->l_level > LKM_NLMODE)) { - mlog(ML_ERROR, - "File lock \"%s\" has busy or locked state: flags: 0x%lx, " - "level: %u\n", lockres->l_name, lockres->l_flags, - lockres->l_level); - return -EINVAL; - } + BUG_ON(!inode); - spin_lock_irqsave(&lockres->l_lock, flags); - if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED)) { - lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0); - spin_unlock_irqrestore(&lockres->l_lock, flags); + mlog_entry_void(); - /* - * Get the lock at NLMODE to start - that way we - * can cancel the upconvert request if need be. - */ - ret = ocfs2_lock_create(osb, lockres, LKM_NLMODE, 0); - if (ret < 0) { - mlog_errno(ret); - goto out; - } + mlog(0, "inode %llu take %s DATA lock\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno, + write ? "EXMODE" : "PRMODE"); - ret = ocfs2_wait_for_mask(&mw); - if (ret) { - mlog_errno(ret); - goto out; + /* We'll allow faking a readonly data lock for + * rodevices. */ + if (ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb))) { + if (write) { + status = -EROFS; + mlog_errno(status); } - spin_lock_irqsave(&lockres->l_lock, flags); + goto out; } - lockres->l_action = OCFS2_AST_CONVERT; - lkm_flags |= LKM_CONVERT; - lockres->l_requested = level; - lockres_or_flags(lockres, OCFS2_LOCK_BUSY); - - lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0); - spin_unlock_irqrestore(&lockres->l_lock, flags); + if (ocfs2_mount_local(osb)) + goto out; - ret = dlmlock(osb->dlm, level, &lockres->l_lksb, lkm_flags, - lockres->l_name, OCFS2_LOCK_ID_MAX_LEN - 1, - ocfs2_locking_ast, lockres, ocfs2_blocking_ast); - if (ret != DLM_NORMAL) { - if (trylock && ret == DLM_NOTQUEUED) - ret = -EAGAIN; - else { - ocfs2_log_dlm_error("dlmlock", ret, lockres); - ret = -EINVAL; - } + lockres = &OCFS2_I(inode)->ip_data_lockres; - ocfs2_recover_from_dlm_error(lockres, 1); - lockres_remove_mask_waiter(lockres, &mw); - goto out; - } + level = write ? LKM_EXMODE : LKM_PRMODE; - ret = ocfs2_wait_for_mask_interruptible(&mw, lockres); - if (ret == -ERESTARTSYS) { - /* - * Userspace can cause deadlock itself with - * flock(). Current behavior locally is to allow the - * deadlock, but abort the system call if a signal is - * received. We follow this example, otherwise a - * poorly written program could sit in kernel until - * reboot. - * - * Handling this is a bit more complicated for Ocfs2 - * though. We can't exit this function with an - * outstanding lock request, so a cancel convert is - * required. We intentionally overwrite 'ret' - if the - * cancel fails and the lock was granted, it's easier - * to just bubble sucess back up to the user. - */ - ret = ocfs2_flock_handle_signal(lockres, level); - } + status = ocfs2_cluster_lock(OCFS2_SB(inode->i_sb), lockres, level, + 0, arg_flags); + if (status < 0 && status != -EAGAIN) + mlog_errno(status); out: - - mlog(0, "Lock: \"%s\" ex: %d, trylock: %d, returns: %d\n", - lockres->l_name, ex, trylock, ret); - return ret; + mlog_exit(status); + return status; } -void ocfs2_file_unlock(struct file *file) +/* see ocfs2_meta_lock_with_page() */ +int ocfs2_data_lock_with_page(struct inode *inode, + int write, + struct page *page) { int ret; - unsigned long flags; - struct ocfs2_file_private *fp = file->private_data; - struct ocfs2_lock_res *lockres = &fp->fp_flock; - struct ocfs2_super *osb = OCFS2_SB(file->f_mapping->host->i_sb); - struct ocfs2_mask_waiter mw; - - ocfs2_init_mask_waiter(&mw); - - if (!(lockres->l_flags & OCFS2_LOCK_ATTACHED)) - return; - - if (lockres->l_level == LKM_NLMODE) - return; - - mlog(0, "Unlock: \"%s\" flags: 0x%lx, level: %d, act: %d\n", - lockres->l_name, lockres->l_flags, lockres->l_level, - lockres->l_action); - spin_lock_irqsave(&lockres->l_lock, flags); - /* - * Fake a blocking ast for the downconvert code. - */ - lockres_or_flags(lockres, OCFS2_LOCK_BLOCKED); - lockres->l_blocking = LKM_EXMODE; - - ocfs2_prepare_downconvert(lockres, LKM_NLMODE); - lockres_add_mask_waiter(lockres, &mw, OCFS2_LOCK_BUSY, 0); - spin_unlock_irqrestore(&lockres->l_lock, flags); - - ret = ocfs2_downconvert_lock(osb, lockres, LKM_NLMODE, 0); - if (ret) { - mlog_errno(ret); - return; + ret = ocfs2_data_lock_full(inode, write, OCFS2_LOCK_NONBLOCK); + if (ret == -EAGAIN) { + unlock_page(page); + if (ocfs2_data_lock(inode, write) == 0) + ocfs2_data_unlock(inode, write); + ret = AOP_TRUNCATED_PAGE; } - ret = ocfs2_wait_for_mask(&mw); - if (ret) - mlog_errno(ret); + return ret; } -static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb, - struct ocfs2_lock_res *lockres) +static void ocfs2_vote_on_unlock(struct ocfs2_super *osb, + struct ocfs2_lock_res *lockres) { int kick = 0; mlog_entry_void(); /* If we know that another node is waiting on our lock, kick - * the downconvert thread * pre-emptively when we reach a release + * the vote thread * pre-emptively when we reach a release * condition. */ if (lockres->l_flags & OCFS2_LOCK_BLOCKED) { switch(lockres->l_blocking) { @@ -1589,7 +1398,27 @@ static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb, } if (kick) - ocfs2_wake_downconvert_thread(osb); + ocfs2_kick_vote_thread(osb); + + mlog_exit_void(); +} + +void ocfs2_data_unlock(struct inode *inode, + int write) +{ + int level = write ? LKM_EXMODE : LKM_PRMODE; + struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_data_lockres; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + + mlog_entry_void(); + + mlog(0, "inode %llu drop %s DATA lock\n", + (unsigned long long)OCFS2_I(inode)->ip_blkno, + write ? "EXMODE" : "PRMODE"); + + if (!ocfs2_is_hard_readonly(OCFS2_SB(inode->i_sb)) && + !ocfs2_mount_local(osb)) + ocfs2_cluster_unlock(OCFS2_SB(inode->i_sb), lockres, level); mlog_exit_void(); } @@ -1613,11 +1442,11 @@ static u64 ocfs2_pack_timespec(struct timespec *spec) /* Call this with the lockres locked. I am reasonably sure we don't * need ip_lock in this function as anyone who would be changing those - * values is supposed to be blocked in ocfs2_inode_lock right now. */ + * values is supposed to be blocked in ocfs2_meta_lock right now. */ static void __ocfs2_stuff_meta_lvb(struct inode *inode) { struct ocfs2_inode_info *oi = OCFS2_I(inode); - struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres; + struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres; struct ocfs2_meta_lvb *lvb; mlog_entry_void(); @@ -1667,7 +1496,7 @@ static void ocfs2_unpack_timespec(struct timespec *spec, static void ocfs2_refresh_inode_from_lvb(struct inode *inode) { struct ocfs2_inode_info *oi = OCFS2_I(inode); - struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres; + struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres; struct ocfs2_meta_lvb *lvb; mlog_entry_void(); @@ -1775,12 +1604,12 @@ static inline void ocfs2_complete_lock_res_refresh(struct ocfs2_lock_res *lockre } /* may or may not return a bh if it went to disk. */ -static int ocfs2_inode_lock_update(struct inode *inode, +static int ocfs2_meta_lock_update(struct inode *inode, struct buffer_head **bh) { int status = 0; struct ocfs2_inode_info *oi = OCFS2_I(inode); - struct ocfs2_lock_res *lockres = &oi->ip_inode_lockres; + struct ocfs2_lock_res *lockres = &oi->ip_meta_lockres; struct ocfs2_dinode *fe; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); @@ -1892,7 +1721,7 @@ static int ocfs2_assign_bh(struct inode *inode, * returns < 0 error if the callback will never be called, otherwise * the result of the lock will be communicated via the callback. */ -int ocfs2_inode_lock_full(struct inode *inode, +int ocfs2_meta_lock_full(struct inode *inode, struct buffer_head **ret_bh, int ex, int arg_flags) @@ -1927,7 +1756,7 @@ int ocfs2_inode_lock_full(struct inode *inode, wait_event(osb->recovery_event, ocfs2_node_map_is_empty(osb, &osb->recovery_map)); - lockres = &OCFS2_I(inode)->ip_inode_lockres; + lockres = &OCFS2_I(inode)->ip_meta_lockres; level = ex ? LKM_EXMODE : LKM_PRMODE; dlm_flags = 0; if (arg_flags & OCFS2_META_LOCK_NOQUEUE) @@ -1966,11 +1795,11 @@ int ocfs2_inode_lock_full(struct inode *inode, } /* This is fun. The caller may want a bh back, or it may - * not. ocfs2_inode_lock_update definitely wants one in, but + * not. ocfs2_meta_lock_update definitely wants one in, but * may or may not read one, depending on what's in the * LVB. The result of all of this is that we've *only* gone to * disk if we have to, so the complexity is worthwhile. */ - status = ocfs2_inode_lock_update(inode, &local_bh); + status = ocfs2_meta_lock_update(inode, &local_bh); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -1992,7 +1821,7 @@ int ocfs2_inode_lock_full(struct inode *inode, *ret_bh = NULL; } if (acquired) - ocfs2_inode_unlock(inode, ex); + ocfs2_meta_unlock(inode, ex); } if (local_bh) @@ -2003,20 +1832,19 @@ int ocfs2_inode_lock_full(struct inode *inode, } /* - * This is working around a lock inversion between tasks acquiring DLM - * locks while holding a page lock and the downconvert thread which - * blocks dlm lock acquiry while acquiring page locks. + * This is working around a lock inversion between tasks acquiring DLM locks + * while holding a page lock and the vote thread which blocks dlm lock acquiry + * while acquiring page locks. * * ** These _with_page variantes are only intended to be called from aop * methods that hold page locks and return a very specific *positive* error * code that aop methods pass up to the VFS -- test for errors with != 0. ** * - * The DLM is called such that it returns -EAGAIN if it would have - * blocked waiting for the downconvert thread. In that case we unlock - * our page so the downconvert thread can make progress. Once we've - * done this we have to return AOP_TRUNCATED_PAGE so the aop method - * that called us can bubble that back up into the VFS who will then - * immediately retry the aop call. + * The DLM is called such that it returns -EAGAIN if it would have blocked + * waiting for the vote thread. In that case we unlock our page so the vote + * thread can make progress. Once we've done this we have to return + * AOP_TRUNCATED_PAGE so the aop method that called us can bubble that back up + * into the VFS who will then immediately retry the aop call. * * We do a blocking lock and immediate unlock before returning, though, so that * the lock has a great chance of being cached on this node by the time the VFS @@ -2024,32 +1852,32 @@ int ocfs2_inode_lock_full(struct inode *inode, * ping locks back and forth, but that's a risk we're willing to take to avoid * the lock inversion simply. */ -int ocfs2_inode_lock_with_page(struct inode *inode, +int ocfs2_meta_lock_with_page(struct inode *inode, struct buffer_head **ret_bh, int ex, struct page *page) { int ret; - ret = ocfs2_inode_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK); + ret = ocfs2_meta_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK); if (ret == -EAGAIN) { unlock_page(page); - if (ocfs2_inode_lock(inode, ret_bh, ex) == 0) - ocfs2_inode_unlock(inode, ex); + if (ocfs2_meta_lock(inode, ret_bh, ex) == 0) + ocfs2_meta_unlock(inode, ex); ret = AOP_TRUNCATED_PAGE; } return ret; } -int ocfs2_inode_lock_atime(struct inode *inode, +int ocfs2_meta_lock_atime(struct inode *inode, struct vfsmount *vfsmnt, int *level) { int ret; mlog_entry_void(); - ret = ocfs2_inode_lock(inode, NULL, 0); + ret = ocfs2_meta_lock(inode, NULL, 0); if (ret < 0) { mlog_errno(ret); return ret; @@ -2062,8 +1890,8 @@ int ocfs2_inode_lock_atime(struct inode *inode, if (ocfs2_should_update_atime(inode, vfsmnt)) { struct buffer_head *bh = NULL; - ocfs2_inode_unlock(inode, 0); - ret = ocfs2_inode_lock(inode, &bh, 1); + ocfs2_meta_unlock(inode, 0); + ret = ocfs2_meta_lock(inode, &bh, 1); if (ret < 0) { mlog_errno(ret); return ret; @@ -2080,11 +1908,11 @@ int ocfs2_inode_lock_atime(struct inode *inode, return ret; } -void ocfs2_inode_unlock(struct inode *inode, +void ocfs2_meta_unlock(struct inode *inode, int ex) { int level = ex ? LKM_EXMODE : LKM_PRMODE; - struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_inode_lockres; + struct ocfs2_lock_res *lockres = &OCFS2_I(inode)->ip_meta_lockres; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); mlog_entry_void(); @@ -2492,11 +2320,11 @@ int ocfs2_dlm_init(struct ocfs2_super *osb) goto bail; } - /* launch downconvert thread */ - osb->dc_task = kthread_run(ocfs2_downconvert_thread, osb, "ocfs2dc"); - if (IS_ERR(osb->dc_task)) { - status = PTR_ERR(osb->dc_task); - osb->dc_task = NULL; + /* launch vote thread */ + osb->vote_task = kthread_run(ocfs2_vote_thread, osb, "ocfs2vote"); + if (IS_ERR(osb->vote_task)) { + status = PTR_ERR(osb->vote_task); + osb->vote_task = NULL; mlog_errno(status); goto bail; } @@ -2525,8 +2353,8 @@ int ocfs2_dlm_init(struct ocfs2_super *osb) bail: if (status < 0) { ocfs2_dlm_shutdown_debug(osb); - if (osb->dc_task) - kthread_stop(osb->dc_task); + if (osb->vote_task) + kthread_stop(osb->vote_task); } mlog_exit(status); @@ -2541,9 +2369,9 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb) ocfs2_drop_osb_locks(osb); - if (osb->dc_task) { - kthread_stop(osb->dc_task); - osb->dc_task = NULL; + if (osb->vote_task) { + kthread_stop(osb->vote_task); + osb->vote_task = NULL; } ocfs2_lock_res_free(&osb->osb_super_lockres); @@ -2699,7 +2527,7 @@ static int ocfs2_drop_lock(struct ocfs2_super *osb, /* Mark the lockres as being dropped. It will no longer be * queued if blocking, but we still may have to wait on it - * being dequeued from the downconvert thread before we can consider + * being dequeued from the vote thread before we can consider * it safe to drop. * * You can *not* attempt to call cluster_lock on this lockres anymore. */ @@ -2762,7 +2590,14 @@ int ocfs2_drop_inode_locks(struct inode *inode) status = err; err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb), - &OCFS2_I(inode)->ip_inode_lockres); + &OCFS2_I(inode)->ip_data_lockres); + if (err < 0) + mlog_errno(err); + if (err < 0 && !status) + status = err; + + err = ocfs2_drop_lock(OCFS2_SB(inode->i_sb), + &OCFS2_I(inode)->ip_meta_lockres); if (err < 0) mlog_errno(err); if (err < 0 && !status) @@ -3015,9 +2850,6 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres, inode = ocfs2_lock_res_inode(lockres); mapping = inode->i_mapping; - if (S_ISREG(inode->i_mode)) - goto out; - /* * We need this before the filemap_fdatawrite() so that it can * transfer the dirty bit from the PTE to the @@ -3043,7 +2875,6 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres, filemap_fdatawait(mapping); } -out: return UNBLOCK_CONTINUE; } @@ -3072,7 +2903,7 @@ static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres) /* * Does the final reference drop on our dentry lock. Right now this - * happens in the downconvert thread, but we could choose to simplify the + * happens in the vote thread, but we could choose to simplify the * dlmglue API and push these off to the ocfs2_wq in the future. */ static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb, @@ -3211,7 +3042,7 @@ void ocfs2_process_blocked_lock(struct ocfs2_super *osb, mlog(0, "lockres %s blocked.\n", lockres->l_name); /* Detect whether a lock has been marked as going away while - * the downconvert thread was processing other things. A lock can + * the vote thread was processing other things. A lock can * still be marked with OCFS2_LOCK_FREEING after this check, * but short circuiting here will still save us some * performance. */ @@ -3260,104 +3091,13 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb, lockres_or_flags(lockres, OCFS2_LOCK_QUEUED); - spin_lock(&osb->dc_task_lock); + spin_lock(&osb->vote_task_lock); if (list_empty(&lockres->l_blocked_list)) { list_add_tail(&lockres->l_blocked_list, &osb->blocked_lock_list); osb->blocked_lock_count++; } - spin_unlock(&osb->dc_task_lock); - - mlog_exit_void(); -} - -static void ocfs2_downconvert_thread_do_work(struct ocfs2_super *osb) -{ - unsigned long processed; - struct ocfs2_lock_res *lockres; - - mlog_entry_void(); - - spin_lock(&osb->dc_task_lock); - /* grab this early so we know to try again if a state change and - * wake happens part-way through our work */ - osb->dc_work_sequence = osb->dc_wake_sequence; - - processed = osb->blocked_lock_count; - while (processed) { - BUG_ON(list_empty(&osb->blocked_lock_list)); - - lockres = list_entry(osb->blocked_lock_list.next, - struct ocfs2_lock_res, l_blocked_list); - list_del_init(&lockres->l_blocked_list); - osb->blocked_lock_count--; - spin_unlock(&osb->dc_task_lock); - - BUG_ON(!processed); - processed--; - - ocfs2_process_blocked_lock(osb, lockres); - - spin_lock(&osb->dc_task_lock); - } - spin_unlock(&osb->dc_task_lock); + spin_unlock(&osb->vote_task_lock); mlog_exit_void(); } - -static int ocfs2_downconvert_thread_lists_empty(struct ocfs2_super *osb) -{ - int empty = 0; - - spin_lock(&osb->dc_task_lock); - if (list_empty(&osb->blocked_lock_list)) - empty = 1; - - spin_unlock(&osb->dc_task_lock); - return empty; -} - -static int ocfs2_downconvert_thread_should_wake(struct ocfs2_super *osb) -{ - int should_wake = 0; - - spin_lock(&osb->dc_task_lock); - if (osb->dc_work_sequence != osb->dc_wake_sequence) - should_wake = 1; - spin_unlock(&osb->dc_task_lock); - - return should_wake; -} - -int ocfs2_downconvert_thread(void *arg) -{ - int status = 0; - struct ocfs2_super *osb = arg; - - /* only quit once we've been asked to stop and there is no more - * work available */ - while (!(kthread_should_stop() && - ocfs2_downconvert_thread_lists_empty(osb))) { - - wait_event_interruptible(osb->dc_event, - ocfs2_downconvert_thread_should_wake(osb) || - kthread_should_stop()); - - mlog(0, "downconvert_thread: awoken\n"); - - ocfs2_downconvert_thread_do_work(osb); - } - - osb->dc_task = NULL; - return status; -} - -void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb) -{ - spin_lock(&osb->dc_task_lock); - /* make sure the voting thread gets a swipe at whatever changes - * the caller may have made to the voting state */ - osb->dc_wake_sequence++; - spin_unlock(&osb->dc_task_lock); - wake_up(&osb->dc_event); -} diff --git a/trunk/fs/ocfs2/dlmglue.h b/trunk/fs/ocfs2/dlmglue.h index 5f17243ba501..87a785e41205 100644 --- a/trunk/fs/ocfs2/dlmglue.h +++ b/trunk/fs/ocfs2/dlmglue.h @@ -49,12 +49,12 @@ struct ocfs2_meta_lvb { __be32 lvb_reserved2; }; -/* ocfs2_inode_lock_full() 'arg_flags' flags */ +/* ocfs2_meta_lock_full() and ocfs2_data_lock_full() 'arg_flags' flags */ /* don't wait on recovery. */ #define OCFS2_META_LOCK_RECOVERY (0x01) /* Instruct the dlm not to queue ourselves on the other node. */ #define OCFS2_META_LOCK_NOQUEUE (0x02) -/* don't block waiting for the downconvert thread, instead return -EAGAIN */ +/* don't block waiting for the vote thread, instead return -EAGAIN */ #define OCFS2_LOCK_NONBLOCK (0x04) int ocfs2_dlm_init(struct ocfs2_super *osb); @@ -66,32 +66,38 @@ void ocfs2_inode_lock_res_init(struct ocfs2_lock_res *res, struct inode *inode); void ocfs2_dentry_lock_res_init(struct ocfs2_dentry_lock *dl, u64 parent, struct inode *inode); -struct ocfs2_file_private; -void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, - struct ocfs2_file_private *fp); void ocfs2_lock_res_free(struct ocfs2_lock_res *res); int ocfs2_create_new_inode_locks(struct inode *inode); int ocfs2_drop_inode_locks(struct inode *inode); +int ocfs2_data_lock_full(struct inode *inode, + int write, + int arg_flags); +#define ocfs2_data_lock(inode, write) ocfs2_data_lock_full(inode, write, 0) +int ocfs2_data_lock_with_page(struct inode *inode, + int write, + struct page *page); +void ocfs2_data_unlock(struct inode *inode, + int write); int ocfs2_rw_lock(struct inode *inode, int write); void ocfs2_rw_unlock(struct inode *inode, int write); int ocfs2_open_lock(struct inode *inode); int ocfs2_try_open_lock(struct inode *inode, int write); void ocfs2_open_unlock(struct inode *inode); -int ocfs2_inode_lock_atime(struct inode *inode, +int ocfs2_meta_lock_atime(struct inode *inode, struct vfsmount *vfsmnt, int *level); -int ocfs2_inode_lock_full(struct inode *inode, +int ocfs2_meta_lock_full(struct inode *inode, struct buffer_head **ret_bh, int ex, int arg_flags); -int ocfs2_inode_lock_with_page(struct inode *inode, +int ocfs2_meta_lock_with_page(struct inode *inode, struct buffer_head **ret_bh, int ex, struct page *page); /* 99% of the time we don't want to supply any additional flags -- * those are for very specific cases only. */ -#define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0) -void ocfs2_inode_unlock(struct inode *inode, +#define ocfs2_meta_lock(i, b, e) ocfs2_meta_lock_full(i, b, e, 0) +void ocfs2_meta_unlock(struct inode *inode, int ex); int ocfs2_super_lock(struct ocfs2_super *osb, int ex); @@ -101,17 +107,14 @@ int ocfs2_rename_lock(struct ocfs2_super *osb); void ocfs2_rename_unlock(struct ocfs2_super *osb); int ocfs2_dentry_lock(struct dentry *dentry, int ex); void ocfs2_dentry_unlock(struct dentry *dentry, int ex); -int ocfs2_file_lock(struct file *file, int ex, int trylock); -void ocfs2_file_unlock(struct file *file); void ocfs2_mark_lockres_freeing(struct ocfs2_lock_res *lockres); void ocfs2_simple_drop_lockres(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres); -/* for the downconvert thread */ +/* for the vote thread */ void ocfs2_process_blocked_lock(struct ocfs2_super *osb, struct ocfs2_lock_res *lockres); -void ocfs2_wake_downconvert_thread(struct ocfs2_super *osb); struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void); void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug); diff --git a/trunk/fs/ocfs2/endian.h b/trunk/fs/ocfs2/endian.h index 1942e09f6ee5..ff257628af16 100644 --- a/trunk/fs/ocfs2/endian.h +++ b/trunk/fs/ocfs2/endian.h @@ -37,6 +37,11 @@ static inline void le64_add_cpu(__le64 *var, u64 val) *var = cpu_to_le64(le64_to_cpu(*var) + val); } +static inline void le32_and_cpu(__le32 *var, u32 val) +{ + *var = cpu_to_le32(le32_to_cpu(*var) & val); +} + static inline void be32_add_cpu(__be32 *var, u32 val) { *var = cpu_to_be32(be32_to_cpu(*var) + val); diff --git a/trunk/fs/ocfs2/export.c b/trunk/fs/ocfs2/export.c index 67527cebf214..535bfa9568a4 100644 --- a/trunk/fs/ocfs2/export.c +++ b/trunk/fs/ocfs2/export.c @@ -58,7 +58,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb, return ERR_PTR(-ESTALE); } - inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0, 0); + inode = ocfs2_iget(OCFS2_SB(sb), handle->ih_blkno, 0); if (IS_ERR(inode)) return (void *)inode; @@ -95,7 +95,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) mlog(0, "find parent of directory %llu\n", (unsigned long long)OCFS2_I(dir)->ip_blkno); - status = ocfs2_inode_lock(dir, NULL, 0); + status = ocfs2_meta_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -109,7 +109,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) goto bail_unlock; } - inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0); + inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0); if (IS_ERR(inode)) { mlog(ML_ERROR, "Unable to create inode %llu\n", (unsigned long long)blkno); @@ -126,7 +126,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) parent->d_op = &ocfs2_dentry_ops; bail_unlock: - ocfs2_inode_unlock(dir, 0); + ocfs2_meta_unlock(dir, 0); bail: mlog_exit_ptr(parent); diff --git a/trunk/fs/ocfs2/file.c b/trunk/fs/ocfs2/file.c index ed5d5232e85d..b75b2e1f0e42 100644 --- a/trunk/fs/ocfs2/file.c +++ b/trunk/fs/ocfs2/file.c @@ -51,7 +51,6 @@ #include "inode.h" #include "ioctl.h" #include "journal.h" -#include "locks.h" #include "mmap.h" #include "suballoc.h" #include "super.h" @@ -64,35 +63,6 @@ static int ocfs2_sync_inode(struct inode *inode) return sync_mapping_buffers(inode->i_mapping); } -static int ocfs2_init_file_private(struct inode *inode, struct file *file) -{ - struct ocfs2_file_private *fp; - - fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL); - if (!fp) - return -ENOMEM; - - fp->fp_file = file; - mutex_init(&fp->fp_mutex); - ocfs2_file_lock_res_init(&fp->fp_flock, fp); - file->private_data = fp; - - return 0; -} - -static void ocfs2_free_file_private(struct inode *inode, struct file *file) -{ - struct ocfs2_file_private *fp = file->private_data; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - - if (fp) { - ocfs2_simple_drop_lockres(osb, &fp->fp_flock); - ocfs2_lock_res_free(&fp->fp_flock); - kfree(fp); - file->private_data = NULL; - } -} - static int ocfs2_file_open(struct inode *inode, struct file *file) { int status; @@ -119,18 +89,7 @@ static int ocfs2_file_open(struct inode *inode, struct file *file) oi->ip_open_count++; spin_unlock(&oi->ip_lock); - - status = ocfs2_init_file_private(inode, file); - if (status) { - /* - * We want to set open count back if we're failing the - * open. - */ - spin_lock(&oi->ip_lock); - oi->ip_open_count--; - spin_unlock(&oi->ip_lock); - } - + status = 0; leave: mlog_exit(status); return status; @@ -149,24 +108,11 @@ static int ocfs2_file_release(struct inode *inode, struct file *file) oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT; spin_unlock(&oi->ip_lock); - ocfs2_free_file_private(inode, file); - mlog_exit(0); return 0; } -static int ocfs2_dir_open(struct inode *inode, struct file *file) -{ - return ocfs2_init_file_private(inode, file); -} - -static int ocfs2_dir_release(struct inode *inode, struct file *file) -{ - ocfs2_free_file_private(inode, file); - return 0; -} - static int ocfs2_sync_file(struct file *file, struct dentry *dentry, int datasync) @@ -436,13 +382,18 @@ static int ocfs2_truncate_file(struct inode *inode, down_write(&OCFS2_I(inode)->ip_alloc_sem); - /* - * The inode lock forced other nodes to sync and drop their - * pages, which (correctly) happens even if we have a truncate - * without allocation change - ocfs2 cluster sizes can be much - * greater than page size, so we have to truncate them - * anyway. - */ + /* This forces other nodes to sync and drop their pages. Do + * this even if we have a truncate without allocation change - + * ocfs2 cluster sizes can be much greater than page size, so + * we have to truncate them anyway. */ + status = ocfs2_data_lock(inode, 1); + if (status < 0) { + up_write(&OCFS2_I(inode)->ip_alloc_sem); + + mlog_errno(status); + goto bail; + } + unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1); truncate_inode_pages(inode->i_mapping, new_i_size); @@ -452,7 +403,7 @@ static int ocfs2_truncate_file(struct inode *inode, if (status) mlog_errno(status); - goto bail_unlock_sem; + goto bail_unlock_data; } /* alright, we're going to need to do a full blown alloc size @@ -462,23 +413,25 @@ static int ocfs2_truncate_file(struct inode *inode, status = ocfs2_orphan_for_truncate(osb, inode, di_bh, new_i_size); if (status < 0) { mlog_errno(status); - goto bail_unlock_sem; + goto bail_unlock_data; } status = ocfs2_prepare_truncate(osb, inode, di_bh, &tc); if (status < 0) { mlog_errno(status); - goto bail_unlock_sem; + goto bail_unlock_data; } status = ocfs2_commit_truncate(osb, inode, di_bh, tc); if (status < 0) { mlog_errno(status); - goto bail_unlock_sem; + goto bail_unlock_data; } /* TODO: orphan dir cleanup here. */ -bail_unlock_sem: +bail_unlock_data: + ocfs2_data_unlock(inode, 1); + up_write(&OCFS2_I(inode)->ip_alloc_sem); bail: @@ -626,7 +579,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, " "clusters_to_add = %u, extents_to_split = %u\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno, (long long)i_size_read(inode), + (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode), le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split); num_free_extents = ocfs2_num_free_extents(osb, inode, di); @@ -807,7 +760,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start, le32_to_cpu(fe->i_clusters), (unsigned long long)le64_to_cpu(fe->i_size)); mlog(0, "inode: ip_clusters=%u, i_size=%lld\n", - OCFS2_I(inode)->ip_clusters, (long long)i_size_read(inode)); + OCFS2_I(inode)->ip_clusters, i_size_read(inode)); leave: if (handle) { @@ -964,7 +917,7 @@ static int ocfs2_extend_file(struct inode *inode, struct buffer_head *di_bh, u64 new_i_size) { - int ret = 0; + int ret = 0, data_locked = 0; struct ocfs2_inode_info *oi = OCFS2_I(inode); BUG_ON(!di_bh); @@ -990,6 +943,20 @@ static int ocfs2_extend_file(struct inode *inode, && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) goto out_update_size; + /* + * protect the pages that ocfs2_zero_extend is going to be + * pulling into the page cache.. we do this before the + * metadata extend so that we don't get into the situation + * where we've extended the metadata but can't get the data + * lock to zero. + */ + ret = ocfs2_data_lock(inode, 1); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + data_locked = 1; + /* * The alloc sem blocks people in read/write from reading our * allocation until we're done changing it. We depend on @@ -1013,7 +980,7 @@ static int ocfs2_extend_file(struct inode *inode, up_write(&oi->ip_alloc_sem); mlog_errno(ret); - goto out; + goto out_unlock; } } @@ -1024,7 +991,7 @@ static int ocfs2_extend_file(struct inode *inode, if (ret < 0) { mlog_errno(ret); - goto out; + goto out_unlock; } out_update_size: @@ -1032,6 +999,10 @@ static int ocfs2_extend_file(struct inode *inode, if (ret < 0) mlog_errno(ret); +out_unlock: + if (data_locked) + ocfs2_data_unlock(inode, 1); + out: return ret; } @@ -1079,7 +1050,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) } } - status = ocfs2_inode_lock(inode, &bh, 1); + status = ocfs2_meta_lock(inode, &bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -1131,7 +1102,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) bail_commit: ocfs2_commit_trans(osb, handle); bail_unlock: - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); bail_unlock_rw: if (size_change) ocfs2_rw_unlock(inode, 1); @@ -1178,7 +1149,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd) mlog_entry_void(); - ret = ocfs2_inode_lock(inode, NULL, 0); + ret = ocfs2_meta_lock(inode, NULL, 0); if (ret) { if (ret != -ENOENT) mlog_errno(ret); @@ -1187,7 +1158,7 @@ int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd) ret = generic_permission(inode, mask, NULL); - ocfs2_inode_unlock(inode, 0); + ocfs2_meta_unlock(inode, 0); out: mlog_exit(ret); return ret; @@ -1659,7 +1630,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, goto out; } - ret = ocfs2_inode_lock(inode, &di_bh, 1); + ret = ocfs2_meta_lock(inode, &di_bh, 1); if (ret) { mlog_errno(ret); goto out_rw_unlock; @@ -1667,7 +1638,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) { ret = -EPERM; - goto out_inode_unlock; + goto out_meta_unlock; } switch (sr->l_whence) { @@ -1681,7 +1652,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, break; default: ret = -EINVAL; - goto out_inode_unlock; + goto out_meta_unlock; } sr->l_whence = 0; @@ -1692,14 +1663,14 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, || (sr->l_start + llen) < 0 || (sr->l_start + llen) > max_off) { ret = -EINVAL; - goto out_inode_unlock; + goto out_meta_unlock; } size = sr->l_start + sr->l_len; if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) { if (sr->l_len <= 0) { ret = -EINVAL; - goto out_inode_unlock; + goto out_meta_unlock; } } @@ -1707,7 +1678,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, ret = __ocfs2_write_remove_suid(inode, di_bh); if (ret) { mlog_errno(ret); - goto out_inode_unlock; + goto out_meta_unlock; } } @@ -1733,7 +1704,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, up_write(&OCFS2_I(inode)->ip_alloc_sem); if (ret) { mlog_errno(ret); - goto out_inode_unlock; + goto out_meta_unlock; } /* @@ -1743,7 +1714,7 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, if (IS_ERR(handle)) { ret = PTR_ERR(handle); mlog_errno(ret); - goto out_inode_unlock; + goto out_meta_unlock; } if (change_size && i_size_read(inode) < size) @@ -1756,9 +1727,9 @@ static int __ocfs2_change_file_space(struct file *file, struct inode *inode, ocfs2_commit_trans(osb, handle); -out_inode_unlock: +out_meta_unlock: brelse(di_bh); - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); out_rw_unlock: ocfs2_rw_unlock(inode, 1); @@ -1828,7 +1799,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, * if we need to make modifications here. */ for(;;) { - ret = ocfs2_inode_lock(inode, NULL, meta_level); + ret = ocfs2_meta_lock(inode, NULL, meta_level); if (ret < 0) { meta_level = -1; mlog_errno(ret); @@ -1846,7 +1817,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, * set inode->i_size at the end of a write. */ if (should_remove_suid(dentry)) { if (meta_level == 0) { - ocfs2_inode_unlock(inode, meta_level); + ocfs2_meta_unlock(inode, meta_level); meta_level = 1; continue; } @@ -1915,7 +1886,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, *ppos = saved_pos; out_unlock: - ocfs2_inode_unlock(inode, meta_level); + ocfs2_meta_unlock(inode, meta_level); out: return ret; @@ -2128,12 +2099,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in, /* * See the comment in ocfs2_file_aio_read() */ - ret = ocfs2_inode_lock(inode, NULL, 0); + ret = ocfs2_meta_lock(inode, NULL, 0); if (ret < 0) { mlog_errno(ret); goto bail; } - ocfs2_inode_unlock(inode, 0); + ocfs2_meta_unlock(inode, 0); ret = generic_file_splice_read(in, ppos, pipe, len, flags); @@ -2189,12 +2160,12 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, * like i_size. This allows the checks down below * generic_file_aio_read() a chance of actually working. */ - ret = ocfs2_inode_lock_atime(inode, filp->f_vfsmnt, &lock_level); + ret = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); if (ret < 0) { mlog_errno(ret); goto bail; } - ocfs2_inode_unlock(inode, lock_level); + ocfs2_meta_unlock(inode, lock_level); ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos); if (ret == -EINVAL) @@ -2233,7 +2204,6 @@ const struct inode_operations ocfs2_special_file_iops = { }; const struct file_operations ocfs2_fops = { - .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, .mmap = ocfs2_mmap, @@ -2246,21 +2216,16 @@ const struct file_operations ocfs2_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ocfs2_compat_ioctl, #endif - .flock = ocfs2_flock, .splice_read = ocfs2_file_splice_read, .splice_write = ocfs2_file_splice_write, }; const struct file_operations ocfs2_dops = { - .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = ocfs2_readdir, .fsync = ocfs2_sync_file, - .release = ocfs2_dir_release, - .open = ocfs2_dir_open, .ioctl = ocfs2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ocfs2_compat_ioctl, #endif - .flock = ocfs2_flock, }; diff --git a/trunk/fs/ocfs2/file.h b/trunk/fs/ocfs2/file.h index 048ddcaf5c80..066f14add3a8 100644 --- a/trunk/fs/ocfs2/file.h +++ b/trunk/fs/ocfs2/file.h @@ -32,12 +32,6 @@ extern const struct inode_operations ocfs2_file_iops; extern const struct inode_operations ocfs2_special_file_iops; struct ocfs2_alloc_context; -struct ocfs2_file_private { - struct file *fp_file; - struct mutex fp_mutex; - struct ocfs2_lock_res fp_flock; -}; - enum ocfs2_alloc_restarted { RESTART_NONE = 0, RESTART_TRANS, diff --git a/trunk/fs/ocfs2/heartbeat.c b/trunk/fs/ocfs2/heartbeat.c index c0efd9489fe8..c4c36171240d 100644 --- a/trunk/fs/ocfs2/heartbeat.c +++ b/trunk/fs/ocfs2/heartbeat.c @@ -30,6 +30,9 @@ #include #include +#include +#include + #include #define MLOG_MASK_PREFIX ML_SUPER @@ -41,9 +44,13 @@ #include "heartbeat.h" #include "inode.h" #include "journal.h" +#include "vote.h" #include "buffer_head_io.h" +#define OCFS2_HB_NODE_DOWN_PRI (0x0000002) +#define OCFS2_HB_NODE_UP_PRI OCFS2_HB_NODE_DOWN_PRI + static inline void __ocfs2_node_map_set_bit(struct ocfs2_node_map *map, int bit); static inline void __ocfs2_node_map_clear_bit(struct ocfs2_node_map *map, @@ -57,7 +64,9 @@ static void __ocfs2_node_map_set(struct ocfs2_node_map *target, void ocfs2_init_node_maps(struct ocfs2_super *osb) { spin_lock_init(&osb->node_map_lock); + ocfs2_node_map_init(&osb->mounted_map); ocfs2_node_map_init(&osb->recovery_map); + ocfs2_node_map_init(&osb->umount_map); ocfs2_node_map_init(&osb->osb_recovering_orphan_dirs); } @@ -78,7 +87,24 @@ static void ocfs2_do_node_down(int node_num, return; } + if (ocfs2_node_map_test_bit(osb, &osb->umount_map, node_num)) { + /* If a node is in the umount map, then we've been + * expecting him to go down and we know ahead of time + * that recovery is not necessary. */ + ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num); + return; + } + ocfs2_recovery_thread(osb, node_num); + + ocfs2_remove_node_from_vote_queues(osb, node_num); +} + +static void ocfs2_hb_node_down_cb(struct o2nm_node *node, + int node_num, + void *data) +{ + ocfs2_do_node_down(node_num, (struct ocfs2_super *) data); } /* Called from the dlm when it's about to evict a node. We may also @@ -95,8 +121,27 @@ static void ocfs2_dlm_eviction_cb(int node_num, ocfs2_do_node_down(node_num, osb); } +static void ocfs2_hb_node_up_cb(struct o2nm_node *node, + int node_num, + void *data) +{ + struct ocfs2_super *osb = data; + + BUG_ON(osb->node_num == node_num); + + mlog(0, "node up event for %d\n", node_num); + ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num); +} + void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb) { + o2hb_setup_callback(&osb->osb_hb_down, O2HB_NODE_DOWN_CB, + ocfs2_hb_node_down_cb, osb, + OCFS2_HB_NODE_DOWN_PRI); + + o2hb_setup_callback(&osb->osb_hb_up, O2HB_NODE_UP_CB, + ocfs2_hb_node_up_cb, osb, OCFS2_HB_NODE_UP_PRI); + /* Not exactly a heartbeat callback, but leads to essentially * the same path so we set it up here. */ dlm_setup_eviction_cb(&osb->osb_eviction_cb, @@ -104,6 +149,39 @@ void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb) osb); } +/* Most functions here are just stubs for now... */ +int ocfs2_register_hb_callbacks(struct ocfs2_super *osb) +{ + int status; + + if (ocfs2_mount_local(osb)) + return 0; + + status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_down); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_up); + if (status < 0) { + mlog_errno(status); + o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down); + } + +bail: + return status; +} + +void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb) +{ + if (ocfs2_mount_local(osb)) + return; + + o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down); + o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_up); +} + void ocfs2_stop_heartbeat(struct ocfs2_super *osb) { int ret; @@ -263,6 +341,8 @@ int ocfs2_recovery_map_set(struct ocfs2_super *osb, spin_lock(&osb->node_map_lock); + __ocfs2_node_map_clear_bit(&osb->mounted_map, num); + if (!test_bit(num, osb->recovery_map.map)) { __ocfs2_node_map_set_bit(&osb->recovery_map, num); set = 1; diff --git a/trunk/fs/ocfs2/heartbeat.h b/trunk/fs/ocfs2/heartbeat.h index 56859211888a..e8fb079122e4 100644 --- a/trunk/fs/ocfs2/heartbeat.h +++ b/trunk/fs/ocfs2/heartbeat.h @@ -29,6 +29,8 @@ void ocfs2_init_node_maps(struct ocfs2_super *osb); void ocfs2_setup_hb_callbacks(struct ocfs2_super *osb); +int ocfs2_register_hb_callbacks(struct ocfs2_super *osb); +void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb); void ocfs2_stop_heartbeat(struct ocfs2_super *osb); /* node map functions - used to keep track of mounted and in-recovery diff --git a/trunk/fs/ocfs2/inode.c b/trunk/fs/ocfs2/inode.c index 7e9e4c79aec7..ebb2bbe30f35 100644 --- a/trunk/fs/ocfs2/inode.c +++ b/trunk/fs/ocfs2/inode.c @@ -49,6 +49,7 @@ #include "symlink.h" #include "sysfile.h" #include "uptodate.h" +#include "vote.h" #include "buffer_head_io.h" @@ -57,11 +58,8 @@ struct ocfs2_find_inode_args u64 fi_blkno; unsigned long fi_ino; unsigned int fi_flags; - unsigned int fi_sysfile_type; }; -static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES]; - static int ocfs2_read_locked_inode(struct inode *inode, struct ocfs2_find_inode_args *args); static int ocfs2_init_locked_inode(struct inode *inode, void *opaque); @@ -109,8 +107,7 @@ void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi) oi->ip_attr |= OCFS2_DIRSYNC_FL; } -struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, - int sysfile_type) +struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags) { struct inode *inode = NULL; struct super_block *sb = osb->sb; @@ -130,7 +127,6 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, args.fi_blkno = blkno; args.fi_flags = flags; args.fi_ino = ino_from_blkno(sb, blkno); - args.fi_sysfile_type = sysfile_type; inode = iget5_locked(sb, args.fi_ino, ocfs2_find_actor, ocfs2_init_locked_inode, &args); @@ -205,9 +201,6 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) inode->i_ino = args->fi_ino; OCFS2_I(inode)->ip_blkno = args->fi_blkno; - if (args->fi_sysfile_type != 0) - lockdep_set_class(&inode->i_mutex, - &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); mlog_exit(0); return 0; @@ -329,7 +322,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, */ BUG_ON(le32_to_cpu(fe->i_flags) & OCFS2_SYSTEM_FL); - ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres, + ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres, OCFS2_LOCK_TYPE_META, 0, inode); ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_open_lockres, @@ -340,6 +333,10 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, OCFS2_LOCK_TYPE_RW, inode->i_generation, inode); + ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_data_lockres, + OCFS2_LOCK_TYPE_DATA, inode->i_generation, + inode); + ocfs2_set_inode_flags(inode); status = 0; @@ -417,7 +414,7 @@ static int ocfs2_read_locked_inode(struct inode *inode, if (args->fi_flags & OCFS2_FI_FLAG_SYSFILE) generation = osb->fs_generation; - ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_inode_lockres, + ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres, OCFS2_LOCK_TYPE_META, generation, inode); @@ -432,7 +429,7 @@ static int ocfs2_read_locked_inode(struct inode *inode, mlog_errno(status); return status; } - status = ocfs2_inode_lock(inode, NULL, 0); + status = ocfs2_meta_lock(inode, NULL, 0); if (status) { make_bad_inode(inode); mlog_errno(status); @@ -487,7 +484,7 @@ static int ocfs2_read_locked_inode(struct inode *inode, bail: if (can_lock) - ocfs2_inode_unlock(inode, 0); + ocfs2_meta_unlock(inode, 0); if (status < 0) make_bad_inode(inode); @@ -589,7 +586,7 @@ static int ocfs2_remove_inode(struct inode *inode, } mutex_lock(&inode_alloc_inode->i_mutex); - status = ocfs2_inode_lock(inode_alloc_inode, &inode_alloc_bh, 1); + status = ocfs2_meta_lock(inode_alloc_inode, &inode_alloc_bh, 1); if (status < 0) { mutex_unlock(&inode_alloc_inode->i_mutex); @@ -620,7 +617,7 @@ static int ocfs2_remove_inode(struct inode *inode, } di->i_dtime = cpu_to_le64(CURRENT_TIME.tv_sec); - di->i_flags &= cpu_to_le32(~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL)); + le32_and_cpu(&di->i_flags, ~(OCFS2_VALID_FL | OCFS2_ORPHANED_FL)); status = ocfs2_journal_dirty(handle, di_bh); if (status < 0) { @@ -638,7 +635,7 @@ static int ocfs2_remove_inode(struct inode *inode, bail_commit: ocfs2_commit_trans(osb, handle); bail_unlock: - ocfs2_inode_unlock(inode_alloc_inode, 1); + ocfs2_meta_unlock(inode_alloc_inode, 1); mutex_unlock(&inode_alloc_inode->i_mutex); brelse(inode_alloc_bh); bail: @@ -712,7 +709,7 @@ static int ocfs2_wipe_inode(struct inode *inode, * delete_inode operation. We do this now to avoid races with * recovery completion on other nodes. */ mutex_lock(&orphan_dir_inode->i_mutex); - status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); + status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1); if (status < 0) { mutex_unlock(&orphan_dir_inode->i_mutex); @@ -721,8 +718,8 @@ static int ocfs2_wipe_inode(struct inode *inode, } /* we do this while holding the orphan dir lock because we - * don't want recovery being run from another node to try an - * inode delete underneath us -- this will result in two nodes + * don't want recovery being run from another node to vote for + * an inode delete on us -- this will result in two nodes * truncating the same file! */ status = ocfs2_truncate_for_delete(osb, inode, di_bh); if (status < 0) { @@ -736,7 +733,7 @@ static int ocfs2_wipe_inode(struct inode *inode, mlog_errno(status); bail_unlock_dir: - ocfs2_inode_unlock(orphan_dir_inode, 1); + ocfs2_meta_unlock(orphan_dir_inode, 1); mutex_unlock(&orphan_dir_inode->i_mutex); brelse(orphan_dir_bh); bail: @@ -747,7 +744,7 @@ static int ocfs2_wipe_inode(struct inode *inode, } /* There is a series of simple checks that should be done before a - * trylock is even considered. Encapsulate those in this function. */ + * vote is even considered. Encapsulate those in this function. */ static int ocfs2_inode_is_valid_to_delete(struct inode *inode) { int ret = 0; @@ -761,14 +758,14 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode) goto bail; } - /* If we're coming from downconvert_thread we can't go into our own + /* If we're coming from process_vote we can't go into our own * voting [hello, deadlock city!], so unforuntately we just * have to skip deleting this guy. That's OK though because * the node who's doing the actual deleting should handle it * anyway. */ - if (current == osb->dc_task) { + if (current == osb->vote_task) { mlog(0, "Skipping delete of %lu because we're currently " - "in downconvert\n", inode->i_ino); + "in process_vote\n", inode->i_ino); goto bail; } @@ -782,9 +779,10 @@ static int ocfs2_inode_is_valid_to_delete(struct inode *inode) goto bail_unlock; } - /* If we have allowd wipe of this inode for another node, it - * will be marked here so we can safely skip it. Recovery will - * cleanup any inodes we might inadvertantly skip here. */ + /* If we have voted "yes" on the wipe of this inode for + * another node, it will be marked here so we can safely skip + * it. Recovery will cleanup any inodes we might inadvertantly + * skip here. */ if (oi->ip_flags & OCFS2_INODE_SKIP_DELETE) { mlog(0, "Skipping delete of %lu because another node " "has done this for us.\n", inode->i_ino); @@ -931,13 +929,13 @@ void ocfs2_delete_inode(struct inode *inode) /* Lock down the inode. This gives us an up to date view of * it's metadata (for verification), and allows us to - * serialize delete_inode on multiple nodes. + * serialize delete_inode votes. * * Even though we might be doing a truncate, we don't take the * allocation lock here as it won't be needed - nobody will * have the file open. */ - status = ocfs2_inode_lock(inode, &di_bh, 1); + status = ocfs2_meta_lock(inode, &di_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -949,15 +947,15 @@ void ocfs2_delete_inode(struct inode *inode) * before we go ahead and wipe the inode. */ status = ocfs2_query_inode_wipe(inode, di_bh, &wipe); if (!wipe || status < 0) { - /* Error and remote inode busy both mean we won't be + /* Error and inode busy vote both mean we won't be * removing the inode, so they take almost the same * path. */ if (status < 0) mlog_errno(status); - /* Someone in the cluster has disallowed a wipe of - * this inode, or it was never completely - * orphaned. Write out the pages and exit now. */ + /* Someone in the cluster has voted to not wipe this + * inode, or it was never completely orphaned. Write + * out the pages and exit now. */ ocfs2_cleanup_delete_inode(inode, 1); goto bail_unlock_inode; } @@ -983,7 +981,7 @@ void ocfs2_delete_inode(struct inode *inode) OCFS2_I(inode)->ip_flags |= OCFS2_INODE_DELETED; bail_unlock_inode: - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); brelse(di_bh); bail_unblock: status = sigprocmask(SIG_SETMASK, &oldset, NULL); @@ -1010,14 +1008,15 @@ void ocfs2_clear_inode(struct inode *inode) mlog_bug_on_msg(OCFS2_SB(inode->i_sb) == NULL, "Inode=%lu\n", inode->i_ino); - /* To preven remote deletes we hold open lock before, now it - * is time to unlock PR and EX open locks. */ + /* For remove delete_inode vote, we hold open lock before, + * now it is time to unlock PR and EX open locks. */ ocfs2_open_unlock(inode); /* Do these before all the other work so that we don't bounce - * the downconvert thread while waiting to destroy the locks. */ + * the vote thread while waiting to destroy the locks. */ ocfs2_mark_lockres_freeing(&oi->ip_rw_lockres); - ocfs2_mark_lockres_freeing(&oi->ip_inode_lockres); + ocfs2_mark_lockres_freeing(&oi->ip_meta_lockres); + ocfs2_mark_lockres_freeing(&oi->ip_data_lockres); ocfs2_mark_lockres_freeing(&oi->ip_open_lockres); /* We very well may get a clear_inode before all an inodes @@ -1040,7 +1039,8 @@ void ocfs2_clear_inode(struct inode *inode) mlog_errno(status); ocfs2_lock_res_free(&oi->ip_rw_lockres); - ocfs2_lock_res_free(&oi->ip_inode_lockres); + ocfs2_lock_res_free(&oi->ip_meta_lockres); + ocfs2_lock_res_free(&oi->ip_data_lockres); ocfs2_lock_res_free(&oi->ip_open_lockres); ocfs2_metadata_cache_purge(inode); @@ -1184,15 +1184,15 @@ int ocfs2_inode_revalidate(struct dentry *dentry) } spin_unlock(&OCFS2_I(inode)->ip_lock); - /* Let ocfs2_inode_lock do the work of updating our struct + /* Let ocfs2_meta_lock do the work of updating our struct * inode for us. */ - status = ocfs2_inode_lock(inode, NULL, 0); + status = ocfs2_meta_lock(inode, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto bail; } - ocfs2_inode_unlock(inode, 0); + ocfs2_meta_unlock(inode, 0); bail: mlog_exit(status); diff --git a/trunk/fs/ocfs2/inode.h b/trunk/fs/ocfs2/inode.h index 390a85596aa0..70e881c55536 100644 --- a/trunk/fs/ocfs2/inode.h +++ b/trunk/fs/ocfs2/inode.h @@ -34,7 +34,8 @@ struct ocfs2_inode_info u64 ip_blkno; struct ocfs2_lock_res ip_rw_lockres; - struct ocfs2_lock_res ip_inode_lockres; + struct ocfs2_lock_res ip_meta_lockres; + struct ocfs2_lock_res ip_data_lockres; struct ocfs2_lock_res ip_open_lockres; /* protects allocation changes on this inode. */ @@ -120,10 +121,9 @@ void ocfs2_delete_inode(struct inode *inode); void ocfs2_drop_inode(struct inode *inode); /* Flags for ocfs2_iget() */ -#define OCFS2_FI_FLAG_SYSFILE 0x1 -#define OCFS2_FI_FLAG_ORPHAN_RECOVERY 0x2 -struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags, - int sysfile_type); +#define OCFS2_FI_FLAG_SYSFILE 0x4 +#define OCFS2_FI_FLAG_ORPHAN_RECOVERY 0x8 +struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, int flags); int ocfs2_inode_init_private(struct inode *inode); int ocfs2_inode_revalidate(struct dentry *dentry); int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, diff --git a/trunk/fs/ocfs2/ioctl.c b/trunk/fs/ocfs2/ioctl.c index 5177fba5162b..87dcece7e1b5 100644 --- a/trunk/fs/ocfs2/ioctl.c +++ b/trunk/fs/ocfs2/ioctl.c @@ -20,7 +20,6 @@ #include "ocfs2_fs.h" #include "ioctl.h" -#include "resize.h" #include @@ -28,14 +27,14 @@ static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags) { int status; - status = ocfs2_inode_lock(inode, NULL, 0); + status = ocfs2_meta_lock(inode, NULL, 0); if (status < 0) { mlog_errno(status); return status; } ocfs2_get_inode_flags(OCFS2_I(inode)); *flags = OCFS2_I(inode)->ip_attr; - ocfs2_inode_unlock(inode, 0); + ocfs2_meta_unlock(inode, 0); mlog_exit(status); return status; @@ -53,7 +52,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, mutex_lock(&inode->i_mutex); - status = ocfs2_inode_lock(inode, &bh, 1); + status = ocfs2_meta_lock(inode, &bh, 1); if (status < 0) { mlog_errno(status); goto bail; @@ -101,7 +100,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, ocfs2_commit_trans(osb, handle); bail_unlock: - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); bail: mutex_unlock(&inode->i_mutex); @@ -116,10 +115,8 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { unsigned int flags; - int new_clusters; int status; struct ocfs2_space_resv sr; - struct ocfs2_new_group_input input; switch (cmd) { case OCFS2_IOC_GETFLAGS: @@ -143,23 +140,6 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp, return -EFAULT; return ocfs2_change_file_space(filp, cmd, &sr); - case OCFS2_IOC_GROUP_EXTEND: - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - if (get_user(new_clusters, (int __user *)arg)) - return -EFAULT; - - return ocfs2_group_extend(inode, new_clusters); - case OCFS2_IOC_GROUP_ADD: - case OCFS2_IOC_GROUP_ADD64: - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - if (copy_from_user(&input, (int __user *) arg, sizeof(input))) - return -EFAULT; - - return ocfs2_group_add(inode, &input); default: return -ENOTTY; } @@ -182,9 +162,6 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) case OCFS2_IOC_RESVSP64: case OCFS2_IOC_UNRESVSP: case OCFS2_IOC_UNRESVSP64: - case OCFS2_IOC_GROUP_EXTEND: - case OCFS2_IOC_GROUP_ADD: - case OCFS2_IOC_GROUP_ADD64: break; default: return -ENOIOCTLCMD; diff --git a/trunk/fs/ocfs2/journal.c b/trunk/fs/ocfs2/journal.c index f31c7e8c19c3..8d81f6c1b877 100644 --- a/trunk/fs/ocfs2/journal.c +++ b/trunk/fs/ocfs2/journal.c @@ -44,6 +44,7 @@ #include "localalloc.h" #include "slot_map.h" #include "super.h" +#include "vote.h" #include "sysfile.h" #include "buffer_head_io.h" @@ -102,7 +103,7 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb) mlog(0, "commit_thread: flushed transaction %lu (%u handles)\n", journal->j_trans_id, flushed); - ocfs2_wake_downconvert_thread(osb); + ocfs2_kick_vote_thread(osb); wake_up(&journal->j_checkpointed); finally: mlog_exit(status); @@ -313,18 +314,14 @@ int ocfs2_journal_dirty_data(handle_t *handle, return err; } -#define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * JBD_DEFAULT_MAX_COMMIT_AGE) +#define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * 5) void ocfs2_set_journal_params(struct ocfs2_super *osb) { journal_t *journal = osb->journal->j_journal; - unsigned long commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL; - - if (osb->osb_commit_interval) - commit_interval = osb->osb_commit_interval; spin_lock(&journal->j_state_lock); - journal->j_commit_interval = commit_interval; + journal->j_commit_interval = OCFS2_DEFAULT_COMMIT_INTERVAL; if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER) journal->j_flags |= JFS_BARRIER; else @@ -340,7 +337,7 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty) struct ocfs2_dinode *di = NULL; struct buffer_head *bh = NULL; struct ocfs2_super *osb; - int inode_lock = 0; + int meta_lock = 0; mlog_entry_void(); @@ -370,14 +367,14 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty) /* Skip recovery waits here - journal inode metadata never * changes in a live cluster so it can be considered an * exception to the rule. */ - status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); + status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); if (status < 0) { if (status != -ERESTARTSYS) mlog(ML_ERROR, "Could not get lock on journal!\n"); goto done; } - inode_lock = 1; + meta_lock = 1; di = (struct ocfs2_dinode *)bh->b_data; if (inode->i_size < OCFS2_MIN_JOURNAL_SIZE) { @@ -417,8 +414,8 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty) status = 0; done: if (status < 0) { - if (inode_lock) - ocfs2_inode_unlock(inode, 1); + if (meta_lock) + ocfs2_meta_unlock(inode, 1); if (bh != NULL) brelse(bh); if (inode) { @@ -547,7 +544,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb) OCFS2_I(inode)->ip_open_count--; /* unlock our journal */ - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); brelse(journal->j_bh); journal->j_bh = NULL; @@ -886,8 +883,8 @@ static int __ocfs2_recovery_thread(void *arg) ocfs2_super_unlock(osb, 1); /* We always run recovery on our own orphan dir - the dead - * node(s) may have disallowd a previos inode delete. Re-processing - * is therefore required. */ + * node(s) may have voted "no" on an inode delete earlier. A + * revote is therefore required. */ ocfs2_queue_recovery_completion(osb->journal, osb->slot_num, NULL, NULL); @@ -976,9 +973,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb, } SET_INODE_JOURNAL(inode); - status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); + status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); if (status < 0) { - mlog(0, "status returned from ocfs2_inode_lock=%d\n", status); + mlog(0, "status returned from ocfs2_meta_lock=%d\n", status); if (status != -ERESTARTSYS) mlog(ML_ERROR, "Could not lock journal!\n"); goto done; @@ -1050,7 +1047,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb, done: /* drop the lock on this nodes journal */ if (got_lock) - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); if (inode) iput(inode); @@ -1165,14 +1162,14 @@ static int ocfs2_trylock_journal(struct ocfs2_super *osb, SET_INODE_JOURNAL(inode); flags = OCFS2_META_LOCK_RECOVERY | OCFS2_META_LOCK_NOQUEUE; - status = ocfs2_inode_lock_full(inode, NULL, 1, flags); + status = ocfs2_meta_lock_full(inode, NULL, 1, flags); if (status < 0) { if (status != -EAGAIN) mlog_errno(status); goto bail; } - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); bail: if (inode) iput(inode); @@ -1244,7 +1241,7 @@ static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len, /* Skip bad inodes so that recovery can continue */ iter = ocfs2_iget(p->osb, ino, - OCFS2_FI_FLAG_ORPHAN_RECOVERY, 0); + OCFS2_FI_FLAG_ORPHAN_RECOVERY); if (IS_ERR(iter)) return 0; @@ -1280,7 +1277,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb, } mutex_lock(&orphan_dir_inode->i_mutex); - status = ocfs2_inode_lock(orphan_dir_inode, NULL, 0); + status = ocfs2_meta_lock(orphan_dir_inode, NULL, 0); if (status < 0) { mlog_errno(status); goto out; @@ -1296,7 +1293,7 @@ static int ocfs2_queue_orphans(struct ocfs2_super *osb, *head = priv.head; out_cluster: - ocfs2_inode_unlock(orphan_dir_inode, 0); + ocfs2_meta_unlock(orphan_dir_inode, 0); out: mutex_unlock(&orphan_dir_inode->i_mutex); iput(orphan_dir_inode); @@ -1383,10 +1380,10 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, iter = oi->ip_next_orphan; spin_lock(&oi->ip_lock); - /* The remote delete code may have set these on the - * assumption that the other node would wipe them - * successfully. If they are still in the node's - * orphan dir, we need to reset that state. */ + /* Delete voting may have set these on the assumption + * that the other node would wipe them successfully. + * If they are still in the node's orphan dir, we need + * to reset that state. */ oi->ip_flags &= ~(OCFS2_INODE_DELETED|OCFS2_INODE_SKIP_DELETE); /* Set the proper information to get us going into diff --git a/trunk/fs/ocfs2/journal.h b/trunk/fs/ocfs2/journal.h index 220f3e818e78..4b32e0961568 100644 --- a/trunk/fs/ocfs2/journal.h +++ b/trunk/fs/ocfs2/journal.h @@ -278,12 +278,6 @@ int ocfs2_journal_dirty_data(handle_t *handle, /* simple file updates like chmod, etc. */ #define OCFS2_INODE_UPDATE_CREDITS 1 -/* group extend. inode update and last group update. */ -#define OCFS2_GROUP_EXTEND_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) - -/* group add. inode update and the new group update. */ -#define OCFS2_GROUP_ADD_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1) - /* get one bit out of a suballocator: dinode + group descriptor + * prev. group desc. if we relink. */ #define OCFS2_SUBALLOC_ALLOC (3) diff --git a/trunk/fs/ocfs2/localalloc.c b/trunk/fs/ocfs2/localalloc.c index add1ffdc5c6c..58ea88b5af36 100644 --- a/trunk/fs/ocfs2/localalloc.c +++ b/trunk/fs/ocfs2/localalloc.c @@ -75,12 +75,18 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, struct inode *local_alloc_inode); +/* + * Determine how large our local alloc window should be, in bits. + * + * These values (and the behavior in ocfs2_alloc_should_use_local) have + * been chosen so that most allocations, including new block groups go + * through local alloc. + */ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb) { - BUG_ON(osb->s_clustersize_bits > 20); + BUG_ON(osb->s_clustersize_bits < 12); - /* Size local alloc windows by the megabyte */ - return osb->local_alloc_size << (20 - osb->s_clustersize_bits); + return 2048 >> (osb->s_clustersize_bits - 12); } /* @@ -90,23 +96,18 @@ static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb) int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits) { int la_bits = ocfs2_local_alloc_window_bits(osb); - int ret = 0; if (osb->local_alloc_state != OCFS2_LA_ENABLED) - goto bail; + return 0; /* la_bits should be at least twice the size (in clusters) of * a new block group. We want to be sure block group * allocations go through the local alloc, so allow an * allocation to take up to half the bitmap. */ if (bits > (la_bits / 2)) - goto bail; + return 0; - ret = 1; -bail: - mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n", - osb->local_alloc_state, (unsigned long long)bits, la_bits, ret); - return ret; + return 1; } int ocfs2_load_local_alloc(struct ocfs2_super *osb) @@ -120,19 +121,6 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) mlog_entry_void(); - if (ocfs2_mount_local(osb)) - goto bail; - - if (osb->local_alloc_size == 0) - goto bail; - - if (ocfs2_local_alloc_window_bits(osb) >= osb->bitmap_cpg) { - mlog(ML_NOTICE, "Requested local alloc window %d is larger " - "than max possible %u. Using defaults.\n", - ocfs2_local_alloc_window_bits(osb), (osb->bitmap_cpg - 1)); - osb->local_alloc_size = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE; - } - /* read the alloc off disk */ inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE, osb->slot_num); @@ -193,9 +181,6 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb) if (inode) iput(inode); - mlog(0, "Local alloc window bits = %d\n", - ocfs2_local_alloc_window_bits(osb)); - mlog_exit(status); return status; } @@ -246,7 +231,7 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb) mutex_lock(&main_bm_inode->i_mutex); - status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1); + status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1); if (status < 0) { mlog_errno(status); goto out_mutex; @@ -301,7 +286,7 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb) if (main_bm_bh) brelse(main_bm_bh); - ocfs2_inode_unlock(main_bm_inode, 1); + ocfs2_meta_unlock(main_bm_inode, 1); out_mutex: mutex_unlock(&main_bm_inode->i_mutex); @@ -414,7 +399,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb, mutex_lock(&main_bm_inode->i_mutex); - status = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1); + status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1); if (status < 0) { mlog_errno(status); goto out_mutex; @@ -439,7 +424,7 @@ int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb, ocfs2_commit_trans(osb, handle); out_unlock: - ocfs2_inode_unlock(main_bm_inode, 1); + ocfs2_meta_unlock(main_bm_inode, 1); out_mutex: mutex_unlock(&main_bm_inode->i_mutex); @@ -536,9 +521,6 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, iput(local_alloc_inode); } - mlog(0, "bits=%d, slot=%d, ret=%d\n", bits_wanted, osb->slot_num, - status); - mlog_exit(status); return status; } diff --git a/trunk/fs/ocfs2/locks.c b/trunk/fs/ocfs2/locks.c deleted file mode 100644 index 203f87143877..000000000000 --- a/trunk/fs/ocfs2/locks.c +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; -*- - * vim: noexpandtab sw=8 ts=8 sts=0: - * - * locks.c - * - * Userspace file locking support - * - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include - -#define MLOG_MASK_PREFIX ML_INODE -#include - -#include "ocfs2.h" - -#include "dlmglue.h" -#include "file.h" -#include "locks.h" - -static int ocfs2_do_flock(struct file *file, struct inode *inode, - int cmd, struct file_lock *fl) -{ - int ret = 0, level = 0, trylock = 0; - struct ocfs2_file_private *fp = file->private_data; - struct ocfs2_lock_res *lockres = &fp->fp_flock; - - if (fl->fl_type == F_WRLCK) - level = 1; - if (!IS_SETLKW(cmd)) - trylock = 1; - - mutex_lock(&fp->fp_mutex); - - if (lockres->l_flags & OCFS2_LOCK_ATTACHED && - lockres->l_level > LKM_NLMODE) { - int old_level = 0; - - if (lockres->l_level == LKM_EXMODE) - old_level = 1; - - if (level == old_level) - goto out; - - /* - * Converting an existing lock is not guaranteed to be - * atomic, so we can get away with simply unlocking - * here and allowing the lock code to try at the new - * level. - */ - - flock_lock_file_wait(file, - &(struct file_lock){.fl_type = F_UNLCK}); - - ocfs2_file_unlock(file); - } - - ret = ocfs2_file_lock(file, level, trylock); - if (ret) { - if (ret == -EAGAIN && trylock) - ret = -EWOULDBLOCK; - else - mlog_errno(ret); - goto out; - } - - ret = flock_lock_file_wait(file, fl); - -out: - mutex_unlock(&fp->fp_mutex); - - return ret; -} - -static int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl) -{ - int ret; - struct ocfs2_file_private *fp = file->private_data; - - mutex_lock(&fp->fp_mutex); - ocfs2_file_unlock(file); - ret = flock_lock_file_wait(file, fl); - mutex_unlock(&fp->fp_mutex); - - return ret; -} - -/* - * Overall flow of ocfs2_flock() was influenced by gfs2_flock(). - */ -int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl) -{ - struct inode *inode = file->f_mapping->host; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - - if (!(fl->fl_flags & FL_FLOCK)) - return -ENOLCK; - if (__mandatory_lock(inode)) - return -ENOLCK; - - if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) || - ocfs2_mount_local(osb)) - return flock_lock_file_wait(file, fl); - - if (fl->fl_type == F_UNLCK) - return ocfs2_do_funlock(file, cmd, fl); - else - return ocfs2_do_flock(file, inode, cmd, fl); -} diff --git a/trunk/fs/ocfs2/mmap.c b/trunk/fs/ocfs2/mmap.c index 3dc18d67557c..98756156d298 100644 --- a/trunk/fs/ocfs2/mmap.c +++ b/trunk/fs/ocfs2/mmap.c @@ -168,7 +168,7 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) * node. Taking the data lock will also ensure that we don't * attempt page truncation as part of a downconvert. */ - ret = ocfs2_inode_lock(inode, &di_bh, 1); + ret = ocfs2_meta_lock(inode, &di_bh, 1); if (ret < 0) { mlog_errno(ret); goto out; @@ -181,12 +181,21 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page) */ down_write(&OCFS2_I(inode)->ip_alloc_sem); + ret = ocfs2_data_lock(inode, 1); + if (ret < 0) { + mlog_errno(ret); + goto out_meta_unlock; + } + ret = __ocfs2_page_mkwrite(inode, di_bh, page); + ocfs2_data_unlock(inode, 1); + +out_meta_unlock: up_write(&OCFS2_I(inode)->ip_alloc_sem); brelse(di_bh); - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); out: ret2 = ocfs2_vm_op_unblock_sigs(&oldset); @@ -205,13 +214,13 @@ int ocfs2_mmap(struct file *file, struct vm_area_struct *vma) { int ret = 0, lock_level = 0; - ret = ocfs2_inode_lock_atime(file->f_dentry->d_inode, + ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode, file->f_vfsmnt, &lock_level); if (ret < 0) { mlog_errno(ret); goto out; } - ocfs2_inode_unlock(file->f_dentry->d_inode, lock_level); + ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level); out: vma->vm_ops = &ocfs2_file_vm_ops; vma->vm_flags |= VM_CAN_NONLINEAR; diff --git a/trunk/fs/ocfs2/namei.c b/trunk/fs/ocfs2/namei.c index ae9ad9587516..989ac2718587 100644 --- a/trunk/fs/ocfs2/namei.c +++ b/trunk/fs/ocfs2/namei.c @@ -60,6 +60,7 @@ #include "symlink.h" #include "sysfile.h" #include "uptodate.h" +#include "vote.h" #include "buffer_head_io.h" @@ -115,7 +116,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); - status = ocfs2_inode_lock(dir, NULL, 0); + status = ocfs2_meta_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -128,7 +129,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, if (status < 0) goto bail_add; - inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0); + inode = ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0); if (IS_ERR(inode)) { ret = ERR_PTR(-EACCES); goto bail_unlock; @@ -175,8 +176,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, /* Don't drop the cluster lock until *after* the d_add -- * unlink on another node will message us to remove that * dentry under this lock so otherwise we can race this with - * the downconvert thread and have a stale dentry. */ - ocfs2_inode_unlock(dir, 0); + * the vote thread and have a stale dentry. */ + ocfs2_meta_unlock(dir, 0); bail: @@ -208,7 +209,7 @@ static int ocfs2_mknod(struct inode *dir, /* get our super block */ osb = OCFS2_SB(dir->i_sb); - status = ocfs2_inode_lock(dir, &parent_fe_bh, 1); + status = ocfs2_meta_lock(dir, &parent_fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -322,7 +323,7 @@ static int ocfs2_mknod(struct inode *dir, if (handle) ocfs2_commit_trans(osb, handle); - ocfs2_inode_unlock(dir, 1); + ocfs2_meta_unlock(dir, 1); if (status == -ENOSPC) mlog(0, "Disk is full\n"); @@ -552,7 +553,7 @@ static int ocfs2_link(struct dentry *old_dentry, if (S_ISDIR(inode->i_mode)) return -EPERM; - err = ocfs2_inode_lock(dir, &parent_fe_bh, 1); + err = ocfs2_meta_lock(dir, &parent_fe_bh, 1); if (err < 0) { if (err != -ENOENT) mlog_errno(err); @@ -577,7 +578,7 @@ static int ocfs2_link(struct dentry *old_dentry, goto out; } - err = ocfs2_inode_lock(inode, &fe_bh, 1); + err = ocfs2_meta_lock(inode, &fe_bh, 1); if (err < 0) { if (err != -ENOENT) mlog_errno(err); @@ -642,10 +643,10 @@ static int ocfs2_link(struct dentry *old_dentry, out_commit: ocfs2_commit_trans(osb, handle); out_unlock_inode: - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); out: - ocfs2_inode_unlock(dir, 1); + ocfs2_meta_unlock(dir, 1); if (de_bh) brelse(de_bh); @@ -719,7 +720,7 @@ static int ocfs2_unlink(struct inode *dir, return -EPERM; } - status = ocfs2_inode_lock(dir, &parent_node_bh, 1); + status = ocfs2_meta_lock(dir, &parent_node_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -744,7 +745,7 @@ static int ocfs2_unlink(struct inode *dir, goto leave; } - status = ocfs2_inode_lock(inode, &fe_bh, 1); + status = ocfs2_meta_lock(inode, &fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -764,7 +765,7 @@ static int ocfs2_unlink(struct inode *dir, status = ocfs2_remote_dentry_delete(dentry); if (status < 0) { - /* This remote delete should succeed under all normal + /* This vote should succeed under all normal * circumstances. */ mlog_errno(status); goto leave; @@ -840,13 +841,13 @@ static int ocfs2_unlink(struct inode *dir, ocfs2_commit_trans(osb, handle); if (child_locked) - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); - ocfs2_inode_unlock(dir, 1); + ocfs2_meta_unlock(dir, 1); if (orphan_dir) { /* This was locked for us in ocfs2_prepare_orphan_dir() */ - ocfs2_inode_unlock(orphan_dir, 1); + ocfs2_meta_unlock(orphan_dir, 1); mutex_unlock(&orphan_dir->i_mutex); iput(orphan_dir); } @@ -907,7 +908,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, inode1 = tmpinode; } /* lock id2 */ - status = ocfs2_inode_lock(inode2, bh2, 1); + status = ocfs2_meta_lock(inode2, bh2, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -916,14 +917,14 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, } /* lock id1 */ - status = ocfs2_inode_lock(inode1, bh1, 1); + status = ocfs2_meta_lock(inode1, bh1, 1); if (status < 0) { /* * An error return must mean that no cluster locks * were held on function exit. */ if (oi1->ip_blkno != oi2->ip_blkno) - ocfs2_inode_unlock(inode2, 1); + ocfs2_meta_unlock(inode2, 1); if (status != -ENOENT) mlog_errno(status); @@ -936,10 +937,10 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2) { - ocfs2_inode_unlock(inode1, 1); + ocfs2_meta_unlock(inode1, 1); if (inode1 != inode2) - ocfs2_inode_unlock(inode2, 1); + ocfs2_meta_unlock(inode2, 1); } static int ocfs2_rename(struct inode *old_dir, @@ -1030,11 +1031,10 @@ static int ocfs2_rename(struct inode *old_dir, /* * Aside from allowing a meta data update, the locking here - * also ensures that the downconvert thread on other nodes - * won't have to concurrently downconvert the inode and the - * dentry locks. + * also ensures that the vote thread on other nodes won't have + * to concurrently downconvert the inode and the dentry locks. */ - status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1); + status = ocfs2_meta_lock(old_inode, &old_inode_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -1143,7 +1143,7 @@ static int ocfs2_rename(struct inode *old_dir, goto bail; } - status = ocfs2_inode_lock(new_inode, &newfe_bh, 1); + status = ocfs2_meta_lock(new_inode, &newfe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -1355,14 +1355,14 @@ static int ocfs2_rename(struct inode *old_dir, ocfs2_double_unlock(old_dir, new_dir); if (old_child_locked) - ocfs2_inode_unlock(old_inode, 1); + ocfs2_meta_unlock(old_inode, 1); if (new_child_locked) - ocfs2_inode_unlock(new_inode, 1); + ocfs2_meta_unlock(new_inode, 1); if (orphan_dir) { /* This was locked for us in ocfs2_prepare_orphan_dir() */ - ocfs2_inode_unlock(orphan_dir, 1); + ocfs2_meta_unlock(orphan_dir, 1); mutex_unlock(&orphan_dir->i_mutex); iput(orphan_dir); } @@ -1530,7 +1530,7 @@ static int ocfs2_symlink(struct inode *dir, credits = ocfs2_calc_symlink_credits(sb); /* lock the parent directory */ - status = ocfs2_inode_lock(dir, &parent_fe_bh, 1); + status = ocfs2_meta_lock(dir, &parent_fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -1657,7 +1657,7 @@ static int ocfs2_symlink(struct inode *dir, if (handle) ocfs2_commit_trans(osb, handle); - ocfs2_inode_unlock(dir, 1); + ocfs2_meta_unlock(dir, 1); if (new_fe_bh) brelse(new_fe_bh); @@ -1735,7 +1735,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, mutex_lock(&orphan_dir_inode->i_mutex); - status = ocfs2_inode_lock(orphan_dir_inode, &orphan_dir_bh, 1); + status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1); if (status < 0) { mlog_errno(status); goto leave; @@ -1745,7 +1745,7 @@ static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, orphan_dir_bh, name, OCFS2_ORPHAN_NAMELEN, de_bh); if (status < 0) { - ocfs2_inode_unlock(orphan_dir_inode, 1); + ocfs2_meta_unlock(orphan_dir_inode, 1); mlog_errno(status); goto leave; diff --git a/trunk/fs/ocfs2/ocfs2.h b/trunk/fs/ocfs2/ocfs2.h index d08480580470..60a23e1906b0 100644 --- a/trunk/fs/ocfs2/ocfs2.h +++ b/trunk/fs/ocfs2/ocfs2.h @@ -101,7 +101,6 @@ enum ocfs2_unlock_action { * about to be * dropped. */ #define OCFS2_LOCK_QUEUED (0x00000100) /* queued for downconvert */ -#define OCFS2_LOCK_NOCACHE (0x00000200) /* don't use a holder count */ struct ocfs2_lock_res_ops; @@ -171,7 +170,6 @@ enum ocfs2_mount_options OCFS2_MOUNT_NOINTR = 1 << 2, /* Don't catch signals */ OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */ OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */ - OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */ }; #define OCFS2_OSB_SOFT_RO 0x0001 @@ -191,7 +189,9 @@ struct ocfs2_super struct ocfs2_slot_info *slot_info; spinlock_t node_map_lock; + struct ocfs2_node_map mounted_map; struct ocfs2_node_map recovery_map; + struct ocfs2_node_map umount_map; u64 root_blkno; u64 system_dir_blkno; @@ -231,9 +231,7 @@ struct ocfs2_super wait_queue_head_t checkpoint_event; atomic_t needs_checkpoint; struct ocfs2_journal *journal; - unsigned long osb_commit_interval; - int local_alloc_size; enum ocfs2_local_alloc_state local_alloc_state; struct buffer_head *local_alloc_bh; u64 la_last_gd; @@ -256,21 +254,28 @@ struct ocfs2_super wait_queue_head_t recovery_event; - spinlock_t dc_task_lock; - struct task_struct *dc_task; - wait_queue_head_t dc_event; - unsigned long dc_wake_sequence; - unsigned long dc_work_sequence; + spinlock_t vote_task_lock; + struct task_struct *vote_task; + wait_queue_head_t vote_event; + unsigned long vote_wake_sequence; + unsigned long vote_work_sequence; - /* - * Any thread can add locks to the list, but the downconvert - * thread is the only one allowed to remove locks. Any change - * to this rule requires updating - * ocfs2_downconvert_thread_do_work(). - */ struct list_head blocked_lock_list; unsigned long blocked_lock_count; + struct list_head vote_list; + int vote_count; + + u32 net_key; + spinlock_t net_response_lock; + unsigned int net_response_ids; + struct list_head net_response_list; + + struct o2hb_callback_func osb_hb_up; + struct o2hb_callback_func osb_hb_down; + + struct list_head osb_net_handlers; + wait_queue_head_t osb_mount_event; /* Truncate log info */ diff --git a/trunk/fs/ocfs2/ocfs2_fs.h b/trunk/fs/ocfs2/ocfs2_fs.h index 3633edd3982f..6ef876759a73 100644 --- a/trunk/fs/ocfs2/ocfs2_fs.h +++ b/trunk/fs/ocfs2/ocfs2_fs.h @@ -231,20 +231,6 @@ struct ocfs2_space_resv { #define OCFS2_IOC_RESVSP64 _IOW ('X', 42, struct ocfs2_space_resv) #define OCFS2_IOC_UNRESVSP64 _IOW ('X', 43, struct ocfs2_space_resv) -/* Used to pass group descriptor data when online resize is done */ -struct ocfs2_new_group_input { - __u64 group; /* Group descriptor's blkno. */ - __u32 clusters; /* Total number of clusters in this group */ - __u32 frees; /* Total free clusters in this group */ - __u16 chain; /* Chain for this group */ - __u16 reserved1; - __u32 reserved2; -}; - -#define OCFS2_IOC_GROUP_EXTEND _IOW('o', 1, int) -#define OCFS2_IOC_GROUP_ADD _IOW('o', 2,struct ocfs2_new_group_input) -#define OCFS2_IOC_GROUP_ADD64 _IOW('o', 3,struct ocfs2_new_group_input) - /* * Journal Flags (ocfs2_dinode.id1.journal1.i_flags) */ @@ -270,14 +256,6 @@ struct ocfs2_new_group_input { /* Journal limits (in bytes) */ #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024) -/* - * Default local alloc size (in megabytes) - * - * The value chosen should be such that most allocations, including new - * block groups, use local alloc. - */ -#define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8 - struct ocfs2_system_inode_info { char *si_name; int si_iflags; diff --git a/trunk/fs/ocfs2/ocfs2_lockid.h b/trunk/fs/ocfs2/ocfs2_lockid.h index 86f3e3799c2b..4ca02b1c38ac 100644 --- a/trunk/fs/ocfs2/ocfs2_lockid.h +++ b/trunk/fs/ocfs2/ocfs2_lockid.h @@ -45,7 +45,6 @@ enum ocfs2_lock_type { OCFS2_LOCK_TYPE_RW, OCFS2_LOCK_TYPE_DENTRY, OCFS2_LOCK_TYPE_OPEN, - OCFS2_LOCK_TYPE_FLOCK, OCFS2_NUM_LOCK_TYPES }; @@ -74,9 +73,6 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type) case OCFS2_LOCK_TYPE_OPEN: c = 'O'; break; - case OCFS2_LOCK_TYPE_FLOCK: - c = 'F'; - break; default: c = '\0'; } @@ -94,7 +90,6 @@ static char *ocfs2_lock_type_strings[] = { [OCFS2_LOCK_TYPE_RW] = "Write/Read", [OCFS2_LOCK_TYPE_DENTRY] = "Dentry", [OCFS2_LOCK_TYPE_OPEN] = "Open", - [OCFS2_LOCK_TYPE_FLOCK] = "Flock", }; static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) diff --git a/trunk/fs/ocfs2/resize.c b/trunk/fs/ocfs2/resize.c deleted file mode 100644 index 37835ffcb039..000000000000 --- a/trunk/fs/ocfs2/resize.c +++ /dev/null @@ -1,634 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; -*- - * vim: noexpandtab sw=8 ts=8 sts=0: - * - * resize.c - * - * volume resize. - * Inspired by ext3/resize.c. - * - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include - -#define MLOG_MASK_PREFIX ML_DISK_ALLOC -#include - -#include "ocfs2.h" - -#include "alloc.h" -#include "dlmglue.h" -#include "inode.h" -#include "journal.h" -#include "super.h" -#include "sysfile.h" -#include "uptodate.h" - -#include "buffer_head_io.h" -#include "suballoc.h" -#include "resize.h" - -/* - * Check whether there are new backup superblocks exist - * in the last group. If there are some, mark them or clear - * them in the bitmap. - * - * Return how many backups we find in the last group. - */ -static u16 ocfs2_calc_new_backup_super(struct inode *inode, - struct ocfs2_group_desc *gd, - int new_clusters, - u32 first_new_cluster, - u16 cl_cpg, - int set) -{ - int i; - u16 backups = 0; - u32 cluster; - u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno); - - for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) { - blkno = ocfs2_backup_super_blkno(inode->i_sb, i); - cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno); - - gd_blkno = ocfs2_which_cluster_group(inode, cluster); - if (gd_blkno < lgd_blkno) - continue; - else if (gd_blkno > lgd_blkno) - break; - - if (set) - ocfs2_set_bit(cluster % cl_cpg, - (unsigned long *)gd->bg_bitmap); - else - ocfs2_clear_bit(cluster % cl_cpg, - (unsigned long *)gd->bg_bitmap); - backups++; - } - - mlog_exit_void(); - return backups; -} - -static int ocfs2_update_last_group_and_inode(handle_t *handle, - struct inode *bm_inode, - struct buffer_head *bm_bh, - struct buffer_head *group_bh, - u32 first_new_cluster, - int new_clusters) -{ - int ret = 0; - struct ocfs2_super *osb = OCFS2_SB(bm_inode->i_sb); - struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bm_bh->b_data; - struct ocfs2_chain_list *cl = &fe->id2.i_chain; - struct ocfs2_chain_rec *cr; - struct ocfs2_group_desc *group; - u16 chain, num_bits, backups = 0; - u16 cl_bpc = le16_to_cpu(cl->cl_bpc); - u16 cl_cpg = le16_to_cpu(cl->cl_cpg); - - mlog_entry("(new_clusters=%d, first_new_cluster = %u)\n", - new_clusters, first_new_cluster); - - ret = ocfs2_journal_access(handle, bm_inode, group_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (ret < 0) { - mlog_errno(ret); - goto out; - } - - group = (struct ocfs2_group_desc *)group_bh->b_data; - - /* update the group first. */ - num_bits = new_clusters * cl_bpc; - le16_add_cpu(&group->bg_bits, num_bits); - le16_add_cpu(&group->bg_free_bits_count, num_bits); - - /* - * check whether there are some new backup superblocks exist in - * this group and update the group bitmap accordingly. - */ - if (OCFS2_HAS_COMPAT_FEATURE(osb->sb, - OCFS2_FEATURE_COMPAT_BACKUP_SB)) { - backups = ocfs2_calc_new_backup_super(bm_inode, - group, - new_clusters, - first_new_cluster, - cl_cpg, 1); - le16_add_cpu(&group->bg_free_bits_count, -1 * backups); - } - - ret = ocfs2_journal_dirty(handle, group_bh); - if (ret < 0) { - mlog_errno(ret); - goto out_rollback; - } - - /* update the inode accordingly. */ - ret = ocfs2_journal_access(handle, bm_inode, bm_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (ret < 0) { - mlog_errno(ret); - goto out_rollback; - } - - chain = le16_to_cpu(group->bg_chain); - cr = (&cl->cl_recs[chain]); - le32_add_cpu(&cr->c_total, num_bits); - le32_add_cpu(&cr->c_free, num_bits); - le32_add_cpu(&fe->id1.bitmap1.i_total, num_bits); - le32_add_cpu(&fe->i_clusters, new_clusters); - - if (backups) { - le32_add_cpu(&cr->c_free, -1 * backups); - le32_add_cpu(&fe->id1.bitmap1.i_used, backups); - } - - spin_lock(&OCFS2_I(bm_inode)->ip_lock); - OCFS2_I(bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters); - le64_add_cpu(&fe->i_size, new_clusters << osb->s_clustersize_bits); - spin_unlock(&OCFS2_I(bm_inode)->ip_lock); - i_size_write(bm_inode, le64_to_cpu(fe->i_size)); - - ocfs2_journal_dirty(handle, bm_bh); - -out_rollback: - if (ret < 0) { - ocfs2_calc_new_backup_super(bm_inode, - group, - new_clusters, - first_new_cluster, - cl_cpg, 0); - le16_add_cpu(&group->bg_free_bits_count, backups); - le16_add_cpu(&group->bg_bits, -1 * num_bits); - le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits); - } -out: - mlog_exit(ret); - return ret; -} - -static int update_backups(struct inode * inode, u32 clusters, char *data) -{ - int i, ret = 0; - u32 cluster; - u64 blkno; - struct buffer_head *backup = NULL; - struct ocfs2_dinode *backup_di = NULL; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - - /* calculate the real backups we need to update. */ - for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) { - blkno = ocfs2_backup_super_blkno(inode->i_sb, i); - cluster = ocfs2_blocks_to_clusters(inode->i_sb, blkno); - if (cluster > clusters) - break; - - ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL); - if (ret < 0) { - mlog_errno(ret); - break; - } - - memcpy(backup->b_data, data, inode->i_sb->s_blocksize); - - backup_di = (struct ocfs2_dinode *)backup->b_data; - backup_di->i_blkno = cpu_to_le64(blkno); - - ret = ocfs2_write_super_or_backup(osb, backup); - brelse(backup); - backup = NULL; - if (ret < 0) { - mlog_errno(ret); - break; - } - } - - return ret; -} - -static void ocfs2_update_super_and_backups(struct inode *inode, - int new_clusters) -{ - int ret; - u32 clusters = 0; - struct buffer_head *super_bh = NULL; - struct ocfs2_dinode *super_di = NULL; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - - /* - * update the superblock last. - * It doesn't matter if the write failed. - */ - ret = ocfs2_read_block(osb, OCFS2_SUPER_BLOCK_BLKNO, - &super_bh, 0, NULL); - if (ret < 0) { - mlog_errno(ret); - goto out; - } - - super_di = (struct ocfs2_dinode *)super_bh->b_data; - le32_add_cpu(&super_di->i_clusters, new_clusters); - clusters = le32_to_cpu(super_di->i_clusters); - - ret = ocfs2_write_super_or_backup(osb, super_bh); - if (ret < 0) { - mlog_errno(ret); - goto out; - } - - if (OCFS2_HAS_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_COMPAT_BACKUP_SB)) - ret = update_backups(inode, clusters, super_bh->b_data); - -out: - brelse(super_bh); - if (ret) - printk(KERN_WARNING "ocfs2: Failed to update super blocks on %s" - " during fs resize. This condition is not fatal," - " but fsck.ocfs2 should be run to fix it\n", - osb->dev_str); - return; -} - -/* - * Extend the filesystem to the new number of clusters specified. This entry - * point is only used to extend the current filesystem to the end of the last - * existing group. - */ -int ocfs2_group_extend(struct inode * inode, int new_clusters) -{ - int ret; - handle_t *handle; - struct buffer_head *main_bm_bh = NULL; - struct buffer_head *group_bh = NULL; - struct inode *main_bm_inode = NULL; - struct ocfs2_dinode *fe = NULL; - struct ocfs2_group_desc *group = NULL; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - u16 cl_bpc; - u32 first_new_cluster; - u64 lgd_blkno; - - mlog_entry_void(); - - if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) - return -EROFS; - - if (new_clusters < 0) - return -EINVAL; - else if (new_clusters == 0) - return 0; - - main_bm_inode = ocfs2_get_system_file_inode(osb, - GLOBAL_BITMAP_SYSTEM_INODE, - OCFS2_INVALID_SLOT); - if (!main_bm_inode) { - ret = -EINVAL; - mlog_errno(ret); - goto out; - } - - mutex_lock(&main_bm_inode->i_mutex); - - ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1); - if (ret < 0) { - mlog_errno(ret); - goto out_mutex; - } - - fe = (struct ocfs2_dinode *)main_bm_bh->b_data; - - if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != - ocfs2_group_bitmap_size(osb->sb) * 8) { - mlog(ML_ERROR, "The disk is too old and small. " - "Force to do offline resize."); - ret = -EINVAL; - goto out_unlock; - } - - if (!OCFS2_IS_VALID_DINODE(fe)) { - OCFS2_RO_ON_INVALID_DINODE(main_bm_inode->i_sb, fe); - ret = -EIO; - goto out_unlock; - } - - first_new_cluster = le32_to_cpu(fe->i_clusters); - lgd_blkno = ocfs2_which_cluster_group(main_bm_inode, - first_new_cluster - 1); - - ret = ocfs2_read_block(osb, lgd_blkno, &group_bh, OCFS2_BH_CACHED, - main_bm_inode); - if (ret < 0) { - mlog_errno(ret); - goto out_unlock; - } - - group = (struct ocfs2_group_desc *)group_bh->b_data; - - ret = ocfs2_check_group_descriptor(inode->i_sb, fe, group); - if (ret) { - mlog_errno(ret); - goto out_unlock; - } - - cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); - if (le16_to_cpu(group->bg_bits) / cl_bpc + new_clusters > - le16_to_cpu(fe->id2.i_chain.cl_cpg)) { - ret = -EINVAL; - goto out_unlock; - } - - mlog(0, "extend the last group at %llu, new clusters = %d\n", - (unsigned long long)le64_to_cpu(group->bg_blkno), new_clusters); - - handle = ocfs2_start_trans(osb, OCFS2_GROUP_EXTEND_CREDITS); - if (IS_ERR(handle)) { - mlog_errno(PTR_ERR(handle)); - ret = -EINVAL; - goto out_unlock; - } - - /* update the last group descriptor and inode. */ - ret = ocfs2_update_last_group_and_inode(handle, main_bm_inode, - main_bm_bh, group_bh, - first_new_cluster, - new_clusters); - if (ret) { - mlog_errno(ret); - goto out_commit; - } - - ocfs2_update_super_and_backups(main_bm_inode, new_clusters); - -out_commit: - ocfs2_commit_trans(osb, handle); -out_unlock: - brelse(group_bh); - brelse(main_bm_bh); - - ocfs2_inode_unlock(main_bm_inode, 1); - -out_mutex: - mutex_unlock(&main_bm_inode->i_mutex); - iput(main_bm_inode); - -out: - mlog_exit_void(); - return ret; -} - -static int ocfs2_check_new_group(struct inode *inode, - struct ocfs2_dinode *di, - struct ocfs2_new_group_input *input, - struct buffer_head *group_bh) -{ - int ret; - struct ocfs2_group_desc *gd; - u16 cl_bpc = le16_to_cpu(di->id2.i_chain.cl_bpc); - unsigned int max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) * - le16_to_cpu(di->id2.i_chain.cl_bpc); - - - gd = (struct ocfs2_group_desc *)group_bh->b_data; - - ret = -EIO; - if (!OCFS2_IS_VALID_GROUP_DESC(gd)) - mlog(ML_ERROR, "Group descriptor # %llu isn't valid.\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno)); - else if (di->i_blkno != gd->bg_parent_dinode) - mlog(ML_ERROR, "Group descriptor # %llu has bad parent " - "pointer (%llu, expected %llu)\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno), - (unsigned long long)le64_to_cpu(gd->bg_parent_dinode), - (unsigned long long)le64_to_cpu(di->i_blkno)); - else if (le16_to_cpu(gd->bg_bits) > max_bits) - mlog(ML_ERROR, "Group descriptor # %llu has bit count of %u\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno), - le16_to_cpu(gd->bg_bits)); - else if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits)) - mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but " - "claims that %u are free\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno), - le16_to_cpu(gd->bg_bits), - le16_to_cpu(gd->bg_free_bits_count)); - else if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size))) - mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but " - "max bitmap bits of %u\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno), - le16_to_cpu(gd->bg_bits), - 8 * le16_to_cpu(gd->bg_size)); - else if (le16_to_cpu(gd->bg_chain) != input->chain) - mlog(ML_ERROR, "Group descriptor # %llu has bad chain %u " - "while input has %u set.\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno), - le16_to_cpu(gd->bg_chain), input->chain); - else if (le16_to_cpu(gd->bg_bits) != input->clusters * cl_bpc) - mlog(ML_ERROR, "Group descriptor # %llu has bit count %u but " - "input has %u clusters set\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno), - le16_to_cpu(gd->bg_bits), input->clusters); - else if (le16_to_cpu(gd->bg_free_bits_count) != input->frees * cl_bpc) - mlog(ML_ERROR, "Group descriptor # %llu has free bit count %u " - "but it should have %u set\n", - (unsigned long long)le64_to_cpu(gd->bg_blkno), - le16_to_cpu(gd->bg_bits), - input->frees * cl_bpc); - else - ret = 0; - - return ret; -} - -static int ocfs2_verify_group_and_input(struct inode *inode, - struct ocfs2_dinode *di, - struct ocfs2_new_group_input *input, - struct buffer_head *group_bh) -{ - u16 cl_count = le16_to_cpu(di->id2.i_chain.cl_count); - u16 cl_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg); - u16 next_free = le16_to_cpu(di->id2.i_chain.cl_next_free_rec); - u32 cluster = ocfs2_blocks_to_clusters(inode->i_sb, input->group); - u32 total_clusters = le32_to_cpu(di->i_clusters); - int ret = -EINVAL; - - if (cluster < total_clusters) - mlog(ML_ERROR, "add a group which is in the current volume.\n"); - else if (input->chain >= cl_count) - mlog(ML_ERROR, "input chain exceeds the limit.\n"); - else if (next_free != cl_count && next_free != input->chain) - mlog(ML_ERROR, - "the add group should be in chain %u\n", next_free); - else if (total_clusters + input->clusters < total_clusters) - mlog(ML_ERROR, "add group's clusters overflow.\n"); - else if (input->clusters > cl_cpg) - mlog(ML_ERROR, "the cluster exceeds the maximum of a group\n"); - else if (input->frees > input->clusters) - mlog(ML_ERROR, "the free cluster exceeds the total clusters\n"); - else if (total_clusters % cl_cpg != 0) - mlog(ML_ERROR, - "the last group isn't full. Use group extend first.\n"); - else if (input->group != ocfs2_which_cluster_group(inode, cluster)) - mlog(ML_ERROR, "group blkno is invalid\n"); - else if ((ret = ocfs2_check_new_group(inode, di, input, group_bh))) - mlog(ML_ERROR, "group descriptor check failed.\n"); - else - ret = 0; - - return ret; -} - -/* Add a new group descriptor to global_bitmap. */ -int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input) -{ - int ret; - handle_t *handle; - struct buffer_head *main_bm_bh = NULL; - struct inode *main_bm_inode = NULL; - struct ocfs2_dinode *fe = NULL; - struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct buffer_head *group_bh = NULL; - struct ocfs2_group_desc *group = NULL; - struct ocfs2_chain_list *cl; - struct ocfs2_chain_rec *cr; - u16 cl_bpc; - - mlog_entry_void(); - - if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) - return -EROFS; - - main_bm_inode = ocfs2_get_system_file_inode(osb, - GLOBAL_BITMAP_SYSTEM_INODE, - OCFS2_INVALID_SLOT); - if (!main_bm_inode) { - ret = -EINVAL; - mlog_errno(ret); - goto out; - } - - mutex_lock(&main_bm_inode->i_mutex); - - ret = ocfs2_inode_lock(main_bm_inode, &main_bm_bh, 1); - if (ret < 0) { - mlog_errno(ret); - goto out_mutex; - } - - fe = (struct ocfs2_dinode *)main_bm_bh->b_data; - - if (le16_to_cpu(fe->id2.i_chain.cl_cpg) != - ocfs2_group_bitmap_size(osb->sb) * 8) { - mlog(ML_ERROR, "The disk is too old and small." - " Force to do offline resize."); - ret = -EINVAL; - goto out_unlock; - } - - ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL); - if (ret < 0) { - mlog(ML_ERROR, "Can't read the group descriptor # %llu " - "from the device.", (unsigned long long)input->group); - goto out_unlock; - } - - ocfs2_set_new_buffer_uptodate(inode, group_bh); - - ret = ocfs2_verify_group_and_input(main_bm_inode, fe, input, group_bh); - if (ret) { - mlog_errno(ret); - goto out_unlock; - } - - mlog(0, "Add a new group %llu in chain = %u, length = %u\n", - (unsigned long long)input->group, input->chain, input->clusters); - - handle = ocfs2_start_trans(osb, OCFS2_GROUP_ADD_CREDITS); - if (IS_ERR(handle)) { - mlog_errno(PTR_ERR(handle)); - ret = -EINVAL; - goto out_unlock; - } - - cl_bpc = le16_to_cpu(fe->id2.i_chain.cl_bpc); - cl = &fe->id2.i_chain; - cr = &cl->cl_recs[input->chain]; - - ret = ocfs2_journal_access(handle, main_bm_inode, group_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (ret < 0) { - mlog_errno(ret); - goto out_commit; - } - - group = (struct ocfs2_group_desc *)group_bh->b_data; - group->bg_next_group = cr->c_blkno; - - ret = ocfs2_journal_dirty(handle, group_bh); - if (ret < 0) { - mlog_errno(ret); - goto out_commit; - } - - ret = ocfs2_journal_access(handle, main_bm_inode, main_bm_bh, - OCFS2_JOURNAL_ACCESS_WRITE); - if (ret < 0) { - mlog_errno(ret); - goto out_commit; - } - - if (input->chain == le16_to_cpu(cl->cl_next_free_rec)) { - le16_add_cpu(&cl->cl_next_free_rec, 1); - memset(cr, 0, sizeof(struct ocfs2_chain_rec)); - } - - cr->c_blkno = le64_to_cpu(input->group); - le32_add_cpu(&cr->c_total, input->clusters * cl_bpc); - le32_add_cpu(&cr->c_free, input->frees * cl_bpc); - - le32_add_cpu(&fe->id1.bitmap1.i_total, input->clusters *cl_bpc); - le32_add_cpu(&fe->id1.bitmap1.i_used, - (input->clusters - input->frees) * cl_bpc); - le32_add_cpu(&fe->i_clusters, input->clusters); - - ocfs2_journal_dirty(handle, main_bm_bh); - - spin_lock(&OCFS2_I(main_bm_inode)->ip_lock); - OCFS2_I(main_bm_inode)->ip_clusters = le32_to_cpu(fe->i_clusters); - le64_add_cpu(&fe->i_size, input->clusters << osb->s_clustersize_bits); - spin_unlock(&OCFS2_I(main_bm_inode)->ip_lock); - i_size_write(main_bm_inode, le64_to_cpu(fe->i_size)); - - ocfs2_update_super_and_backups(main_bm_inode, input->clusters); - -out_commit: - ocfs2_commit_trans(osb, handle); -out_unlock: - brelse(group_bh); - brelse(main_bm_bh); - - ocfs2_inode_unlock(main_bm_inode, 1); - -out_mutex: - mutex_unlock(&main_bm_inode->i_mutex); - iput(main_bm_inode); - -out: - mlog_exit_void(); - return ret; -} diff --git a/trunk/fs/ocfs2/resize.h b/trunk/fs/ocfs2/resize.h deleted file mode 100644 index f38841abf10b..000000000000 --- a/trunk/fs/ocfs2/resize.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8; -*- - * vim: noexpandtab sw=8 ts=8 sts=0: - * - * resize.h - * - * Function prototypes - * - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef OCFS2_RESIZE_H -#define OCFS2_RESIZE_H - -int ocfs2_group_extend(struct inode * inode, int new_clusters); -int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input); - -#endif /* OCFS2_RESIZE_H */ diff --git a/trunk/fs/ocfs2/slot_map.c b/trunk/fs/ocfs2/slot_map.c index 3a50ce555e64..af4882b62cfa 100644 --- a/trunk/fs/ocfs2/slot_map.c +++ b/trunk/fs/ocfs2/slot_map.c @@ -48,6 +48,25 @@ static void __ocfs2_fill_slot(struct ocfs2_slot_info *si, s16 slot_num, s16 node_num); +/* Use the slot information we've collected to create a map of mounted + * nodes. Should be holding an EX on super block. assumes slot info is + * up to date. Note that we call this *after* we find a slot, so our + * own node should be set in the map too... */ +void ocfs2_populate_mounted_map(struct ocfs2_super *osb) +{ + int i; + struct ocfs2_slot_info *si = osb->slot_info; + + spin_lock(&si->si_lock); + + for (i = 0; i < si->si_size; i++) + if (si->si_global_node_nums[i] != OCFS2_INVALID_SLOT) + ocfs2_node_map_set_bit(osb, &osb->mounted_map, + si->si_global_node_nums[i]); + + spin_unlock(&si->si_lock); +} + /* post the slot information on disk into our slot_info struct. */ void ocfs2_update_slot_info(struct ocfs2_slot_info *si) { diff --git a/trunk/fs/ocfs2/slot_map.h b/trunk/fs/ocfs2/slot_map.h index 1025872aaade..d8c8ceed031b 100644 --- a/trunk/fs/ocfs2/slot_map.h +++ b/trunk/fs/ocfs2/slot_map.h @@ -52,6 +52,8 @@ s16 ocfs2_node_num_to_slot(struct ocfs2_slot_info *si, void ocfs2_clear_slot(struct ocfs2_slot_info *si, s16 slot_num); +void ocfs2_populate_mounted_map(struct ocfs2_super *osb); + static inline int ocfs2_is_empty_slot(struct ocfs2_slot_info *si, int slot_num) { diff --git a/trunk/fs/ocfs2/suballoc.c b/trunk/fs/ocfs2/suballoc.c index 7e397e2c25dd..8f09f5235e3a 100644 --- a/trunk/fs/ocfs2/suballoc.c +++ b/trunk/fs/ocfs2/suballoc.c @@ -101,6 +101,8 @@ static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode, u64 bg_blkno, u16 bg_bit_off); +static inline u64 ocfs2_which_cluster_group(struct inode *inode, + u32 cluster); static inline void ocfs2_block_to_cluster_group(struct inode *inode, u64 data_blkno, u64 *bg_blkno, @@ -112,7 +114,7 @@ void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac) if (inode) { if (ac->ac_which != OCFS2_AC_USE_LOCAL) - ocfs2_inode_unlock(inode, 1); + ocfs2_meta_unlock(inode, 1); mutex_unlock(&inode->i_mutex); @@ -129,9 +131,9 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) } /* somewhat more expensive than our other checks, so use sparingly. */ -int ocfs2_check_group_descriptor(struct super_block *sb, - struct ocfs2_dinode *di, - struct ocfs2_group_desc *gd) +static int ocfs2_check_group_descriptor(struct super_block *sb, + struct ocfs2_dinode *di, + struct ocfs2_group_desc *gd) { unsigned int max_bits; @@ -410,7 +412,7 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb, mutex_lock(&alloc_inode->i_mutex); - status = ocfs2_inode_lock(alloc_inode, &bh, 1); + status = ocfs2_meta_lock(alloc_inode, &bh, 1); if (status < 0) { mutex_unlock(&alloc_inode->i_mutex); iput(alloc_inode); @@ -1441,7 +1443,8 @@ static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode, /* given a cluster offset, calculate which block group it belongs to * and return that block offset. */ -u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster) +static inline u64 ocfs2_which_cluster_group(struct inode *inode, + u32 cluster) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); u32 group_no; @@ -1516,9 +1519,8 @@ int __ocfs2_claim_clusters(struct ocfs2_super *osb, if (min_clusters > (osb->bitmap_cpg - 1)) { /* The only paths asking for contiguousness * should know about this already. */ - mlog(ML_ERROR, "minimum allocation requested %u exceeds " - "group bitmap size %u!\n", min_clusters, - osb->bitmap_cpg); + mlog(ML_ERROR, "minimum allocation requested exceeds " + "group bitmap size!"); status = -ENOSPC; goto bail; } diff --git a/trunk/fs/ocfs2/suballoc.h b/trunk/fs/ocfs2/suballoc.h index 8799033bb459..cafe93703095 100644 --- a/trunk/fs/ocfs2/suballoc.h +++ b/trunk/fs/ocfs2/suballoc.h @@ -147,12 +147,4 @@ static inline int ocfs2_is_cluster_bitmap(struct inode *inode) int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb, struct ocfs2_alloc_context *ac); -/* given a cluster offset, calculate which block group it belongs to - * and return that block offset. */ -u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster); - -/* somewhat more expensive than our other checks, so use sparingly. */ -int ocfs2_check_group_descriptor(struct super_block *sb, - struct ocfs2_dinode *di, - struct ocfs2_group_desc *gd); #endif /* _CHAINALLOC_H_ */ diff --git a/trunk/fs/ocfs2/super.c b/trunk/fs/ocfs2/super.c index 01fe40ee5ea9..5ee775420665 100644 --- a/trunk/fs/ocfs2/super.c +++ b/trunk/fs/ocfs2/super.c @@ -65,6 +65,7 @@ #include "sysfile.h" #include "uptodate.h" #include "ver.h" +#include "vote.h" #include "buffer_head_io.h" @@ -83,11 +84,9 @@ MODULE_LICENSE("GPL"); struct mount_options { - unsigned long commit_interval; unsigned long mount_opt; unsigned int atime_quantum; signed short slot; - unsigned int localalloc_opt; }; static int ocfs2_parse_options(struct super_block *sb, char *options, @@ -151,9 +150,6 @@ enum { Opt_data_writeback, Opt_atime_quantum, Opt_slot, - Opt_commit, - Opt_localalloc, - Opt_localflocks, Opt_err, }; @@ -169,9 +165,6 @@ static match_table_t tokens = { {Opt_data_writeback, "data=writeback"}, {Opt_atime_quantum, "atime_quantum=%u"}, {Opt_slot, "preferred_slot=%u"}, - {Opt_commit, "commit=%u"}, - {Opt_localalloc, "localalloc=%d"}, - {Opt_localflocks, "localflocks"}, {Opt_err, NULL} }; @@ -220,7 +213,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) mlog_entry_void(); - new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE, 0); + new = ocfs2_iget(osb, osb->root_blkno, OCFS2_FI_FLAG_SYSFILE); if (IS_ERR(new)) { status = PTR_ERR(new); mlog_errno(status); @@ -228,7 +221,7 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) } osb->root_inode = new; - new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE, 0); + new = ocfs2_iget(osb, osb->system_dir_blkno, OCFS2_FI_FLAG_SYSFILE); if (IS_ERR(new)) { status = PTR_ERR(new); mlog_errno(status); @@ -450,8 +443,6 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) osb->s_mount_opt = parsed_options.mount_opt; osb->s_atime_quantum = parsed_options.atime_quantum; osb->preferred_slot = parsed_options.slot; - if (parsed_options.commit_interval) - osb->osb_commit_interval = parsed_options.commit_interval; if (!ocfs2_is_hard_readonly(osb)) ocfs2_set_journal_params(osb); @@ -606,8 +597,6 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) osb->s_mount_opt = parsed_options.mount_opt; osb->s_atime_quantum = parsed_options.atime_quantum; osb->preferred_slot = parsed_options.slot; - osb->osb_commit_interval = parsed_options.commit_interval; - osb->local_alloc_size = parsed_options.localalloc_opt; sb->s_magic = OCFS2_SUPER_MAGIC; @@ -758,11 +747,9 @@ static int ocfs2_parse_options(struct super_block *sb, mlog_entry("remount: %d, options: \"%s\"\n", is_remount, options ? options : "(none)"); - mopt->commit_interval = 0; mopt->mount_opt = 0; mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; mopt->slot = OCFS2_INVALID_SLOT; - mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE; if (!options) { status = 1; @@ -829,41 +816,6 @@ static int ocfs2_parse_options(struct super_block *sb, if (option) mopt->slot = (s16)option; break; - case Opt_commit: - option = 0; - if (match_int(&args[0], &option)) { - status = 0; - goto bail; - } - if (option < 0) - return 0; - if (option == 0) - option = JBD_DEFAULT_MAX_COMMIT_AGE; - mopt->commit_interval = HZ * option; - break; - case Opt_localalloc: - option = 0; - if (match_int(&args[0], &option)) { - status = 0; - goto bail; - } - if (option >= 0 && (option <= ocfs2_local_alloc_size(sb) * 8)) - mopt->localalloc_opt = option; - break; - case Opt_localflocks: - /* - * Changing this during remount could race - * flock() requests, or "unbalance" existing - * ones (e.g., a lock is taken in one mode but - * dropped in the other). If users care enough - * to flip locking modes during remount, we - * could add a "local" flag to individual - * flock structures for proper tracking of - * state. - */ - if (!is_remount) - mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS; - break; default: mlog(ML_ERROR, "Unrecognized mount option \"%s\" " @@ -912,16 +864,6 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM) seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum); - if (osb->osb_commit_interval) - seq_printf(s, ",commit=%u", - (unsigned) (osb->osb_commit_interval / HZ)); - - if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE) - seq_printf(s, ",localalloc=%d", osb->local_alloc_size); - - if (opts & OCFS2_MOUNT_LOCALFLOCKS) - seq_printf(s, ",localflocks,"); - return 0; } @@ -1023,7 +965,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf) goto bail; } - status = ocfs2_inode_lock(inode, &bh, 0); + status = ocfs2_meta_lock(inode, &bh, 0); if (status < 0) { mlog_errno(status); goto bail; @@ -1047,7 +989,7 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf) brelse(bh); - ocfs2_inode_unlock(inode, 0); + ocfs2_meta_unlock(inode, 0); status = 0; bail: if (inode) @@ -1078,7 +1020,8 @@ static void ocfs2_inode_init_once(struct kmem_cache *cachep, void *data) oi->ip_clusters = 0; ocfs2_lock_res_init_once(&oi->ip_rw_lockres); - ocfs2_lock_res_init_once(&oi->ip_inode_lockres); + ocfs2_lock_res_init_once(&oi->ip_meta_lockres); + ocfs2_lock_res_init_once(&oi->ip_data_lockres); ocfs2_lock_res_init_once(&oi->ip_open_lockres); ocfs2_metadata_cache_init(&oi->vfs_inode); @@ -1174,12 +1117,25 @@ static int ocfs2_mount_volume(struct super_block *sb) goto leave; } + status = ocfs2_register_hb_callbacks(osb); + if (status < 0) { + mlog_errno(status); + goto leave; + } + status = ocfs2_dlm_init(osb); if (status < 0) { mlog_errno(status); goto leave; } + /* requires vote_thread to be running. */ + status = ocfs2_register_net_handlers(osb); + if (status < 0) { + mlog_errno(status); + goto leave; + } + status = ocfs2_super_lock(osb, 1); if (status < 0) { mlog_errno(status); @@ -1194,6 +1150,8 @@ static int ocfs2_mount_volume(struct super_block *sb) goto leave; } + ocfs2_populate_mounted_map(osb); + /* load all node-local system inodes */ status = ocfs2_init_local_system_inodes(osb); if (status < 0) { @@ -1216,6 +1174,15 @@ static int ocfs2_mount_volume(struct super_block *sb) if (ocfs2_mount_local(osb)) goto leave; + /* This should be sent *after* we recovered our journal as it + * will cause other nodes to unmark us as needing + * recovery. However, we need to send it *before* dropping the + * super block lock as otherwise their recovery threads might + * try to clean us up while we're live! */ + status = ocfs2_request_mount_vote(osb); + if (status < 0) + mlog_errno(status); + leave: if (unlock_super) ocfs2_super_unlock(osb, 1); @@ -1273,6 +1240,10 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) mlog_errno(tmp); return; } + + tmp = ocfs2_request_umount_vote(osb); + if (tmp < 0) + mlog_errno(tmp); } if (osb->slot_num != OCFS2_INVALID_SLOT) @@ -1283,8 +1254,13 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) ocfs2_release_system_inodes(osb); - if (osb->dlm) + if (osb->dlm) { + ocfs2_unregister_net_handlers(osb); + ocfs2_dlm_shutdown(osb); + } + + ocfs2_clear_hb_callbacks(osb); debugfs_remove(osb->osb_debug_root); @@ -1339,6 +1315,7 @@ static int ocfs2_initialize_super(struct super_block *sb, int i, cbits, bbits; struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data; struct inode *inode = NULL; + struct buffer_head *bitmap_bh = NULL; struct ocfs2_journal *journal; __le32 uuid_net_key; struct ocfs2_super *osb; @@ -1367,13 +1344,19 @@ static int ocfs2_initialize_super(struct super_block *sb, osb->s_sectsize_bits = blksize_bits(sector_size); BUG_ON(!osb->s_sectsize_bits); + osb->net_response_ids = 0; + spin_lock_init(&osb->net_response_lock); + INIT_LIST_HEAD(&osb->net_response_list); + + INIT_LIST_HEAD(&osb->osb_net_handlers); init_waitqueue_head(&osb->recovery_event); - spin_lock_init(&osb->dc_task_lock); - init_waitqueue_head(&osb->dc_event); - osb->dc_work_sequence = 0; - osb->dc_wake_sequence = 0; + spin_lock_init(&osb->vote_task_lock); + init_waitqueue_head(&osb->vote_event); + osb->vote_work_sequence = 0; + osb->vote_wake_sequence = 0; INIT_LIST_HEAD(&osb->blocked_lock_list); osb->blocked_lock_count = 0; + INIT_LIST_HEAD(&osb->vote_list); spin_lock_init(&osb->osb_lock); atomic_set(&osb->alloc_stats.moves, 0); @@ -1513,6 +1496,7 @@ static int ocfs2_initialize_super(struct super_block *sb, } memcpy(&uuid_net_key, di->id2.i_super.s_uuid, sizeof(uuid_net_key)); + osb->net_key = le32_to_cpu(uuid_net_key); strncpy(osb->vol_label, di->id2.i_super.s_label, 63); osb->vol_label[63] = '\0'; @@ -1555,9 +1539,25 @@ static int ocfs2_initialize_super(struct super_block *sb, } osb->bitmap_blkno = OCFS2_I(inode)->ip_blkno; + + /* We don't have a cluster lock on the bitmap here because + * we're only interested in static information and the extra + * complexity at mount time isn't worht it. Don't pass the + * inode in to the read function though as we don't want it to + * be put in the cache. */ + status = ocfs2_read_block(osb, osb->bitmap_blkno, &bitmap_bh, 0, + NULL); iput(inode); + if (status < 0) { + mlog_errno(status); + goto bail; + } - osb->bitmap_cpg = ocfs2_group_bitmap_size(sb) * 8; + di = (struct ocfs2_dinode *) bitmap_bh->b_data; + osb->bitmap_cpg = le16_to_cpu(di->id2.i_chain.cl_cpg); + brelse(bitmap_bh); + mlog(0, "cluster bitmap inode: %llu, clusters per group: %u\n", + (unsigned long long)osb->bitmap_blkno, osb->bitmap_cpg); status = ocfs2_init_slot_info(osb); if (status < 0) { diff --git a/trunk/fs/ocfs2/sysfile.c b/trunk/fs/ocfs2/sysfile.c index ab713ebdd546..fd2e846e3e6f 100644 --- a/trunk/fs/ocfs2/sysfile.c +++ b/trunk/fs/ocfs2/sysfile.c @@ -112,7 +112,7 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, goto bail; } - inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE, type); + inode = ocfs2_iget(osb, blkno, OCFS2_FI_FLAG_SYSFILE); if (IS_ERR(inode)) { mlog_errno(PTR_ERR(inode)); inode = NULL; diff --git a/trunk/fs/ocfs2/ver.c b/trunk/fs/ocfs2/ver.c index e2488f4128a2..5405ce121c99 100644 --- a/trunk/fs/ocfs2/ver.c +++ b/trunk/fs/ocfs2/ver.c @@ -29,7 +29,7 @@ #include "ver.h" -#define OCFS2_BUILD_VERSION "1.5.0" +#define OCFS2_BUILD_VERSION "1.3.3" #define VERSION_STR "OCFS2 " OCFS2_BUILD_VERSION diff --git a/trunk/fs/ocfs2/vote.c b/trunk/fs/ocfs2/vote.c new file mode 100644 index 000000000000..c05358538f2b --- /dev/null +++ b/trunk/fs/ocfs2/vote.c @@ -0,0 +1,756 @@ +/* -*- mode: c; c-basic-offset: 8; -*- + * vim: noexpandtab sw=8 ts=8 sts=0: + * + * vote.c + * + * description here + * + * Copyright (C) 2003, 2004 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define MLOG_MASK_PREFIX ML_VOTE +#include + +#include "ocfs2.h" + +#include "alloc.h" +#include "dlmglue.h" +#include "extent_map.h" +#include "heartbeat.h" +#include "inode.h" +#include "journal.h" +#include "slot_map.h" +#include "vote.h" + +#include "buffer_head_io.h" + +#define OCFS2_MESSAGE_TYPE_VOTE (0x1) +#define OCFS2_MESSAGE_TYPE_RESPONSE (0x2) +struct ocfs2_msg_hdr +{ + __be32 h_response_id; /* used to lookup message handle on sending + * node. */ + __be32 h_request; + __be64 h_blkno; + __be32 h_generation; + __be32 h_node_num; /* node sending this particular message. */ +}; + +struct ocfs2_vote_msg +{ + struct ocfs2_msg_hdr v_hdr; + __be32 v_reserved1; +} __attribute__ ((packed)); + +/* Responses are given these values to maintain backwards + * compatibility with older ocfs2 versions */ +#define OCFS2_RESPONSE_OK (0) +#define OCFS2_RESPONSE_BUSY (-16) +#define OCFS2_RESPONSE_BAD_MSG (-22) + +struct ocfs2_response_msg +{ + struct ocfs2_msg_hdr r_hdr; + __be32 r_response; +} __attribute__ ((packed)); + +struct ocfs2_vote_work { + struct list_head w_list; + struct ocfs2_vote_msg w_msg; +}; + +enum ocfs2_vote_request { + OCFS2_VOTE_REQ_INVALID = 0, + OCFS2_VOTE_REQ_MOUNT, + OCFS2_VOTE_REQ_UMOUNT, + OCFS2_VOTE_REQ_LAST +}; + +static inline int ocfs2_is_valid_vote_request(int request) +{ + return OCFS2_VOTE_REQ_INVALID < request && + request < OCFS2_VOTE_REQ_LAST; +} + +typedef void (*ocfs2_net_response_callback)(void *priv, + struct ocfs2_response_msg *resp); +struct ocfs2_net_response_cb { + ocfs2_net_response_callback rc_cb; + void *rc_priv; +}; + +struct ocfs2_net_wait_ctxt { + struct list_head n_list; + u32 n_response_id; + wait_queue_head_t n_event; + struct ocfs2_node_map n_node_map; + int n_response; /* an agreggate response. 0 if + * all nodes are go, < 0 on any + * negative response from any + * node or network error. */ + struct ocfs2_net_response_cb *n_callback; +}; + +static void ocfs2_process_mount_request(struct ocfs2_super *osb, + unsigned int node_num) +{ + mlog(0, "MOUNT vote from node %u\n", node_num); + /* The other node only sends us this message when he has an EX + * on the superblock, so our recovery threads (if having been + * launched) are waiting on it.*/ + ocfs2_recovery_map_clear(osb, node_num); + ocfs2_node_map_set_bit(osb, &osb->mounted_map, node_num); + + /* We clear the umount map here because a node may have been + * previously mounted, safely unmounted but never stopped + * heartbeating - in which case we'd have a stale entry. */ + ocfs2_node_map_clear_bit(osb, &osb->umount_map, node_num); +} + +static void ocfs2_process_umount_request(struct ocfs2_super *osb, + unsigned int node_num) +{ + mlog(0, "UMOUNT vote from node %u\n", node_num); + ocfs2_node_map_clear_bit(osb, &osb->mounted_map, node_num); + ocfs2_node_map_set_bit(osb, &osb->umount_map, node_num); +} + +static void ocfs2_process_vote(struct ocfs2_super *osb, + struct ocfs2_vote_msg *msg) +{ + int net_status, vote_response; + unsigned int node_num; + u64 blkno; + enum ocfs2_vote_request request; + struct ocfs2_msg_hdr *hdr = &msg->v_hdr; + struct ocfs2_response_msg response; + + /* decode the network mumbo jumbo into local variables. */ + request = be32_to_cpu(hdr->h_request); + blkno = be64_to_cpu(hdr->h_blkno); + node_num = be32_to_cpu(hdr->h_node_num); + + mlog(0, "processing vote: request = %u, blkno = %llu, node_num = %u\n", + request, (unsigned long long)blkno, node_num); + + if (!ocfs2_is_valid_vote_request(request)) { + mlog(ML_ERROR, "Invalid vote request %d from node %u\n", + request, node_num); + vote_response = OCFS2_RESPONSE_BAD_MSG; + goto respond; + } + + vote_response = OCFS2_RESPONSE_OK; + + switch (request) { + case OCFS2_VOTE_REQ_UMOUNT: + ocfs2_process_umount_request(osb, node_num); + goto respond; + case OCFS2_VOTE_REQ_MOUNT: + ocfs2_process_mount_request(osb, node_num); + goto respond; + default: + /* avoids a gcc warning */ + break; + } + +respond: + /* Response struture is small so we just put it on the stack + * and stuff it inline. */ + memset(&response, 0, sizeof(struct ocfs2_response_msg)); + response.r_hdr.h_response_id = hdr->h_response_id; + response.r_hdr.h_blkno = hdr->h_blkno; + response.r_hdr.h_generation = hdr->h_generation; + response.r_hdr.h_node_num = cpu_to_be32(osb->node_num); + response.r_response = cpu_to_be32(vote_response); + + net_status = o2net_send_message(OCFS2_MESSAGE_TYPE_RESPONSE, + osb->net_key, + &response, + sizeof(struct ocfs2_response_msg), + node_num, + NULL); + /* We still want to error print for ENOPROTOOPT here. The + * sending node shouldn't have unregistered his net handler + * without sending an unmount vote 1st */ + if (net_status < 0 + && net_status != -ETIMEDOUT + && net_status != -ENOTCONN) + mlog(ML_ERROR, "message to node %u fails with error %d!\n", + node_num, net_status); +} + +static void ocfs2_vote_thread_do_work(struct ocfs2_super *osb) +{ + unsigned long processed; + struct ocfs2_lock_res *lockres; + struct ocfs2_vote_work *work; + + mlog_entry_void(); + + spin_lock(&osb->vote_task_lock); + /* grab this early so we know to try again if a state change and + * wake happens part-way through our work */ + osb->vote_work_sequence = osb->vote_wake_sequence; + + processed = osb->blocked_lock_count; + while (processed) { + BUG_ON(list_empty(&osb->blocked_lock_list)); + + lockres = list_entry(osb->blocked_lock_list.next, + struct ocfs2_lock_res, l_blocked_list); + list_del_init(&lockres->l_blocked_list); + osb->blocked_lock_count--; + spin_unlock(&osb->vote_task_lock); + + BUG_ON(!processed); + processed--; + + ocfs2_process_blocked_lock(osb, lockres); + + spin_lock(&osb->vote_task_lock); + } + + while (osb->vote_count) { + BUG_ON(list_empty(&osb->vote_list)); + work = list_entry(osb->vote_list.next, + struct ocfs2_vote_work, w_list); + list_del(&work->w_list); + osb->vote_count--; + spin_unlock(&osb->vote_task_lock); + + ocfs2_process_vote(osb, &work->w_msg); + kfree(work); + + spin_lock(&osb->vote_task_lock); + } + spin_unlock(&osb->vote_task_lock); + + mlog_exit_void(); +} + +static int ocfs2_vote_thread_lists_empty(struct ocfs2_super *osb) +{ + int empty = 0; + + spin_lock(&osb->vote_task_lock); + if (list_empty(&osb->blocked_lock_list) && + list_empty(&osb->vote_list)) + empty = 1; + + spin_unlock(&osb->vote_task_lock); + return empty; +} + +static int ocfs2_vote_thread_should_wake(struct ocfs2_super *osb) +{ + int should_wake = 0; + + spin_lock(&osb->vote_task_lock); + if (osb->vote_work_sequence != osb->vote_wake_sequence) + should_wake = 1; + spin_unlock(&osb->vote_task_lock); + + return should_wake; +} + +int ocfs2_vote_thread(void *arg) +{ + int status = 0; + struct ocfs2_super *osb = arg; + + /* only quit once we've been asked to stop and there is no more + * work available */ + while (!(kthread_should_stop() && + ocfs2_vote_thread_lists_empty(osb))) { + + wait_event_interruptible(osb->vote_event, + ocfs2_vote_thread_should_wake(osb) || + kthread_should_stop()); + + mlog(0, "vote_thread: awoken\n"); + + ocfs2_vote_thread_do_work(osb); + } + + osb->vote_task = NULL; + return status; +} + +static struct ocfs2_net_wait_ctxt *ocfs2_new_net_wait_ctxt(unsigned int response_id) +{ + struct ocfs2_net_wait_ctxt *w; + + w = kzalloc(sizeof(*w), GFP_NOFS); + if (!w) { + mlog_errno(-ENOMEM); + goto bail; + } + + INIT_LIST_HEAD(&w->n_list); + init_waitqueue_head(&w->n_event); + ocfs2_node_map_init(&w->n_node_map); + w->n_response_id = response_id; + w->n_callback = NULL; +bail: + return w; +} + +static unsigned int ocfs2_new_response_id(struct ocfs2_super *osb) +{ + unsigned int ret; + + spin_lock(&osb->net_response_lock); + ret = ++osb->net_response_ids; + spin_unlock(&osb->net_response_lock); + + return ret; +} + +static void ocfs2_dequeue_net_wait_ctxt(struct ocfs2_super *osb, + struct ocfs2_net_wait_ctxt *w) +{ + spin_lock(&osb->net_response_lock); + list_del(&w->n_list); + spin_unlock(&osb->net_response_lock); +} + +static void ocfs2_queue_net_wait_ctxt(struct ocfs2_super *osb, + struct ocfs2_net_wait_ctxt *w) +{ + spin_lock(&osb->net_response_lock); + list_add_tail(&w->n_list, + &osb->net_response_list); + spin_unlock(&osb->net_response_lock); +} + +static void __ocfs2_mark_node_responded(struct ocfs2_super *osb, + struct ocfs2_net_wait_ctxt *w, + int node_num) +{ + assert_spin_locked(&osb->net_response_lock); + + ocfs2_node_map_clear_bit(osb, &w->n_node_map, node_num); + if (ocfs2_node_map_is_empty(osb, &w->n_node_map)) + wake_up(&w->n_event); +} + +/* Intended to be called from the node down callback, we fake remove + * the node from all our response contexts */ +void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb, + int node_num) +{ + struct list_head *p; + struct ocfs2_net_wait_ctxt *w = NULL; + + spin_lock(&osb->net_response_lock); + + list_for_each(p, &osb->net_response_list) { + w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list); + + __ocfs2_mark_node_responded(osb, w, node_num); + } + + spin_unlock(&osb->net_response_lock); +} + +static int ocfs2_broadcast_vote(struct ocfs2_super *osb, + struct ocfs2_vote_msg *request, + unsigned int response_id, + int *response, + struct ocfs2_net_response_cb *callback) +{ + int status, i, remote_err; + struct ocfs2_net_wait_ctxt *w = NULL; + int dequeued = 0; + + mlog_entry_void(); + + w = ocfs2_new_net_wait_ctxt(response_id); + if (!w) { + status = -ENOMEM; + mlog_errno(status); + goto bail; + } + w->n_callback = callback; + + /* we're pretty much ready to go at this point, and this fills + * in n_response which we need anyway... */ + ocfs2_queue_net_wait_ctxt(osb, w); + + i = ocfs2_node_map_iterate(osb, &osb->mounted_map, 0); + + while (i != O2NM_INVALID_NODE_NUM) { + if (i != osb->node_num) { + mlog(0, "trying to send request to node %i\n", i); + ocfs2_node_map_set_bit(osb, &w->n_node_map, i); + + remote_err = 0; + status = o2net_send_message(OCFS2_MESSAGE_TYPE_VOTE, + osb->net_key, + request, + sizeof(*request), + i, + &remote_err); + if (status == -ETIMEDOUT) { + mlog(0, "remote node %d timed out!\n", i); + status = -EAGAIN; + goto bail; + } + if (remote_err < 0) { + status = remote_err; + mlog(0, "remote error %d on node %d!\n", + remote_err, i); + mlog_errno(status); + goto bail; + } + if (status < 0) { + mlog_errno(status); + goto bail; + } + } + i++; + i = ocfs2_node_map_iterate(osb, &osb->mounted_map, i); + mlog(0, "next is %d, i am %d\n", i, osb->node_num); + } + mlog(0, "done sending, now waiting on responses...\n"); + + wait_event(w->n_event, ocfs2_node_map_is_empty(osb, &w->n_node_map)); + + ocfs2_dequeue_net_wait_ctxt(osb, w); + dequeued = 1; + + *response = w->n_response; + status = 0; +bail: + if (w) { + if (!dequeued) + ocfs2_dequeue_net_wait_ctxt(osb, w); + kfree(w); + } + + mlog_exit(status); + return status; +} + +static struct ocfs2_vote_msg * ocfs2_new_vote_request(struct ocfs2_super *osb, + u64 blkno, + unsigned int generation, + enum ocfs2_vote_request type) +{ + struct ocfs2_vote_msg *request; + struct ocfs2_msg_hdr *hdr; + + BUG_ON(!ocfs2_is_valid_vote_request(type)); + + request = kzalloc(sizeof(*request), GFP_NOFS); + if (!request) { + mlog_errno(-ENOMEM); + } else { + hdr = &request->v_hdr; + hdr->h_node_num = cpu_to_be32(osb->node_num); + hdr->h_request = cpu_to_be32(type); + hdr->h_blkno = cpu_to_be64(blkno); + hdr->h_generation = cpu_to_be32(generation); + } + + return request; +} + +/* Complete the buildup of a new vote request and process the + * broadcast return value. */ +static int ocfs2_do_request_vote(struct ocfs2_super *osb, + struct ocfs2_vote_msg *request, + struct ocfs2_net_response_cb *callback) +{ + int status, response = -EBUSY; + unsigned int response_id; + struct ocfs2_msg_hdr *hdr; + + response_id = ocfs2_new_response_id(osb); + + hdr = &request->v_hdr; + hdr->h_response_id = cpu_to_be32(response_id); + + status = ocfs2_broadcast_vote(osb, request, response_id, &response, + callback); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + status = response; +bail: + + return status; +} + +int ocfs2_request_mount_vote(struct ocfs2_super *osb) +{ + int status; + struct ocfs2_vote_msg *request = NULL; + + request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_MOUNT); + if (!request) { + status = -ENOMEM; + goto bail; + } + + status = -EAGAIN; + while (status == -EAGAIN) { + if (!(osb->s_mount_opt & OCFS2_MOUNT_NOINTR) && + signal_pending(current)) { + status = -ERESTARTSYS; + goto bail; + } + + if (ocfs2_node_map_is_only(osb, &osb->mounted_map, + osb->node_num)) { + status = 0; + goto bail; + } + + status = ocfs2_do_request_vote(osb, request, NULL); + } + +bail: + kfree(request); + return status; +} + +int ocfs2_request_umount_vote(struct ocfs2_super *osb) +{ + int status; + struct ocfs2_vote_msg *request = NULL; + + request = ocfs2_new_vote_request(osb, 0ULL, 0, OCFS2_VOTE_REQ_UMOUNT); + if (!request) { + status = -ENOMEM; + goto bail; + } + + status = -EAGAIN; + while (status == -EAGAIN) { + /* Do not check signals on this vote... We really want + * this one to go all the way through. */ + + if (ocfs2_node_map_is_only(osb, &osb->mounted_map, + osb->node_num)) { + status = 0; + goto bail; + } + + status = ocfs2_do_request_vote(osb, request, NULL); + } + +bail: + kfree(request); + return status; +} + +/* TODO: This should eventually be a hash table! */ +static struct ocfs2_net_wait_ctxt * __ocfs2_find_net_wait_ctxt(struct ocfs2_super *osb, + u32 response_id) +{ + struct list_head *p; + struct ocfs2_net_wait_ctxt *w = NULL; + + list_for_each(p, &osb->net_response_list) { + w = list_entry(p, struct ocfs2_net_wait_ctxt, n_list); + if (response_id == w->n_response_id) + break; + w = NULL; + } + + return w; +} + +/* Translate response codes into local node errno values */ +static inline int ocfs2_translate_response(int response) +{ + int ret; + + switch (response) { + case OCFS2_RESPONSE_OK: + ret = 0; + break; + + case OCFS2_RESPONSE_BUSY: + ret = -EBUSY; + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static int ocfs2_handle_response_message(struct o2net_msg *msg, + u32 len, + void *data, void **ret_data) +{ + unsigned int response_id, node_num; + int response_status; + struct ocfs2_super *osb = data; + struct ocfs2_response_msg *resp; + struct ocfs2_net_wait_ctxt * w; + struct ocfs2_net_response_cb *resp_cb; + + resp = (struct ocfs2_response_msg *) msg->buf; + + response_id = be32_to_cpu(resp->r_hdr.h_response_id); + node_num = be32_to_cpu(resp->r_hdr.h_node_num); + response_status = + ocfs2_translate_response(be32_to_cpu(resp->r_response)); + + mlog(0, "received response message:\n"); + mlog(0, "h_response_id = %u\n", response_id); + mlog(0, "h_request = %u\n", be32_to_cpu(resp->r_hdr.h_request)); + mlog(0, "h_blkno = %llu\n", + (unsigned long long)be64_to_cpu(resp->r_hdr.h_blkno)); + mlog(0, "h_generation = %u\n", be32_to_cpu(resp->r_hdr.h_generation)); + mlog(0, "h_node_num = %u\n", node_num); + mlog(0, "r_response = %d\n", response_status); + + spin_lock(&osb->net_response_lock); + w = __ocfs2_find_net_wait_ctxt(osb, response_id); + if (!w) { + mlog(0, "request not found!\n"); + goto bail; + } + resp_cb = w->n_callback; + + if (response_status && (!w->n_response)) { + /* we only really need one negative response so don't + * set it twice. */ + w->n_response = response_status; + } + + if (resp_cb) { + spin_unlock(&osb->net_response_lock); + + resp_cb->rc_cb(resp_cb->rc_priv, resp); + + spin_lock(&osb->net_response_lock); + } + + __ocfs2_mark_node_responded(osb, w, node_num); +bail: + spin_unlock(&osb->net_response_lock); + + return 0; +} + +static int ocfs2_handle_vote_message(struct o2net_msg *msg, + u32 len, + void *data, void **ret_data) +{ + int status; + struct ocfs2_super *osb = data; + struct ocfs2_vote_work *work; + + work = kmalloc(sizeof(struct ocfs2_vote_work), GFP_NOFS); + if (!work) { + status = -ENOMEM; + mlog_errno(status); + goto bail; + } + + INIT_LIST_HEAD(&work->w_list); + memcpy(&work->w_msg, msg->buf, sizeof(struct ocfs2_vote_msg)); + + mlog(0, "scheduling vote request:\n"); + mlog(0, "h_response_id = %u\n", + be32_to_cpu(work->w_msg.v_hdr.h_response_id)); + mlog(0, "h_request = %u\n", be32_to_cpu(work->w_msg.v_hdr.h_request)); + mlog(0, "h_blkno = %llu\n", + (unsigned long long)be64_to_cpu(work->w_msg.v_hdr.h_blkno)); + mlog(0, "h_generation = %u\n", + be32_to_cpu(work->w_msg.v_hdr.h_generation)); + mlog(0, "h_node_num = %u\n", + be32_to_cpu(work->w_msg.v_hdr.h_node_num)); + + spin_lock(&osb->vote_task_lock); + list_add_tail(&work->w_list, &osb->vote_list); + osb->vote_count++; + spin_unlock(&osb->vote_task_lock); + + ocfs2_kick_vote_thread(osb); + + status = 0; +bail: + return status; +} + +void ocfs2_unregister_net_handlers(struct ocfs2_super *osb) +{ + if (!osb->net_key) + return; + + o2net_unregister_handler_list(&osb->osb_net_handlers); + + if (!list_empty(&osb->net_response_list)) + mlog(ML_ERROR, "net response list not empty!\n"); + + osb->net_key = 0; +} + +int ocfs2_register_net_handlers(struct ocfs2_super *osb) +{ + int status = 0; + + if (ocfs2_mount_local(osb)) + return 0; + + status = o2net_register_handler(OCFS2_MESSAGE_TYPE_RESPONSE, + osb->net_key, + sizeof(struct ocfs2_response_msg), + ocfs2_handle_response_message, + osb, NULL, &osb->osb_net_handlers); + if (status) { + mlog_errno(status); + goto bail; + } + + status = o2net_register_handler(OCFS2_MESSAGE_TYPE_VOTE, + osb->net_key, + sizeof(struct ocfs2_vote_msg), + ocfs2_handle_vote_message, + osb, NULL, &osb->osb_net_handlers); + if (status) { + mlog_errno(status); + goto bail; + } +bail: + if (status < 0) + ocfs2_unregister_net_handlers(osb); + + return status; +} diff --git a/trunk/fs/ocfs2/locks.h b/trunk/fs/ocfs2/vote.h similarity index 54% rename from trunk/fs/ocfs2/locks.h rename to trunk/fs/ocfs2/vote.h index 9743ef2324ec..9ea46f62de31 100644 --- a/trunk/fs/ocfs2/locks.h +++ b/trunk/fs/ocfs2/vote.h @@ -1,9 +1,9 @@ /* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * - * locks.h + * vote.h * - * Function prototypes for Userspace file locking support + * description here * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * @@ -23,9 +23,26 @@ * Boston, MA 021110-1307, USA. */ -#ifndef OCFS2_LOCKS_H -#define OCFS2_LOCKS_H -int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl); +#ifndef VOTE_H +#define VOTE_H -#endif /* OCFS2_LOCKS_H */ +int ocfs2_vote_thread(void *arg); +static inline void ocfs2_kick_vote_thread(struct ocfs2_super *osb) +{ + spin_lock(&osb->vote_task_lock); + /* make sure the voting thread gets a swipe at whatever changes + * the caller may have made to the voting state */ + osb->vote_wake_sequence++; + spin_unlock(&osb->vote_task_lock); + wake_up(&osb->vote_event); +} + +int ocfs2_request_mount_vote(struct ocfs2_super *osb); +int ocfs2_request_umount_vote(struct ocfs2_super *osb); +int ocfs2_register_net_handlers(struct ocfs2_super *osb); +void ocfs2_unregister_net_handlers(struct ocfs2_super *osb); + +void ocfs2_remove_node_from_vote_queues(struct ocfs2_super *osb, + int node_num); +#endif diff --git a/trunk/fs/proc/base.c b/trunk/fs/proc/base.c index 91fa8e6ce8ad..7411bfb0b7cc 100644 --- a/trunk/fs/proc/base.c +++ b/trunk/fs/proc/base.c @@ -310,77 +310,6 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer) } #endif -#ifdef CONFIG_LATENCYTOP -static int lstats_show_proc(struct seq_file *m, void *v) -{ - int i; - struct task_struct *task = m->private; - seq_puts(m, "Latency Top version : v0.1\n"); - - for (i = 0; i < 32; i++) { - if (task->latency_record[i].backtrace[0]) { - int q; - seq_printf(m, "%i %li %li ", - task->latency_record[i].count, - task->latency_record[i].time, - task->latency_record[i].max); - for (q = 0; q < LT_BACKTRACEDEPTH; q++) { - char sym[KSYM_NAME_LEN]; - char *c; - if (!task->latency_record[i].backtrace[q]) - break; - if (task->latency_record[i].backtrace[q] == ULONG_MAX) - break; - sprint_symbol(sym, task->latency_record[i].backtrace[q]); - c = strchr(sym, '+'); - if (c) - *c = 0; - seq_printf(m, "%s ", sym); - } - seq_printf(m, "\n"); - } - - } - return 0; -} - -static int lstats_open(struct inode *inode, struct file *file) -{ - int ret; - struct seq_file *m; - struct task_struct *task = get_proc_task(inode); - - ret = single_open(file, lstats_show_proc, NULL); - if (!ret) { - m = file->private_data; - m->private = task; - } - return ret; -} - -static ssize_t lstats_write(struct file *file, const char __user *buf, - size_t count, loff_t *offs) -{ - struct seq_file *m; - struct task_struct *task; - - m = file->private_data; - task = m->private; - clear_all_latency_tracing(task); - - return count; -} - -static const struct file_operations proc_lstats_operations = { - .open = lstats_open, - .read = seq_read, - .write = lstats_write, - .llseek = seq_lseek, - .release = single_release, -}; - -#endif - /* The badness from the OOM killer */ unsigned long badness(struct task_struct *p, unsigned long uptime); static int proc_oom_score(struct task_struct *task, char *buffer) @@ -1091,7 +1020,6 @@ static const struct file_operations proc_fault_inject_operations = { }; #endif - #ifdef CONFIG_SCHED_DEBUG /* * Print out various scheduling related per-task fields: @@ -2302,9 +2230,6 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat), #endif -#ifdef CONFIG_LATENCYTOP - REG("latency", S_IRUGO, lstats), -#endif #ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset), #endif @@ -2630,9 +2555,6 @@ static const struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_SCHEDSTATS INF("schedstat", S_IRUGO, pid_schedstat), #endif -#ifdef CONFIG_LATENCYTOP - REG("latency", S_IRUGO, lstats), -#endif #ifdef CONFIG_PROC_PID_CPUSET REG("cpuset", S_IRUGO, cpuset), #endif diff --git a/trunk/include/asm-cris/arch-v10/ide.h b/trunk/include/asm-cris/arch-v10/ide.h index ea34e0d0a388..78b301ed7b12 100644 --- a/trunk/include/asm-cris/arch-v10/ide.h +++ b/trunk/include/asm-cris/arch-v10/ide.h @@ -89,6 +89,11 @@ static inline void ide_init_default_hwifs(void) } } +/* some configuration options we don't need */ + +#undef SUPPORT_VLB_SYNC +#define SUPPORT_VLB_SYNC 0 + #endif /* __KERNEL__ */ #endif /* __ASMCRIS_IDE_H */ diff --git a/trunk/include/asm-cris/arch-v32/ide.h b/trunk/include/asm-cris/arch-v32/ide.h index fb9c3627a5b4..11296170d057 100644 --- a/trunk/include/asm-cris/arch-v32/ide.h +++ b/trunk/include/asm-cris/arch-v32/ide.h @@ -48,6 +48,11 @@ static inline unsigned long ide_default_io_base(int index) return REG_TYPE_CONV(unsigned long, reg_ata_rw_ctrl2, ctrl2); } +/* some configuration options we don't need */ + +#undef SUPPORT_VLB_SYNC +#define SUPPORT_VLB_SYNC 0 + #define IDE_ARCH_ACK_INTR #define ide_ack_intr(hwif) ((hwif)->ack_intr(hwif)) diff --git a/trunk/include/asm-frv/ide.h b/trunk/include/asm-frv/ide.h index 8c9a540d4344..f0bd2cb250c1 100644 --- a/trunk/include/asm-frv/ide.h +++ b/trunk/include/asm-frv/ide.h @@ -18,6 +18,12 @@ #include #include +#undef SUPPORT_SLOW_DATA_PORTS +#define SUPPORT_SLOW_DATA_PORTS 0 + +#undef SUPPORT_VLB_SYNC +#define SUPPORT_VLB_SYNC 0 + #ifndef MAX_HWIFS #define MAX_HWIFS 8 #endif diff --git a/trunk/include/asm-generic/resource.h b/trunk/include/asm-generic/resource.h index 587566f95f6c..a4a22cc35898 100644 --- a/trunk/include/asm-generic/resource.h +++ b/trunk/include/asm-generic/resource.h @@ -44,8 +44,8 @@ #define RLIMIT_NICE 13 /* max nice prio allowed to raise to 0-39 for nice level 19 .. -20 */ #define RLIMIT_RTPRIO 14 /* maximum realtime priority */ -#define RLIMIT_RTTIME 15 /* timeout for RT tasks in us */ -#define RLIM_NLIMITS 16 + +#define RLIM_NLIMITS 15 /* * SuS says limits have to be unsigned. @@ -86,7 +86,6 @@ [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ [RLIMIT_NICE] = { 0, 0 }, \ [RLIMIT_RTPRIO] = { 0, 0 }, \ - [RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY }, \ } #endif /* __KERNEL__ */ diff --git a/trunk/include/asm-powerpc/ide.h b/trunk/include/asm-powerpc/ide.h index 6d50310ecaea..fd7f5a430f0a 100644 --- a/trunk/include/asm-powerpc/ide.h +++ b/trunk/include/asm-powerpc/ide.h @@ -42,6 +42,9 @@ struct ide_machdep_calls { extern struct ide_machdep_calls ppc_ide_md; +#undef SUPPORT_SLOW_DATA_PORTS +#define SUPPORT_SLOW_DATA_PORTS 0 + #define IDE_ARCH_OBSOLETE_DEFAULTS static __inline__ int ide_default_irq(unsigned long base) diff --git a/trunk/include/asm-x86/thread_info_32.h b/trunk/include/asm-x86/thread_info_32.h index ef58fd2a6eb0..22a8cbcd35e2 100644 --- a/trunk/include/asm-x86/thread_info_32.h +++ b/trunk/include/asm-x86/thread_info_32.h @@ -132,7 +132,6 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */ #define TIF_SECCOMP 7 /* secure computing */ #define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal() */ -#define TIF_HRTICK_RESCHED 9 /* reprogram hrtick timer */ #define TIF_MEMDIE 16 #define TIF_DEBUG 17 /* uses debug registers */ #define TIF_IO_BITMAP 18 /* uses I/O bitmap */ @@ -148,7 +147,6 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_AUDIT (1<= 5 && id[93] == 0; } -static inline int ata_id_has_tpm(const u16 *id) -{ - /* The TPM bits are only valid on ATA8 */ - if (ata_id_major_version(id) < 8) - return 0; - if ((id[48] & 0xC000) != 0x4000) - return 0; - return id[48] & (1 << 0); -} - -static inline int ata_id_has_dword_io(const u16 *id) -{ - /* ATA 8 reuses this flag for "trusted" computing */ - if (ata_id_major_version(id) > 7) - return 0; - if (id[48] & (1 << 0)) - return 1; - return 0; -} - static inline int ata_id_current_chs_valid(const u16 *id) { /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command @@ -659,6 +574,13 @@ static inline int atapi_command_packet_set(const u16 *dev_id) return (dev_id[0] >> 8) & 0x1f; } +static inline int is_atapi_taskfile(const struct ata_taskfile *tf) +{ + return (tf->protocol == ATA_PROT_ATAPI) || + (tf->protocol == ATA_PROT_ATAPI_NODATA) || + (tf->protocol == ATA_PROT_ATAPI_DMA); +} + static inline int is_multi_taskfile(struct ata_taskfile *tf) { return (tf->command == ATA_CMD_READ_MULTI) || diff --git a/trunk/include/linux/blkdev.h b/trunk/include/linux/blkdev.h index 40ee1706caa3..d18ee67b40f8 100644 --- a/trunk/include/linux/blkdev.h +++ b/trunk/include/linux/blkdev.h @@ -144,6 +144,7 @@ enum rq_cmd_type_bits { * private REQ_LB opcodes to differentiate what type of request this is */ REQ_TYPE_ATA_CMD, + REQ_TYPE_ATA_TASK, REQ_TYPE_ATA_TASKFILE, REQ_TYPE_ATA_PC, }; diff --git a/trunk/include/linux/cdrom.h b/trunk/include/linux/cdrom.h index fcdc11b9609b..c6d3e22c0624 100644 --- a/trunk/include/linux/cdrom.h +++ b/trunk/include/linux/cdrom.h @@ -451,7 +451,6 @@ struct cdrom_generic_command #define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e #define GPCMD_READ_10 0x28 #define GPCMD_READ_12 0xa8 -#define GPCMD_READ_BUFFER 0x3c #define GPCMD_READ_BUFFER_CAPACITY 0x5c #define GPCMD_READ_CDVD_CAPACITY 0x25 #define GPCMD_READ_CD 0xbe @@ -481,9 +480,7 @@ struct cdrom_generic_command #define GPCMD_TEST_UNIT_READY 0x00 #define GPCMD_VERIFY_10 0x2f #define GPCMD_WRITE_10 0x2a -#define GPCMD_WRITE_12 0xaa #define GPCMD_WRITE_AND_VERIFY_10 0x2e -#define GPCMD_WRITE_BUFFER 0x3b /* This is listed as optional in ATAPI 2.6, but is (curiously) * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji * Table 377 as an MMC command for SCSi devices though... Most ATAPI diff --git a/trunk/include/linux/cpu.h b/trunk/include/linux/cpu.h index 0be8d65bc3c8..92f2029a34f3 100644 --- a/trunk/include/linux/cpu.h +++ b/trunk/include/linux/cpu.h @@ -71,27 +71,18 @@ static inline void unregister_cpu_notifier(struct notifier_block *nb) int cpu_up(unsigned int cpu); -extern void cpu_hotplug_init(void); - #else static inline int register_cpu_notifier(struct notifier_block *nb) { return 0; } - static inline void unregister_cpu_notifier(struct notifier_block *nb) { } -static inline void cpu_hotplug_init(void) -{ -} - #endif /* CONFIG_SMP */ extern struct sysdev_class cpu_sysdev_class; -extern void cpu_maps_update_begin(void); -extern void cpu_maps_update_done(void); #ifdef CONFIG_HOTPLUG_CPU /* Stop CPUs going up and down. */ @@ -106,8 +97,8 @@ static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex) mutex_unlock(cpu_hp_mutex); } -extern void get_online_cpus(void); -extern void put_online_cpus(void); +extern void lock_cpu_hotplug(void); +extern void unlock_cpu_hotplug(void); #define hotcpu_notifier(fn, pri) { \ static struct notifier_block fn##_nb = \ { .notifier_call = fn, .priority = pri }; \ @@ -124,8 +115,8 @@ static inline void cpuhotplug_mutex_lock(struct mutex *cpu_hp_mutex) static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex) { } -#define get_online_cpus() do { } while (0) -#define put_online_cpus() do { } while (0) +#define lock_cpu_hotplug() do { } while (0) +#define unlock_cpu_hotplug() do { } while (0) #define hotcpu_notifier(fn, pri) do { (void)(fn); } while (0) /* These aren't inline functions due to a GCC bug. */ #define register_hotcpu_notifier(nb) ({ (void)(nb); 0; }) diff --git a/trunk/include/linux/debug_locks.h b/trunk/include/linux/debug_locks.h index f4a5871767f5..1678a5de7013 100644 --- a/trunk/include/linux/debug_locks.h +++ b/trunk/include/linux/debug_locks.h @@ -47,7 +47,6 @@ struct task_struct; #ifdef CONFIG_LOCKDEP extern void debug_show_all_locks(void); -extern void __debug_show_held_locks(struct task_struct *task); extern void debug_show_held_locks(struct task_struct *task); extern void debug_check_no_locks_freed(const void *from, unsigned long len); extern void debug_check_no_locks_held(struct task_struct *task); @@ -56,10 +55,6 @@ static inline void debug_show_all_locks(void) { } -static inline void __debug_show_held_locks(struct task_struct *task) -{ -} - static inline void debug_show_held_locks(struct task_struct *task) { } diff --git a/trunk/include/linux/dlm.h b/trunk/include/linux/dlm.h index c743fbc769db..be9d278761e0 100644 --- a/trunk/include/linux/dlm.h +++ b/trunk/include/linux/dlm.h @@ -19,12 +19,148 @@ * routines and structures to use DLM lockspaces */ -/* Lock levels and flags are here */ -#include +/* + * Lock Modes + */ +#define DLM_LOCK_IV -1 /* invalid */ +#define DLM_LOCK_NL 0 /* null */ +#define DLM_LOCK_CR 1 /* concurrent read */ +#define DLM_LOCK_CW 2 /* concurrent write */ +#define DLM_LOCK_PR 3 /* protected read */ +#define DLM_LOCK_PW 4 /* protected write */ +#define DLM_LOCK_EX 5 /* exclusive */ + +/* + * Maximum size in bytes of a dlm_lock name + */ #define DLM_RESNAME_MAXLEN 64 +/* + * Flags to dlm_lock + * + * DLM_LKF_NOQUEUE + * + * Do not queue the lock request on the wait queue if it cannot be granted + * immediately. If the lock cannot be granted because of this flag, DLM will + * either return -EAGAIN from the dlm_lock call or will return 0 from + * dlm_lock and -EAGAIN in the lock status block when the AST is executed. + * + * DLM_LKF_CANCEL + * + * Used to cancel a pending lock request or conversion. A converting lock is + * returned to its previously granted mode. + * + * DLM_LKF_CONVERT + * + * Indicates a lock conversion request. For conversions the name and namelen + * are ignored and the lock ID in the LKSB is used to identify the lock. + * + * DLM_LKF_VALBLK + * + * Requests DLM to return the current contents of the lock value block in the + * lock status block. When this flag is set in a lock conversion from PW or EX + * modes, DLM assigns the value specified in the lock status block to the lock + * value block of the lock resource. The LVB is a DLM_LVB_LEN size array + * containing application-specific information. + * + * DLM_LKF_QUECVT + * + * Force a conversion request to be queued, even if it is compatible with + * the granted modes of other locks on the same resource. + * + * DLM_LKF_IVVALBLK + * + * Invalidate the lock value block. + * + * DLM_LKF_CONVDEADLK + * + * Allows the dlm to resolve conversion deadlocks internally by demoting the + * granted mode of a converting lock to NL. The DLM_SBF_DEMOTED flag is + * returned for a conversion that's been effected by this. + * + * DLM_LKF_PERSISTENT + * + * Only relevant to locks originating in userspace. A persistent lock will not + * be removed if the process holding the lock exits. + * + * DLM_LKF_NODLCKWT + * + * Do not cancel the lock if it gets into conversion deadlock. + * Exclude this lock from being monitored due to DLM_LSFL_TIMEWARN. + * + * DLM_LKF_NODLCKBLK + * + * net yet implemented + * + * DLM_LKF_EXPEDITE + * + * Used only with new requests for NL mode locks. Tells the lock manager + * to grant the lock, ignoring other locks in convert and wait queues. + * + * DLM_LKF_NOQUEUEBAST + * + * Send blocking AST's before returning -EAGAIN to the caller. It is only + * used along with the NOQUEUE flag. Blocking AST's are not sent for failed + * NOQUEUE requests otherwise. + * + * DLM_LKF_HEADQUE + * + * Add a lock to the head of the convert or wait queue rather than the tail. + * + * DLM_LKF_NOORDER + * + * Disregard the standard grant order rules and grant a lock as soon as it + * is compatible with other granted locks. + * + * DLM_LKF_ORPHAN + * + * not yet implemented + * + * DLM_LKF_ALTPR + * + * If the requested mode cannot be granted immediately, try to grant the lock + * in PR mode instead. If this alternate mode is granted instead of the + * requested mode, DLM_SBF_ALTMODE is returned in the lksb. + * + * DLM_LKF_ALTCW + * + * The same as ALTPR, but the alternate mode is CW. + * + * DLM_LKF_FORCEUNLOCK + * + * Unlock the lock even if it is converting or waiting or has sublocks. + * Only really for use by the userland device.c code. + * + */ + +#define DLM_LKF_NOQUEUE 0x00000001 +#define DLM_LKF_CANCEL 0x00000002 +#define DLM_LKF_CONVERT 0x00000004 +#define DLM_LKF_VALBLK 0x00000008 +#define DLM_LKF_QUECVT 0x00000010 +#define DLM_LKF_IVVALBLK 0x00000020 +#define DLM_LKF_CONVDEADLK 0x00000040 +#define DLM_LKF_PERSISTENT 0x00000080 +#define DLM_LKF_NODLCKWT 0x00000100 +#define DLM_LKF_NODLCKBLK 0x00000200 +#define DLM_LKF_EXPEDITE 0x00000400 +#define DLM_LKF_NOQUEUEBAST 0x00000800 +#define DLM_LKF_HEADQUE 0x00001000 +#define DLM_LKF_NOORDER 0x00002000 +#define DLM_LKF_ORPHAN 0x00004000 +#define DLM_LKF_ALTPR 0x00008000 +#define DLM_LKF_ALTCW 0x00010000 +#define DLM_LKF_FORCEUNLOCK 0x00020000 +#define DLM_LKF_TIMEOUT 0x00040000 + +/* + * Some return codes that are not in errno.h + */ + +#define DLM_ECANCEL 0x10001 +#define DLM_EUNLOCK 0x10002 typedef void dlm_lockspace_t; diff --git a/trunk/include/linux/dlmconstants.h b/trunk/include/linux/dlmconstants.h deleted file mode 100644 index fddb3d3ff321..000000000000 --- a/trunk/include/linux/dlmconstants.h +++ /dev/null @@ -1,159 +0,0 @@ -/****************************************************************************** -******************************************************************************* -** -** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. -** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. -** -** This copyrighted material is made available to anyone wishing to use, -** modify, copy, or redistribute it subject to the terms and conditions -** of the GNU General Public License v.2. -** -******************************************************************************* -******************************************************************************/ - -#ifndef __DLMCONSTANTS_DOT_H__ -#define __DLMCONSTANTS_DOT_H__ - -/* - * Constants used by DLM interface. - */ - -/* - * Lock Modes - */ - -#define DLM_LOCK_IV (-1) /* invalid */ -#define DLM_LOCK_NL 0 /* null */ -#define DLM_LOCK_CR 1 /* concurrent read */ -#define DLM_LOCK_CW 2 /* concurrent write */ -#define DLM_LOCK_PR 3 /* protected read */ -#define DLM_LOCK_PW 4 /* protected write */ -#define DLM_LOCK_EX 5 /* exclusive */ - - -/* - * Flags to dlm_lock - * - * DLM_LKF_NOQUEUE - * - * Do not queue the lock request on the wait queue if it cannot be granted - * immediately. If the lock cannot be granted because of this flag, DLM will - * either return -EAGAIN from the dlm_lock call or will return 0 from - * dlm_lock and -EAGAIN in the lock status block when the AST is executed. - * - * DLM_LKF_CANCEL - * - * Used to cancel a pending lock request or conversion. A converting lock is - * returned to its previously granted mode. - * - * DLM_LKF_CONVERT - * - * Indicates a lock conversion request. For conversions the name and namelen - * are ignored and the lock ID in the LKSB is used to identify the lock. - * - * DLM_LKF_VALBLK - * - * Requests DLM to return the current contents of the lock value block in the - * lock status block. When this flag is set in a lock conversion from PW or EX - * modes, DLM assigns the value specified in the lock status block to the lock - * value block of the lock resource. The LVB is a DLM_LVB_LEN size array - * containing application-specific information. - * - * DLM_LKF_QUECVT - * - * Force a conversion request to be queued, even if it is compatible with - * the granted modes of other locks on the same resource. - * - * DLM_LKF_IVVALBLK - * - * Invalidate the lock value block. - * - * DLM_LKF_CONVDEADLK - * - * Allows the dlm to resolve conversion deadlocks internally by demoting the - * granted mode of a converting lock to NL. The DLM_SBF_DEMOTED flag is - * returned for a conversion that's been effected by this. - * - * DLM_LKF_PERSISTENT - * - * Only relevant to locks originating in userspace. A persistent lock will not - * be removed if the process holding the lock exits. - * - * DLM_LKF_NODLCKWT - * - * Do not cancel the lock if it gets into conversion deadlock. - * Exclude this lock from being monitored due to DLM_LSFL_TIMEWARN. - * - * DLM_LKF_NODLCKBLK - * - * net yet implemented - * - * DLM_LKF_EXPEDITE - * - * Used only with new requests for NL mode locks. Tells the lock manager - * to grant the lock, ignoring other locks in convert and wait queues. - * - * DLM_LKF_NOQUEUEBAST - * - * Send blocking AST's before returning -EAGAIN to the caller. It is only - * used along with the NOQUEUE flag. Blocking AST's are not sent for failed - * NOQUEUE requests otherwise. - * - * DLM_LKF_HEADQUE - * - * Add a lock to the head of the convert or wait queue rather than the tail. - * - * DLM_LKF_NOORDER - * - * Disregard the standard grant order rules and grant a lock as soon as it - * is compatible with other granted locks. - * - * DLM_LKF_ORPHAN - * - * not yet implemented - * - * DLM_LKF_ALTPR - * - * If the requested mode cannot be granted immediately, try to grant the lock - * in PR mode instead. If this alternate mode is granted instead of the - * requested mode, DLM_SBF_ALTMODE is returned in the lksb. - * - * DLM_LKF_ALTCW - * - * The same as ALTPR, but the alternate mode is CW. - * - * DLM_LKF_FORCEUNLOCK - * - * Unlock the lock even if it is converting or waiting or has sublocks. - * Only really for use by the userland device.c code. - * - */ - -#define DLM_LKF_NOQUEUE 0x00000001 -#define DLM_LKF_CANCEL 0x00000002 -#define DLM_LKF_CONVERT 0x00000004 -#define DLM_LKF_VALBLK 0x00000008 -#define DLM_LKF_QUECVT 0x00000010 -#define DLM_LKF_IVVALBLK 0x00000020 -#define DLM_LKF_CONVDEADLK 0x00000040 -#define DLM_LKF_PERSISTENT 0x00000080 -#define DLM_LKF_NODLCKWT 0x00000100 -#define DLM_LKF_NODLCKBLK 0x00000200 -#define DLM_LKF_EXPEDITE 0x00000400 -#define DLM_LKF_NOQUEUEBAST 0x00000800 -#define DLM_LKF_HEADQUE 0x00001000 -#define DLM_LKF_NOORDER 0x00002000 -#define DLM_LKF_ORPHAN 0x00004000 -#define DLM_LKF_ALTPR 0x00008000 -#define DLM_LKF_ALTCW 0x00010000 -#define DLM_LKF_FORCEUNLOCK 0x00020000 -#define DLM_LKF_TIMEOUT 0x00040000 - -/* - * Some return codes that are not in errno.h - */ - -#define DLM_ECANCEL 0x10001 -#define DLM_EUNLOCK 0x10002 - -#endif /* __DLMCONSTANTS_DOT_H__ */ diff --git a/trunk/include/linux/futex.h b/trunk/include/linux/futex.h index 1a15f8e237a7..92d420fe03f8 100644 --- a/trunk/include/linux/futex.h +++ b/trunk/include/linux/futex.h @@ -1,12 +1,8 @@ #ifndef _LINUX_FUTEX_H #define _LINUX_FUTEX_H -#include -#include +#include -struct inode; -struct mm_struct; -struct task_struct; union ktime; /* Second argument to futex syscall */ diff --git a/trunk/include/linux/hardirq.h b/trunk/include/linux/hardirq.h index 2961ec788046..8d302298a161 100644 --- a/trunk/include/linux/hardirq.h +++ b/trunk/include/linux/hardirq.h @@ -72,7 +72,11 @@ #define in_softirq() (softirq_count()) #define in_interrupt() (irq_count()) -#define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0) +#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL) +# define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) +#else +# define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0) +#endif #ifdef CONFIG_PREEMPT # define PREEMPT_CHECK_OFFSET 1 diff --git a/trunk/include/linux/hdreg.h b/trunk/include/linux/hdreg.h index ff43f8d6b5b3..818c6afc1091 100644 --- a/trunk/include/linux/hdreg.h +++ b/trunk/include/linux/hdreg.h @@ -44,9 +44,7 @@ /* Bits for HD_ERROR */ #define MARK_ERR 0x01 /* Bad address mark */ -#define ILI_ERR 0x01 /* Illegal Length Indication (ATAPI) */ #define TRK0_ERR 0x02 /* couldn't find track 0 */ -#define EOM_ERR 0x02 /* End Of Media (ATAPI) */ #define ABRT_ERR 0x04 /* Command aborted */ #define MCR_ERR 0x08 /* media change request */ #define ID_ERR 0x10 /* ID field not found */ @@ -54,7 +52,6 @@ #define ECC_ERR 0x40 /* Uncorrectable ECC error */ #define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ #define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ -#define LFS_ERR 0xf0 /* Last Failed Sense (ATAPI) */ /* Bits of HD_NSECTOR */ #define CD 0x01 @@ -73,13 +70,13 @@ #define HDIO_DRIVE_HOB_HDR_SIZE (8 * sizeof(__u8)) #define HDIO_DRIVE_TASK_HDR_SIZE (8 * sizeof(__u8)) -#define IDE_DRIVE_TASK_NO_DATA 0 -#ifndef __KERNEL__ #define IDE_DRIVE_TASK_INVALID -1 +#define IDE_DRIVE_TASK_NO_DATA 0 #define IDE_DRIVE_TASK_SET_XFER 1 + #define IDE_DRIVE_TASK_IN 2 + #define IDE_DRIVE_TASK_OUT 3 -#endif #define IDE_DRIVE_TASK_RAW_WRITE 4 /* @@ -90,10 +87,10 @@ #ifndef __KERNEL__ #define IDE_TASKFILE_STD_OUT_FLAGS 0xFE #define IDE_HOB_STD_OUT_FLAGS 0x3C +#endif typedef unsigned char task_ioreg_t; typedef unsigned long sata_ioreg_t; -#endif typedef union ide_reg_valid_s { unsigned all : 16; @@ -119,8 +116,8 @@ typedef union ide_reg_valid_s { } ide_reg_valid_t; typedef struct ide_task_request_s { - __u8 io_ports[8]; - __u8 hob_ports[8]; /* bytes 6 and 7 are unused */ + task_ioreg_t io_ports[8]; + task_ioreg_t hob_ports[8]; ide_reg_valid_t out_flags; ide_reg_valid_t in_flags; int data_phase; @@ -136,35 +133,36 @@ typedef struct ide_ioctl_request_s { } ide_ioctl_request_t; struct hd_drive_cmd_hdr { - __u8 command; - __u8 sector_number; - __u8 feature; - __u8 sector_count; + task_ioreg_t command; + task_ioreg_t sector_number; + task_ioreg_t feature; + task_ioreg_t sector_count; }; -#ifndef __KERNEL__ typedef struct hd_drive_task_hdr { - __u8 data; - __u8 feature; - __u8 sector_count; - __u8 sector_number; - __u8 low_cylinder; - __u8 high_cylinder; - __u8 device_head; - __u8 command; + task_ioreg_t data; + task_ioreg_t feature; + task_ioreg_t sector_count; + task_ioreg_t sector_number; + task_ioreg_t low_cylinder; + task_ioreg_t high_cylinder; + task_ioreg_t device_head; + task_ioreg_t command; } task_struct_t; typedef struct hd_drive_hob_hdr { - __u8 data; - __u8 feature; - __u8 sector_count; - __u8 sector_number; - __u8 low_cylinder; - __u8 high_cylinder; - __u8 device_head; - __u8 control; + task_ioreg_t data; + task_ioreg_t feature; + task_ioreg_t sector_count; + task_ioreg_t sector_number; + task_ioreg_t low_cylinder; + task_ioreg_t high_cylinder; + task_ioreg_t device_head; + task_ioreg_t control; } hob_struct_t; -#endif + +#define TASKFILE_INVALID 0x7fff +#define TASKFILE_48 0x8000 #define TASKFILE_NO_DATA 0x0000 @@ -180,16 +178,12 @@ typedef struct hd_drive_hob_hdr { #define TASKFILE_IN_DMAQ 0x0080 #define TASKFILE_OUT_DMAQ 0x0100 -#ifndef __KERNEL__ #define TASKFILE_P_IN 0x0200 #define TASKFILE_P_OUT 0x0400 #define TASKFILE_P_IN_DMA 0x0800 #define TASKFILE_P_OUT_DMA 0x1000 #define TASKFILE_P_IN_DMAQ 0x2000 #define TASKFILE_P_OUT_DMAQ 0x4000 -#define TASKFILE_48 0x8000 -#define TASKFILE_INVALID 0x7fff -#endif /* ATA/ATAPI Commands pre T13 Spec */ #define WIN_NOP 0x00 diff --git a/trunk/include/linux/hrtimer.h b/trunk/include/linux/hrtimer.h index 49067f14fac1..7a9398e19704 100644 --- a/trunk/include/linux/hrtimer.h +++ b/trunk/include/linux/hrtimer.h @@ -115,8 +115,10 @@ struct hrtimer { enum hrtimer_restart (*function)(struct hrtimer *); struct hrtimer_clock_base *base; unsigned long state; +#ifdef CONFIG_HIGH_RES_TIMERS enum hrtimer_cb_mode cb_mode; struct list_head cb_entry; +#endif #ifdef CONFIG_TIMER_STATS void *start_site; char start_comm[16]; @@ -192,10 +194,10 @@ struct hrtimer_cpu_base { spinlock_t lock; struct lock_class_key lock_key; struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; - struct list_head cb_pending; #ifdef CONFIG_HIGH_RES_TIMERS ktime_t expires_next; int hres_active; + struct list_head cb_pending; unsigned long nr_events; #endif }; @@ -215,11 +217,6 @@ static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer) return timer->base->get_time(); } -static inline int hrtimer_is_hres_active(struct hrtimer *timer) -{ - return timer->base->cpu_base->hres_active; -} - /* * The resolution of the clocks. The resolution value is returned in * the clock_getres() system call to give application programmers an @@ -251,10 +248,6 @@ static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer) return timer->base->softirq_time; } -static inline int hrtimer_is_hres_active(struct hrtimer *timer) -{ - return 0; -} #endif extern ktime_t ktime_get(void); @@ -317,7 +310,6 @@ extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, /* Soft interrupt function to run the hrtimer queues: */ extern void hrtimer_run_queues(void); -extern void hrtimer_run_pending(void); /* Bootup initialization: */ extern void __init hrtimers_init(void); diff --git a/trunk/include/linux/i2c-id.h b/trunk/include/linux/i2c-id.h index c7a51a196f51..e18017d45758 100644 --- a/trunk/include/linux/i2c-id.h +++ b/trunk/include/linux/i2c-id.h @@ -125,8 +125,6 @@ #define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */ #define I2C_DRIVERID_VP27SMPX 93 /* Panasonic VP27s tuner internal MPX */ #define I2C_DRIVERID_CS4270 94 /* Cirrus Logic 4270 audio codec */ -#define I2C_DRIVERID_M52790 95 /* Mitsubishi M52790SP/FP AV switch */ -#define I2C_DRIVERID_CS5345 96 /* cs5345 audio processor */ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ diff --git a/trunk/include/linux/ide.h b/trunk/include/linux/ide.h index 1e4409937ec3..9a6a41e7079f 100644 --- a/trunk/include/linux/ide.h +++ b/trunk/include/linux/ide.h @@ -27,10 +27,25 @@ #include #include -#if defined(CRIS) || defined(FRV) -# define SUPPORT_VLB_SYNC 0 -#else -# define SUPPORT_VLB_SYNC 1 +/****************************************************************************** + * IDE driver configuration options (play with these as desired): + * + * REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary + */ +#define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */ + +#ifndef SUPPORT_SLOW_DATA_PORTS /* 1 to support slow data ports */ +#define SUPPORT_SLOW_DATA_PORTS 1 /* 0 to reduce kernel size */ +#endif +#ifndef SUPPORT_VLB_SYNC /* 1 to support weird 32-bit chips */ +#define SUPPORT_VLB_SYNC 1 /* 0 to reduce kernel size */ +#endif +#ifndef OK_TO_RESET_CONTROLLER /* 1 needed for good error recovery */ +#define OK_TO_RESET_CONTROLLER 1 /* 0 for use with AH2372A/B interface */ +#endif + +#ifndef DISABLE_IRQ_NOSYNC +#define DISABLE_IRQ_NOSYNC 0 #endif /* @@ -40,6 +55,10 @@ #define IDE_NO_IRQ (-1) +/* + * "No user-serviceable parts" beyond this point :) + *****************************************************************************/ + typedef unsigned char byte; /* used everywhere */ /* @@ -84,6 +103,8 @@ typedef unsigned char byte; /* used everywhere */ #define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET #define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET +#define IDE_CONTROL_OFFSET_HOB (7) + #define IDE_DATA_REG (HWIF(drive)->io_ports[IDE_DATA_OFFSET]) #define IDE_ERROR_REG (HWIF(drive)->io_ports[IDE_ERROR_OFFSET]) #define IDE_NSECTOR_REG (HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET]) @@ -306,15 +327,46 @@ static inline void ide_init_hwif_ports(hw_regs_t *hw, typedef union { unsigned all : 8; struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned set_geometry : 1; unsigned recalibrate : 1; unsigned set_multmode : 1; unsigned set_tune : 1; unsigned serviced : 1; unsigned reserved : 3; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned reserved : 3; + unsigned serviced : 1; + unsigned set_tune : 1; + unsigned set_multmode : 1; + unsigned recalibrate : 1; + unsigned set_geometry : 1; +#else +#error "Please fix " +#endif } b; } special_t; +/* + * ATA DATA Register Special. + * ATA NSECTOR Count Register(). + * ATAPI Byte Count Register. + */ +typedef union { + unsigned all :16; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned low :8; /* LSB */ + unsigned high :8; /* MSB */ +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned high :8; /* MSB */ + unsigned low :8; /* LSB */ +#else +#error "Please fix " +#endif + } b; +} ata_nsector_t, ata_data_t, atapi_bcount_t; + /* * ATA-IDE Select Register, aka Device-Head * @@ -345,6 +397,131 @@ typedef union { } b; } select_t, ata_select_t; +/* + * The ATA-IDE Status Register. + * The ATAPI Status Register. + * + * check : Error occurred + * idx : Index Error + * corr : Correctable error occurred + * drq : Data is request by the device + * dsc : Disk Seek Complete : ata + * : Media access command finished : atapi + * df : Device Fault : ata + * : Reserved : atapi + * drdy : Ready, Command Mode Capable : ata + * : Ignored for ATAPI commands : atapi + * bsy : Disk is Busy + * : The device has access to the command block + */ +typedef union { + unsigned all :8; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned check :1; + unsigned idx :1; + unsigned corr :1; + unsigned drq :1; + unsigned dsc :1; + unsigned df :1; + unsigned drdy :1; + unsigned bsy :1; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned bsy :1; + unsigned drdy :1; + unsigned df :1; + unsigned dsc :1; + unsigned drq :1; + unsigned corr :1; + unsigned idx :1; + unsigned check :1; +#else +#error "Please fix " +#endif + } b; +} ata_status_t, atapi_status_t; + +/* + * ATAPI Feature Register + * + * dma : Using DMA or PIO + * reserved321 : Reserved + * reserved654 : Reserved (Tag Type) + * reserved7 : Reserved + */ +typedef union { + unsigned all :8; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned dma :1; + unsigned reserved321 :3; + unsigned reserved654 :3; + unsigned reserved7 :1; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned reserved7 :1; + unsigned reserved654 :3; + unsigned reserved321 :3; + unsigned dma :1; +#else +#error "Please fix " +#endif + } b; +} atapi_feature_t; + +/* + * ATAPI Interrupt Reason Register. + * + * cod : Information transferred is command (1) or data (0) + * io : The device requests us to read (1) or write (0) + * reserved : Reserved + */ +typedef union { + unsigned all :8; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned cod :1; + unsigned io :1; + unsigned reserved :6; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned reserved :6; + unsigned io :1; + unsigned cod :1; +#else +#error "Please fix " +#endif + } b; +} atapi_ireason_t; + +/* + * The ATAPI error register. + * + * ili : Illegal Length Indication + * eom : End Of Media Detected + * abrt : Aborted command - As defined by ATA + * mcr : Media Change Requested - As defined by ATA + * sense_key : Sense key of the last failed packet command + */ +typedef union { + unsigned all :8; + struct { +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned ili :1; + unsigned eom :1; + unsigned abrt :1; + unsigned mcr :1; + unsigned sense_key :4; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned sense_key :4; + unsigned mcr :1; + unsigned abrt :1; + unsigned eom :1; + unsigned ili :1; +#else +#error "Please fix " +#endif + } b; +} atapi_error_t; + /* * Status returned from various ide_ functions */ @@ -524,6 +701,8 @@ typedef struct hwif_s { void (*pre_reset)(ide_drive_t *); /* routine to reset controller after a disk reset */ void (*resetproc)(ide_drive_t *); + /* special interrupt handling for shared pci interrupts */ + void (*intrproc)(ide_drive_t *); /* special host masking for drive selection */ void (*maskproc)(ide_drive_t *, int); /* check host's drive quirk list */ @@ -587,6 +766,7 @@ typedef struct hwif_s { int rqsize; /* max sectors per request */ int irq; /* our irq number */ + unsigned long dma_master; /* reference base addr dmabase */ unsigned long dma_base; /* base addr for dma ports */ unsigned long dma_command; /* dma command register */ unsigned long dma_vendor1; /* dma vendor 1 register */ @@ -626,6 +806,7 @@ typedef struct hwif_s { /* * internal ide interrupt handler type */ +typedef ide_startstop_t (ide_pre_handler_t)(ide_drive_t *, struct request *); typedef ide_startstop_t (ide_handler_t)(ide_drive_t *); typedef int (ide_expiry_t)(ide_drive_t *); @@ -839,8 +1020,7 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq, extern void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry); -void ide_execute_command(ide_drive_t *, u8, ide_handler_t *, unsigned int, - ide_expiry_t *); +extern void ide_execute_command(ide_drive_t *, task_ioreg_t cmd, ide_handler_t *, unsigned int, ide_expiry_t *); ide_startstop_t __ide_error(ide_drive_t *, struct request *, u8, u8); @@ -882,114 +1062,52 @@ extern void ide_end_drive_cmd(ide_drive_t *, u8, u8); */ extern int ide_wait_cmd(ide_drive_t *, u8, u8, u8, u8, u8 *); -enum { - IDE_TFLAG_LBA48 = (1 << 0), - IDE_TFLAG_NO_SELECT_MASK = (1 << 1), - IDE_TFLAG_FLAGGED = (1 << 2), - IDE_TFLAG_OUT_DATA = (1 << 3), - IDE_TFLAG_OUT_HOB_FEATURE = (1 << 4), - IDE_TFLAG_OUT_HOB_NSECT = (1 << 5), - IDE_TFLAG_OUT_HOB_LBAL = (1 << 6), - IDE_TFLAG_OUT_HOB_LBAM = (1 << 7), - IDE_TFLAG_OUT_HOB_LBAH = (1 << 8), - IDE_TFLAG_OUT_HOB = IDE_TFLAG_OUT_HOB_FEATURE | - IDE_TFLAG_OUT_HOB_NSECT | - IDE_TFLAG_OUT_HOB_LBAL | - IDE_TFLAG_OUT_HOB_LBAM | - IDE_TFLAG_OUT_HOB_LBAH, - IDE_TFLAG_OUT_FEATURE = (1 << 9), - IDE_TFLAG_OUT_NSECT = (1 << 10), - IDE_TFLAG_OUT_LBAL = (1 << 11), - IDE_TFLAG_OUT_LBAM = (1 << 12), - IDE_TFLAG_OUT_LBAH = (1 << 13), - IDE_TFLAG_OUT_TF = IDE_TFLAG_OUT_FEATURE | - IDE_TFLAG_OUT_NSECT | - IDE_TFLAG_OUT_LBAL | - IDE_TFLAG_OUT_LBAM | - IDE_TFLAG_OUT_LBAH, - IDE_TFLAG_OUT_DEVICE = (1 << 14), - IDE_TFLAG_WRITE = (1 << 15), - IDE_TFLAG_FLAGGED_SET_IN_FLAGS = (1 << 16), - IDE_TFLAG_IN_DATA = (1 << 17), - IDE_TFLAG_CUSTOM_HANDLER = (1 << 18), - IDE_TFLAG_DMA_PIO_FALLBACK = (1 << 19), - IDE_TFLAG_IN_HOB_FEATURE = (1 << 20), - IDE_TFLAG_IN_HOB_NSECT = (1 << 21), - IDE_TFLAG_IN_HOB_LBAL = (1 << 22), - IDE_TFLAG_IN_HOB_LBAM = (1 << 23), - IDE_TFLAG_IN_HOB_LBAH = (1 << 24), - IDE_TFLAG_IN_HOB_LBA = IDE_TFLAG_IN_HOB_LBAL | - IDE_TFLAG_IN_HOB_LBAM | - IDE_TFLAG_IN_HOB_LBAH, - IDE_TFLAG_IN_HOB = IDE_TFLAG_IN_HOB_FEATURE | - IDE_TFLAG_IN_HOB_NSECT | - IDE_TFLAG_IN_HOB_LBA, - IDE_TFLAG_IN_NSECT = (1 << 25), - IDE_TFLAG_IN_LBAL = (1 << 26), - IDE_TFLAG_IN_LBAM = (1 << 27), - IDE_TFLAG_IN_LBAH = (1 << 28), - IDE_TFLAG_IN_LBA = IDE_TFLAG_IN_LBAL | - IDE_TFLAG_IN_LBAM | - IDE_TFLAG_IN_LBAH, - IDE_TFLAG_IN_TF = IDE_TFLAG_IN_NSECT | - IDE_TFLAG_IN_LBA, - IDE_TFLAG_IN_DEVICE = (1 << 29), -}; - -struct ide_taskfile { - u8 hob_data; /* 0: high data byte (for TASKFILE IOCTL) */ - - u8 hob_feature; /* 1-5: additional data to support LBA48 */ - u8 hob_nsect; - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; - - u8 data; /* 6: low data byte (for TASKFILE IOCTL) */ - - union { /*  7: */ - u8 error; /* read: error */ - u8 feature; /* write: feature */ - }; - - u8 nsect; /* 8: number of sectors */ - u8 lbal; /* 9: LBA low */ - u8 lbam; /* 10: LBA mid */ - u8 lbah; /* 11: LBA high */ - - u8 device; /* 12: device select */ - - union { /* 13: */ - u8 status; /*  read: status  */ - u8 command; /* write: command */ - }; -}; - typedef struct ide_task_s { - union { - struct ide_taskfile tf; - u8 tf_array[14]; - }; - u32 tf_flags; +/* + * struct hd_drive_task_hdr tf; + * task_struct_t tf; + * struct hd_drive_hob_hdr hobf; + * hob_struct_t hobf; + */ + task_ioreg_t tfRegister[8]; + task_ioreg_t hobRegister[8]; + ide_reg_valid_t tf_out_flags; + ide_reg_valid_t tf_in_flags; int data_phase; + int command_type; + ide_pre_handler_t *prehandler; + ide_handler_t *handler; struct request *rq; /* copy of request */ void *special; /* valid_t generally */ } ide_task_t; -void ide_tf_load(ide_drive_t *, ide_task_t *); -void ide_tf_read(ide_drive_t *, ide_task_t *); +extern u32 ide_read_24(ide_drive_t *); extern void SELECT_DRIVE(ide_drive_t *); +extern void SELECT_INTERRUPT(ide_drive_t *); extern void SELECT_MASK(ide_drive_t *, int); +extern void QUIRK_LIST(ide_drive_t *); extern int drive_is_ready(ide_drive_t *); -void ide_pktcmd_tf_load(ide_drive_t *, u32, u16, u8); +/* + * taskfile io for disks for now...and builds request from ide_ioctl + */ +extern ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *); + +/* + * Special Flagged Register Validation Caller + */ +extern ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *); -ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *); +extern ide_startstop_t set_multmode_intr(ide_drive_t *); +extern ide_startstop_t set_geometry_intr(ide_drive_t *); +extern ide_startstop_t recal_intr(ide_drive_t *); +extern ide_startstop_t task_no_data_intr(ide_drive_t *); +extern ide_startstop_t task_in_intr(ide_drive_t *); +extern ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); -int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *, u16); -int ide_no_data_taskfile(ide_drive_t *, ide_task_t *); +extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *); int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long); int ide_cmd_ioctl(ide_drive_t *, unsigned int, unsigned long); @@ -1094,7 +1212,6 @@ enum { IDE_HFLAG_IO_32BIT = (1 << 24), /* unmask IRQs */ IDE_HFLAG_UNMASK_IRQS = (1 << 25), - IDE_HFLAG_ABUSE_SET_DMA_MODE = (1 << 26), }; #ifdef CONFIG_BLK_DEV_OFFBOARD @@ -1112,7 +1229,7 @@ struct ide_port_info { void (*fixup)(ide_hwif_t *); ide_pci_enablebit_t enablebits[2]; hwif_chipset_t chipset; - u8 extra; + unsigned int extra; u32 host_flags; u8 pio_mask; u8 swdma_mask; @@ -1239,7 +1356,6 @@ static inline int ide_dev_is_sata(struct hd_driveid *id) return 0; } -u64 ide_get_lba_addr(struct ide_taskfile *, int); u8 ide_dump_status(ide_drive_t *, const char *, u8); typedef struct ide_pio_timings_s { diff --git a/trunk/include/linux/init_task.h b/trunk/include/linux/init_task.h index 796019b22b6f..cae35b6b9aec 100644 --- a/trunk/include/linux/init_task.h +++ b/trunk/include/linux/init_task.h @@ -132,12 +132,9 @@ extern struct group_info init_groups; .cpus_allowed = CPU_MASK_ALL, \ .mm = NULL, \ .active_mm = &init_mm, \ - .rt = { \ - .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \ - .time_slice = HZ, \ - .nr_cpus_allowed = NR_CPUS, \ - }, \ + .run_list = LIST_HEAD_INIT(tsk.run_list), \ .ioprio = 0, \ + .time_slice = HZ, \ .tasks = LIST_HEAD_INIT(tsk.tasks), \ .ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children), \ .ptrace_list = LIST_HEAD_INIT(tsk.ptrace_list), \ diff --git a/trunk/include/linux/interrupt.h b/trunk/include/linux/interrupt.h index c3db4a00f1fa..2306920fa388 100644 --- a/trunk/include/linux/interrupt.h +++ b/trunk/include/linux/interrupt.h @@ -256,7 +256,6 @@ enum #ifdef CONFIG_HIGH_RES_TIMERS HRTIMER_SOFTIRQ, #endif - RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ }; /* softirq mask and active fields moved to irq_cpustat_t in diff --git a/trunk/include/linux/jiffies.h b/trunk/include/linux/jiffies.h index 7ba9e47bf061..8b080024bbc1 100644 --- a/trunk/include/linux/jiffies.h +++ b/trunk/include/linux/jiffies.h @@ -29,12 +29,6 @@ # define SHIFT_HZ 9 #elif HZ >= 768 && HZ < 1536 # define SHIFT_HZ 10 -#elif HZ >= 1536 && HZ < 3072 -# define SHIFT_HZ 11 -#elif HZ >= 3072 && HZ < 6144 -# define SHIFT_HZ 12 -#elif HZ >= 6144 && HZ < 12288 -# define SHIFT_HZ 13 #else # error You lose. #endif diff --git a/trunk/include/linux/kernel.h b/trunk/include/linux/kernel.h index a7283c9beadf..94bc99656963 100644 --- a/trunk/include/linux/kernel.h +++ b/trunk/include/linux/kernel.h @@ -105,8 +105,8 @@ struct user; * supposed to. */ #ifdef CONFIG_PREEMPT_VOLUNTARY -extern int _cond_resched(void); -# define might_resched() _cond_resched() +extern int cond_resched(void); +# define might_resched() cond_resched() #else # define might_resched() do { } while (0) #endif diff --git a/trunk/include/linux/latencytop.h b/trunk/include/linux/latencytop.h deleted file mode 100644 index 901c2d6377a8..000000000000 --- a/trunk/include/linux/latencytop.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * latencytop.h: Infrastructure for displaying latency - * - * (C) Copyright 2008 Intel Corporation - * Author: Arjan van de Ven - * - */ - -#ifndef _INCLUDE_GUARD_LATENCYTOP_H_ -#define _INCLUDE_GUARD_LATENCYTOP_H_ - -#ifdef CONFIG_LATENCYTOP - -#define LT_SAVECOUNT 32 -#define LT_BACKTRACEDEPTH 12 - -struct latency_record { - unsigned long backtrace[LT_BACKTRACEDEPTH]; - unsigned int count; - unsigned long time; - unsigned long max; -}; - - -struct task_struct; - -void account_scheduler_latency(struct task_struct *task, int usecs, int inter); - -void clear_all_latency_tracing(struct task_struct *p); - -#else - -static inline void -account_scheduler_latency(struct task_struct *task, int usecs, int inter) -{ -} - -static inline void clear_all_latency_tracing(struct task_struct *p) -{ -} - -#endif - -#endif diff --git a/trunk/include/linux/libata.h b/trunk/include/linux/libata.h index 4374c4277780..124033cb5e9b 100644 --- a/trunk/include/linux/libata.h +++ b/trunk/include/linux/libata.h @@ -35,7 +35,6 @@ #include #include #include -#include /* * Define if arch has non-standard setup. This is a _PCI_ standard @@ -144,11 +143,10 @@ enum { ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ - ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ - ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + ATA_DFLAG_INIT_MASK = (1 << 16) - 1, - ATA_DFLAG_DETACH = (1 << 24), - ATA_DFLAG_DETACHED = (1 << 25), + ATA_DFLAG_DETACH = (1 << 16), + ATA_DFLAG_DETACHED = (1 << 17), ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -219,7 +217,9 @@ enum { /* struct ata_queued_cmd flags */ ATA_QCFLAG_ACTIVE = (1 << 0), /* cmd not yet ack'd to scsi lyer */ - ATA_QCFLAG_DMAMAP = (1 << 1), /* SG table is DMA mapped */ + ATA_QCFLAG_SG = (1 << 1), /* have s/g table? */ + ATA_QCFLAG_SINGLE = (1 << 2), /* no s/g, just a single buffer */ + ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE, ATA_QCFLAG_IO = (1 << 3), /* standard IO command */ ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */ @@ -266,15 +266,19 @@ enum { PORT_DISABLED = 2, /* encoding various smaller bitmaps into a single - * unsigned long bitmap + * unsigned int bitmap */ - ATA_NR_PIO_MODES = 7, - ATA_NR_MWDMA_MODES = 5, - ATA_NR_UDMA_MODES = 8, + ATA_BITS_PIO = 7, + ATA_BITS_MWDMA = 5, + ATA_BITS_UDMA = 8, ATA_SHIFT_PIO = 0, - ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, - ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_BITS_PIO, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_BITS_MWDMA, + + ATA_MASK_PIO = ((1 << ATA_BITS_PIO) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1 << ATA_BITS_MWDMA) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1 << ATA_BITS_UDMA) - 1) << ATA_SHIFT_UDMA, /* size of buffer to pad xfers ending on unaligned boundaries */ ATA_DMA_PAD_SZ = 4, @@ -345,21 +349,6 @@ enum { ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */ ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */ ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */ - - /* ATAPI command types */ - ATAPI_READ = 0, /* READs */ - ATAPI_WRITE = 1, /* WRITEs */ - ATAPI_READ_CD = 2, /* READ CD [MSF] */ - ATAPI_MISC = 3, /* the rest */ -}; - -enum ata_xfer_mask { - ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) - << ATA_SHIFT_PIO, - ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) - << ATA_SHIFT_MWDMA, - ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) - << ATA_SHIFT_UDMA, }; enum hsm_task_states { @@ -458,7 +447,7 @@ struct ata_queued_cmd { unsigned int tag; unsigned int n_elem; unsigned int n_iter; - unsigned int mapped_n_elem; + unsigned int orig_n_elem; int dma_dir; @@ -466,18 +455,17 @@ struct ata_queued_cmd { unsigned int sect_size; unsigned int nbytes; - unsigned int raw_nbytes; unsigned int curbytes; struct scatterlist *cursg; unsigned int cursg_ofs; - struct scatterlist *last_sg; - struct scatterlist saved_last_sg; struct scatterlist sgent; - struct scatterlist extra_sg[2]; + struct scatterlist pad_sgent; + void *buf_virt; - struct scatterlist *sg; + /* DO NOT iterate over __sg manually, use ata_for_each_sg() */ + struct scatterlist *__sg; unsigned int err_mask; struct ata_taskfile result_tf; @@ -494,7 +482,7 @@ struct ata_port_stats { }; struct ata_ering_entry { - unsigned int eflags; + int is_io; unsigned int err_mask; u64 timestamp; }; @@ -534,9 +522,9 @@ struct ata_device { unsigned int cdb_len; /* per-dev xfer mask */ - unsigned long pio_mask; - unsigned long mwdma_mask; - unsigned long udma_mask; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; /* for CHS addressing */ u16 cylinders; /* Number of cylinders */ @@ -572,8 +560,6 @@ struct ata_eh_context { int tries[ATA_MAX_DEVICES]; unsigned int classes[ATA_MAX_DEVICES]; unsigned int did_probe_mask; - unsigned int saved_ncq_enabled; - u8 saved_xfer_mode[ATA_MAX_DEVICES]; }; struct ata_acpi_drive @@ -700,8 +686,7 @@ struct ata_port_operations { void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc); - unsigned int (*data_xfer) (struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int rw); + void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int); int (*qc_defer) (struct ata_queued_cmd *qc); void (*qc_prep) (struct ata_queued_cmd *qc); @@ -847,6 +832,8 @@ extern int ata_busy_sleep(struct ata_port *ap, unsigned long timeout_pat, unsigned long timeout); extern void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline); extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline); +extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn, + void *data, unsigned long delay); extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, unsigned long interval_msec, unsigned long timeout_msec); @@ -861,16 +848,6 @@ extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis); extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf); -extern unsigned long ata_pack_xfermask(unsigned long pio_mask, - unsigned long mwdma_mask, unsigned long udma_mask); -extern void ata_unpack_xfermask(unsigned long xfer_mask, - unsigned long *pio_mask, unsigned long *mwdma_mask, - unsigned long *udma_mask); -extern u8 ata_xfer_mask2mode(unsigned long xfer_mask); -extern unsigned long ata_xfer_mode2mask(u8 xfer_mode); -extern int ata_xfer_mode2shift(unsigned long xfer_mode); -extern const char *ata_mode_string(unsigned long xfer_mask); -extern unsigned long ata_id_xfermask(const u16 *id); extern void ata_noop_dev_select(struct ata_port *ap, unsigned int device); extern void ata_std_dev_select(struct ata_port *ap, unsigned int device); extern u8 ata_check_status(struct ata_port *ap); @@ -879,15 +856,17 @@ extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) extern int ata_port_start(struct ata_port *ap); extern int ata_sff_port_start(struct ata_port *ap); extern irqreturn_t ata_interrupt(int irq, void *dev_instance); -extern unsigned int ata_data_xfer(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw); -extern unsigned int ata_data_xfer_noirq(struct ata_device *dev, - unsigned char *buf, unsigned int buflen, int rw); +extern void ata_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data); +extern void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data); extern int ata_std_qc_defer(struct ata_queued_cmd *qc); extern void ata_dumb_qc_prep(struct ata_queued_cmd *qc); extern void ata_qc_prep(struct ata_queued_cmd *qc); extern void ata_noop_qc_prep(struct ata_queued_cmd *qc); extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +extern void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, + unsigned int buflen); extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem); extern unsigned int ata_dev_classify(const struct ata_taskfile *tf); @@ -896,6 +875,7 @@ extern void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); +extern void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown); extern void ata_bmdma_setup(struct ata_queued_cmd *qc); extern void ata_bmdma_start(struct ata_queued_cmd *qc); extern void ata_bmdma_stop(struct ata_queued_cmd *qc); @@ -930,7 +910,6 @@ extern u8 ata_irq_on(struct ata_port *ap); extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap); extern int ata_cable_sata(struct ata_port *ap); -extern int ata_cable_ignore(struct ata_port *ap); extern int ata_cable_unknown(struct ata_port *ap); /* @@ -938,13 +917,11 @@ extern int ata_cable_unknown(struct ata_port *ap); */ extern unsigned int ata_pio_need_iordy(const struct ata_device *); -extern const struct ata_timing *ata_timing_find_mode(u8 xfer_mode); extern int ata_timing_compute(struct ata_device *, unsigned short, struct ata_timing *, int, int); extern void ata_timing_merge(const struct ata_timing *, const struct ata_timing *, struct ata_timing *, unsigned int); -extern u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle); enum { ATA_TIMING_SETUP = (1 << 0), @@ -971,40 +948,15 @@ static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap) return &ap->__acpi_init_gtm; return NULL; } +extern int ata_acpi_cbl_80wire(struct ata_port *ap); int ata_acpi_stm(struct ata_port *ap, const struct ata_acpi_gtm *stm); int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm); -unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev, - const struct ata_acpi_gtm *gtm); -int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm); #else static inline const struct ata_acpi_gtm *ata_acpi_init_gtm(struct ata_port *ap) { return NULL; } - -static inline int ata_acpi_stm(const struct ata_port *ap, - struct ata_acpi_gtm *stm) -{ - return -ENOSYS; -} - -static inline int ata_acpi_gtm(const struct ata_port *ap, - struct ata_acpi_gtm *stm) -{ - return -ENOSYS; -} - -static inline unsigned int ata_acpi_gtm_xfermask(struct ata_device *dev, - const struct ata_acpi_gtm *gtm) -{ - return 0; -} - -static inline int ata_acpi_cbl_80wire(struct ata_port *ap, - const struct ata_acpi_gtm *gtm) -{ - return 0; -} +static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } #endif #ifdef CONFIG_PCI @@ -1033,12 +985,8 @@ extern int ata_pci_init_bmdma(struct ata_host *host); extern int ata_pci_prepare_sff_host(struct pci_dev *pdev, const struct ata_port_info * const * ppi, struct ata_host **r_host); -extern int ata_pci_activate_sff_host(struct ata_host *host, - irq_handler_t irq_handler, - struct scsi_host_template *sht); extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); -extern unsigned long ata_pci_default_filter(struct ata_device *dev, - unsigned long xfer_mask); +extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long); #endif /* CONFIG_PCI */ /* @@ -1126,6 +1074,35 @@ extern void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, const char *name); #endif +/* + * qc helpers + */ +static inline struct scatterlist * +ata_qc_first_sg(struct ata_queued_cmd *qc) +{ + qc->n_iter = 0; + if (qc->n_elem) + return qc->__sg; + if (qc->pad_len) + return &qc->pad_sgent; + return NULL; +} + +static inline struct scatterlist * +ata_qc_next_sg(struct scatterlist *sg, struct ata_queued_cmd *qc) +{ + if (sg == &qc->pad_sgent) + return NULL; + if (++qc->n_iter < qc->n_elem) + return sg_next(sg); + if (qc->pad_len) + return &qc->pad_sgent; + return NULL; +} + +#define ata_for_each_sg(sg, qc) \ + for (sg = ata_qc_first_sg(qc); sg; sg = ata_qc_next_sg(sg, qc)) + static inline unsigned int ata_tag_valid(unsigned int tag) { return (tag < ATA_MAX_QUEUE) ? 1 : 0; @@ -1360,17 +1337,15 @@ static inline void ata_tf_init(struct ata_device *dev, struct ata_taskfile *tf) static inline void ata_qc_reinit(struct ata_queued_cmd *qc) { qc->dma_dir = DMA_NONE; - qc->sg = NULL; + qc->__sg = NULL; qc->flags = 0; qc->cursg = NULL; qc->cursg_ofs = 0; - qc->nbytes = qc->raw_nbytes = qc->curbytes = 0; + qc->nbytes = qc->curbytes = 0; qc->n_elem = 0; - qc->mapped_n_elem = 0; qc->n_iter = 0; qc->err_mask = 0; qc->pad_len = 0; - qc->last_sg = NULL; qc->sect_size = ATA_SECT_SIZE; ata_tf_init(qc->dev, &qc->tf); @@ -1387,27 +1362,6 @@ static inline int ata_try_flush_cache(const struct ata_device *dev) ata_id_has_flush_ext(dev->id); } -static inline int atapi_cmd_type(u8 opcode) -{ - switch (opcode) { - case GPCMD_READ_10: - case GPCMD_READ_12: - return ATAPI_READ; - - case GPCMD_WRITE_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_10: - return ATAPI_WRITE; - - case GPCMD_READ_CD: - case GPCMD_READ_CD_MSF: - return ATAPI_READ_CD; - - default: - return ATAPI_MISC; - } -} - static inline unsigned int ac_err_mask(u8 status) { if (status & (ATA_BUSY | ATA_DRQ)) diff --git a/trunk/include/linux/notifier.h b/trunk/include/linux/notifier.h index 5dfbc684ce7d..0c40cc0b4a36 100644 --- a/trunk/include/linux/notifier.h +++ b/trunk/include/linux/notifier.h @@ -207,7 +207,9 @@ static inline int notifier_to_errno(int ret) #define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ #define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ #define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ -#define CPU_DYING 0x0008 /* CPU (unsigned)v not running any task, +#define CPU_LOCK_ACQUIRE 0x0008 /* Acquire all hotcpu locks */ +#define CPU_LOCK_RELEASE 0x0009 /* Release all hotcpu locks */ +#define CPU_DYING 0x000A /* CPU (unsigned)v not running any task, * not handling interrupts, soon dead */ /* Used for CPU hotplug events occuring while tasks are frozen due to a suspend diff --git a/trunk/include/linux/pci_ids.h b/trunk/include/linux/pci_ids.h index 1fbd0256e86b..7f2215139e9a 100644 --- a/trunk/include/linux/pci_ids.h +++ b/trunk/include/linux/pci_ids.h @@ -2066,9 +2066,6 @@ #define PCI_VENDOR_ID_NETCELL 0x169c #define PCI_DEVICE_ID_REVOLUTION 0x0044 -#define PCI_VENDOR_ID_CENATEK 0x16CA -#define PCI_DEVICE_ID_CENATEK_IDE 0x0001 - #define PCI_VENDOR_ID_VITESSE 0x1725 #define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174 diff --git a/trunk/include/linux/rcuclassic.h b/trunk/include/linux/rcuclassic.h deleted file mode 100644 index 4d6624260b4c..000000000000 --- a/trunk/include/linux/rcuclassic.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion (classic version) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2001 - * - * Author: Dipankar Sarma - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU - * - */ - -#ifndef __LINUX_RCUCLASSIC_H -#define __LINUX_RCUCLASSIC_H - -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include - - -/* Global control variables for rcupdate callback mechanism. */ -struct rcu_ctrlblk { - long cur; /* Current batch number. */ - long completed; /* Number of the last completed batch */ - int next_pending; /* Is the next batch already waiting? */ - - int signaled; - - spinlock_t lock ____cacheline_internodealigned_in_smp; - cpumask_t cpumask; /* CPUs that need to switch in order */ - /* for current batch to proceed. */ -} ____cacheline_internodealigned_in_smp; - -/* Is batch a before batch b ? */ -static inline int rcu_batch_before(long a, long b) -{ - return (a - b) < 0; -} - -/* Is batch a after batch b ? */ -static inline int rcu_batch_after(long a, long b) -{ - return (a - b) > 0; -} - -/* - * Per-CPU data for Read-Copy UPdate. - * nxtlist - new callbacks are added here - * curlist - current batch for which quiescent cycle started if any - */ -struct rcu_data { - /* 1) quiescent state handling : */ - long quiescbatch; /* Batch # for grace period */ - int passed_quiesc; /* User-mode/idle loop etc. */ - int qs_pending; /* core waits for quiesc state */ - - /* 2) batch handling */ - long batch; /* Batch # for current RCU batch */ - struct rcu_head *nxtlist; - struct rcu_head **nxttail; - long qlen; /* # of queued callbacks */ - struct rcu_head *curlist; - struct rcu_head **curtail; - struct rcu_head *donelist; - struct rcu_head **donetail; - long blimit; /* Upper limit on a processed batch */ - int cpu; - struct rcu_head barrier; -}; - -DECLARE_PER_CPU(struct rcu_data, rcu_data); -DECLARE_PER_CPU(struct rcu_data, rcu_bh_data); - -/* - * Increment the quiescent state counter. - * The counter is a bit degenerated: We do not need to know - * how many quiescent states passed, just if there was at least - * one since the start of the grace period. Thus just a flag. - */ -static inline void rcu_qsctr_inc(int cpu) -{ - struct rcu_data *rdp = &per_cpu(rcu_data, cpu); - rdp->passed_quiesc = 1; -} -static inline void rcu_bh_qsctr_inc(int cpu) -{ - struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); - rdp->passed_quiesc = 1; -} - -extern int rcu_pending(int cpu); -extern int rcu_needs_cpu(int cpu); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -extern struct lockdep_map rcu_lock_map; -# define rcu_read_acquire() \ - lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_) -# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_) -#else -# define rcu_read_acquire() do { } while (0) -# define rcu_read_release() do { } while (0) -#endif - -#define __rcu_read_lock() \ - do { \ - preempt_disable(); \ - __acquire(RCU); \ - rcu_read_acquire(); \ - } while (0) -#define __rcu_read_unlock() \ - do { \ - rcu_read_release(); \ - __release(RCU); \ - preempt_enable(); \ - } while (0) -#define __rcu_read_lock_bh() \ - do { \ - local_bh_disable(); \ - __acquire(RCU_BH); \ - rcu_read_acquire(); \ - } while (0) -#define __rcu_read_unlock_bh() \ - do { \ - rcu_read_release(); \ - __release(RCU_BH); \ - local_bh_enable(); \ - } while (0) - -#define __synchronize_sched() synchronize_rcu() - -extern void __rcu_init(void); -extern void rcu_check_callbacks(int cpu, int user); -extern void rcu_restart_cpu(int cpu); - -extern long rcu_batches_completed(void); -extern long rcu_batches_completed_bh(void); - -#endif /* __KERNEL__ */ -#endif /* __LINUX_RCUCLASSIC_H */ diff --git a/trunk/include/linux/rcupdate.h b/trunk/include/linux/rcupdate.h index d32c14de270e..cc24a01df940 100644 --- a/trunk/include/linux/rcupdate.h +++ b/trunk/include/linux/rcupdate.h @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * Copyright IBM Corporation, 2001 + * Copyright (C) IBM Corporation, 2001 * * Author: Dipankar Sarma * @@ -53,18 +53,96 @@ struct rcu_head { void (*func)(struct rcu_head *head); }; -#ifdef CONFIG_CLASSIC_RCU -#include -#else /* #ifdef CONFIG_CLASSIC_RCU */ -#include -#endif /* #else #ifdef CONFIG_CLASSIC_RCU */ - #define RCU_HEAD_INIT { .next = NULL, .func = NULL } #define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT #define INIT_RCU_HEAD(ptr) do { \ (ptr)->next = NULL; (ptr)->func = NULL; \ } while (0) + + +/* Global control variables for rcupdate callback mechanism. */ +struct rcu_ctrlblk { + long cur; /* Current batch number. */ + long completed; /* Number of the last completed batch */ + int next_pending; /* Is the next batch already waiting? */ + + int signaled; + + spinlock_t lock ____cacheline_internodealigned_in_smp; + cpumask_t cpumask; /* CPUs that need to switch in order */ + /* for current batch to proceed. */ +} ____cacheline_internodealigned_in_smp; + +/* Is batch a before batch b ? */ +static inline int rcu_batch_before(long a, long b) +{ + return (a - b) < 0; +} + +/* Is batch a after batch b ? */ +static inline int rcu_batch_after(long a, long b) +{ + return (a - b) > 0; +} + +/* + * Per-CPU data for Read-Copy UPdate. + * nxtlist - new callbacks are added here + * curlist - current batch for which quiescent cycle started if any + */ +struct rcu_data { + /* 1) quiescent state handling : */ + long quiescbatch; /* Batch # for grace period */ + int passed_quiesc; /* User-mode/idle loop etc. */ + int qs_pending; /* core waits for quiesc state */ + + /* 2) batch handling */ + long batch; /* Batch # for current RCU batch */ + struct rcu_head *nxtlist; + struct rcu_head **nxttail; + long qlen; /* # of queued callbacks */ + struct rcu_head *curlist; + struct rcu_head **curtail; + struct rcu_head *donelist; + struct rcu_head **donetail; + long blimit; /* Upper limit on a processed batch */ + int cpu; + struct rcu_head barrier; +}; + +DECLARE_PER_CPU(struct rcu_data, rcu_data); +DECLARE_PER_CPU(struct rcu_data, rcu_bh_data); + +/* + * Increment the quiescent state counter. + * The counter is a bit degenerated: We do not need to know + * how many quiescent states passed, just if there was at least + * one since the start of the grace period. Thus just a flag. + */ +static inline void rcu_qsctr_inc(int cpu) +{ + struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + rdp->passed_quiesc = 1; +} +static inline void rcu_bh_qsctr_inc(int cpu) +{ + struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); + rdp->passed_quiesc = 1; +} + +extern int rcu_pending(int cpu); +extern int rcu_needs_cpu(int cpu); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +extern struct lockdep_map rcu_lock_map; +# define rcu_read_acquire() lock_acquire(&rcu_lock_map, 0, 0, 2, 1, _THIS_IP_) +# define rcu_read_release() lock_release(&rcu_lock_map, 1, _THIS_IP_) +#else +# define rcu_read_acquire() do { } while (0) +# define rcu_read_release() do { } while (0) +#endif + /** * rcu_read_lock - mark the beginning of an RCU read-side critical section. * @@ -94,13 +172,24 @@ struct rcu_head { * * It is illegal to block while in an RCU read-side critical section. */ -#define rcu_read_lock() __rcu_read_lock() +#define rcu_read_lock() \ + do { \ + preempt_disable(); \ + __acquire(RCU); \ + rcu_read_acquire(); \ + } while(0) /** * rcu_read_unlock - marks the end of an RCU read-side critical section. * * See rcu_read_lock() for more information. */ +#define rcu_read_unlock() \ + do { \ + rcu_read_release(); \ + __release(RCU); \ + preempt_enable(); \ + } while(0) /* * So where is rcu_write_lock()? It does not exist, as there is no @@ -111,7 +200,6 @@ struct rcu_head { * used as well. RCU does not care how the writers keep out of each * others' way, as long as they do so. */ -#define rcu_read_unlock() __rcu_read_unlock() /** * rcu_read_lock_bh - mark the beginning of a softirq-only RCU critical section @@ -124,14 +212,24 @@ struct rcu_head { * can use just rcu_read_lock(). * */ -#define rcu_read_lock_bh() __rcu_read_lock_bh() +#define rcu_read_lock_bh() \ + do { \ + local_bh_disable(); \ + __acquire(RCU_BH); \ + rcu_read_acquire(); \ + } while(0) /* * rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section * * See rcu_read_lock_bh() for more information. */ -#define rcu_read_unlock_bh() __rcu_read_unlock_bh() +#define rcu_read_unlock_bh() \ + do { \ + rcu_read_release(); \ + __release(RCU_BH); \ + local_bh_enable(); \ + } while(0) /* * Prevent the compiler from merging or refetching accesses. The compiler @@ -195,52 +293,21 @@ struct rcu_head { * In "classic RCU", these two guarantees happen to be one and * the same, but can differ in realtime RCU implementations. */ -#define synchronize_sched() __synchronize_sched() - -/** - * call_rcu - Queue an RCU callback for invocation after a grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual update function to be invoked after the grace period - * - * The update function will be invoked some time after a full grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. RCU read-side critical - * sections are delimited by rcu_read_lock() and rcu_read_unlock(), - * and may be nested. - */ -extern void call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *head)); - -/** - * call_rcu_bh - Queue an RCU for invocation after a quicker grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual update function to be invoked after the grace period - * - * The update function will be invoked some time after a full grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. call_rcu_bh() assumes - * that the read-side critical sections end on completion of a softirq - * handler. This means that read-side critical sections in process - * context must not be interrupted by softirqs. This interface is to be - * used when most of the read-side critical sections are in softirq context. - * RCU read-side critical sections are delimited by : - * - rcu_read_lock() and rcu_read_unlock(), if in interrupt context. - * OR - * - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context. - * These may be nested. - */ -extern void call_rcu_bh(struct rcu_head *head, - void (*func)(struct rcu_head *head)); +#define synchronize_sched() synchronize_rcu() -/* Exported common interfaces */ -extern void synchronize_rcu(void); -extern void rcu_barrier(void); +extern void rcu_init(void); +extern void rcu_check_callbacks(int cpu, int user); +extern void rcu_restart_cpu(int cpu); extern long rcu_batches_completed(void); extern long rcu_batches_completed_bh(void); -/* Internal to kernel */ -extern void rcu_init(void); -extern int rcu_needs_cpu(int cpu); +/* Exported interfaces */ +extern void FASTCALL(call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *head))); +extern void FASTCALL(call_rcu_bh(struct rcu_head *head, + void (*func)(struct rcu_head *head))); +extern void synchronize_rcu(void); +extern void rcu_barrier(void); #endif /* __KERNEL__ */ #endif /* __LINUX_RCUPDATE_H */ diff --git a/trunk/include/linux/rcupreempt.h b/trunk/include/linux/rcupreempt.h deleted file mode 100644 index ece8eb3e4151..000000000000 --- a/trunk/include/linux/rcupreempt.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion (RT implementation) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2006 - * - * Author: Paul McKenney - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU - * - */ - -#ifndef __LINUX_RCUPREEMPT_H -#define __LINUX_RCUPREEMPT_H - -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include - -#define rcu_qsctr_inc(cpu) -#define rcu_bh_qsctr_inc(cpu) -#define call_rcu_bh(head, rcu) call_rcu(head, rcu) - -extern void __rcu_read_lock(void); -extern void __rcu_read_unlock(void); -extern int rcu_pending(int cpu); -extern int rcu_needs_cpu(int cpu); - -#define __rcu_read_lock_bh() { rcu_read_lock(); local_bh_disable(); } -#define __rcu_read_unlock_bh() { local_bh_enable(); rcu_read_unlock(); } - -extern void __synchronize_sched(void); - -extern void __rcu_init(void); -extern void rcu_check_callbacks(int cpu, int user); -extern void rcu_restart_cpu(int cpu); -extern long rcu_batches_completed(void); - -/* - * Return the number of RCU batches processed thus far. Useful for debug - * and statistic. The _bh variant is identifcal to straight RCU - */ -static inline long rcu_batches_completed_bh(void) -{ - return rcu_batches_completed(); -} - -#ifdef CONFIG_RCU_TRACE -struct rcupreempt_trace; -extern long *rcupreempt_flipctr(int cpu); -extern long rcupreempt_data_completed(void); -extern int rcupreempt_flip_flag(int cpu); -extern int rcupreempt_mb_flag(int cpu); -extern char *rcupreempt_try_flip_state_name(void); -extern struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu); -#endif - -struct softirq_action; - -#endif /* __KERNEL__ */ -#endif /* __LINUX_RCUPREEMPT_H */ diff --git a/trunk/include/linux/rcupreempt_trace.h b/trunk/include/linux/rcupreempt_trace.h deleted file mode 100644 index 21cd6b2a5c42..000000000000 --- a/trunk/include/linux/rcupreempt_trace.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion (RT implementation) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2006 - * - * Author: Paul McKenney - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of the Preemptible Read-Copy Update mechanism see - - * http://lwn.net/Articles/253651/ - */ - -#ifndef __LINUX_RCUPREEMPT_TRACE_H -#define __LINUX_RCUPREEMPT_TRACE_H - -#ifdef __KERNEL__ -#include -#include - -#include - -/* - * PREEMPT_RCU data structures. - */ - -struct rcupreempt_trace { - long next_length; - long next_add; - long wait_length; - long wait_add; - long done_length; - long done_add; - long done_remove; - atomic_t done_invoked; - long rcu_check_callbacks; - atomic_t rcu_try_flip_1; - atomic_t rcu_try_flip_e1; - long rcu_try_flip_i1; - long rcu_try_flip_ie1; - long rcu_try_flip_g1; - long rcu_try_flip_a1; - long rcu_try_flip_ae1; - long rcu_try_flip_a2; - long rcu_try_flip_z1; - long rcu_try_flip_ze1; - long rcu_try_flip_z2; - long rcu_try_flip_m1; - long rcu_try_flip_me1; - long rcu_try_flip_m2; -}; - -#ifdef CONFIG_RCU_TRACE -#define RCU_TRACE(fn, arg) fn(arg); -#else -#define RCU_TRACE(fn, arg) -#endif - -extern void rcupreempt_trace_move2done(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_invoke(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_next_add(struct rcupreempt_trace *trace); - -#endif /* __KERNEL__ */ -#endif /* __LINUX_RCUPREEMPT_TRACE_H */ diff --git a/trunk/include/linux/sched.h b/trunk/include/linux/sched.h index df5b24ee80b3..d6eacda765ca 100644 --- a/trunk/include/linux/sched.h +++ b/trunk/include/linux/sched.h @@ -78,6 +78,7 @@ struct sched_param { #include #include #include +#include #include #include @@ -87,13 +88,11 @@ struct sched_param { #include #include #include -#include #include struct exec_domain; struct futex_pi_state; -struct robust_list_head; struct bio; /* @@ -231,8 +230,6 @@ static inline int select_nohz_load_balancer(int cpu) } #endif -extern unsigned long rt_needs_cpu(int cpu); - /* * Only dump TASK_* tasks. (0 for all tasks) */ @@ -260,19 +257,13 @@ extern void trap_init(void); extern void account_process_tick(struct task_struct *task, int user); extern void update_process_times(int user); extern void scheduler_tick(void); -extern void hrtick_resched(void); - -extern void sched_show_task(struct task_struct *p); #ifdef CONFIG_DETECT_SOFTLOCKUP extern void softlockup_tick(void); extern void spawn_softlockup_task(void); extern void touch_softlockup_watchdog(void); extern void touch_all_softlockup_watchdogs(void); -extern unsigned long softlockup_thresh; -extern unsigned long sysctl_hung_task_check_count; -extern unsigned long sysctl_hung_task_timeout_secs; -extern unsigned long sysctl_hung_task_warnings; +extern int softlockup_thresh; #else static inline void softlockup_tick(void) { @@ -831,7 +822,6 @@ struct sched_class { void (*enqueue_task) (struct rq *rq, struct task_struct *p, int wakeup); void (*dequeue_task) (struct rq *rq, struct task_struct *p, int sleep); void (*yield_task) (struct rq *rq); - int (*select_task_rq)(struct task_struct *p, int sync); void (*check_preempt_curr) (struct rq *rq, struct task_struct *p); @@ -847,25 +837,11 @@ struct sched_class { int (*move_one_task) (struct rq *this_rq, int this_cpu, struct rq *busiest, struct sched_domain *sd, enum cpu_idle_type idle); - void (*pre_schedule) (struct rq *this_rq, struct task_struct *task); - void (*post_schedule) (struct rq *this_rq); - void (*task_wake_up) (struct rq *this_rq, struct task_struct *task); #endif void (*set_curr_task) (struct rq *rq); - void (*task_tick) (struct rq *rq, struct task_struct *p, int queued); + void (*task_tick) (struct rq *rq, struct task_struct *p); void (*task_new) (struct rq *rq, struct task_struct *p); - void (*set_cpus_allowed)(struct task_struct *p, cpumask_t *newmask); - - void (*join_domain)(struct rq *rq); - void (*leave_domain)(struct rq *rq); - - void (*switched_from) (struct rq *this_rq, struct task_struct *task, - int running); - void (*switched_to) (struct rq *this_rq, struct task_struct *task, - int running); - void (*prio_changed) (struct rq *this_rq, struct task_struct *task, - int oldprio, int running); }; struct load_weight { @@ -895,8 +871,6 @@ struct sched_entity { #ifdef CONFIG_SCHEDSTATS u64 wait_start; u64 wait_max; - u64 wait_count; - u64 wait_sum; u64 sleep_start; u64 sleep_max; @@ -935,21 +909,6 @@ struct sched_entity { #endif }; -struct sched_rt_entity { - struct list_head run_list; - unsigned int time_slice; - unsigned long timeout; - int nr_cpus_allowed; - -#ifdef CONFIG_FAIR_GROUP_SCHED - struct sched_rt_entity *parent; - /* rq on which this entity is (to be) queued: */ - struct rt_rq *rt_rq; - /* rq "owned" by this entity/group: */ - struct rt_rq *my_q; -#endif -}; - struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; @@ -966,9 +925,9 @@ struct task_struct { #endif int prio, static_prio, normal_prio; + struct list_head run_list; const struct sched_class *sched_class; struct sched_entity se; - struct sched_rt_entity rt; #ifdef CONFIG_PREEMPT_NOTIFIERS /* list of struct preempt_notifier: */ @@ -992,11 +951,7 @@ struct task_struct { unsigned int policy; cpumask_t cpus_allowed; - -#ifdef CONFIG_PREEMPT_RCU - int rcu_read_lock_nesting; - int rcu_flipctr_idx; -#endif /* #ifdef CONFIG_PREEMPT_RCU */ + unsigned int time_slice; #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) struct sched_info sched_info; @@ -1086,11 +1041,6 @@ struct task_struct { /* ipc stuff */ struct sysv_sem sysvsem; #endif -#ifdef CONFIG_DETECT_SOFTLOCKUP -/* hung task detection */ - unsigned long last_switch_timestamp; - unsigned long last_switch_count; -#endif /* CPU-specific state of this task */ struct thread_struct thread; /* filesystem information */ @@ -1223,10 +1173,6 @@ struct task_struct { int make_it_fail; #endif struct prop_local_single dirties; -#ifdef CONFIG_LATENCYTOP - int latency_record_count; - struct latency_record latency_record[LT_SAVECOUNT]; -#endif }; /* @@ -1507,12 +1453,6 @@ extern unsigned int sysctl_sched_child_runs_first; extern unsigned int sysctl_sched_features; extern unsigned int sysctl_sched_migration_cost; extern unsigned int sysctl_sched_nr_migrate; -extern unsigned int sysctl_sched_rt_period; -extern unsigned int sysctl_sched_rt_ratio; -#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP) -extern unsigned int sysctl_sched_min_bal_int_shares; -extern unsigned int sysctl_sched_max_bal_int_shares; -#endif int sched_nr_latency_handler(struct ctl_table *table, int write, struct file *file, void __user *buffer, size_t *length, @@ -1905,18 +1845,7 @@ static inline int need_resched(void) * cond_resched_lock() will drop the spinlock before scheduling, * cond_resched_softirq() will enable bhs before scheduling. */ -#ifdef CONFIG_PREEMPT -static inline int cond_resched(void) -{ - return 0; -} -#else -extern int _cond_resched(void); -static inline int cond_resched(void) -{ - return _cond_resched(); -} -#endif +extern int cond_resched(void); extern int cond_resched_lock(spinlock_t * lock); extern int cond_resched_softirq(void); diff --git a/trunk/include/linux/smp_lock.h b/trunk/include/linux/smp_lock.h index aab3a4cff4e1..58962c51dee1 100644 --- a/trunk/include/linux/smp_lock.h +++ b/trunk/include/linux/smp_lock.h @@ -17,10 +17,22 @@ extern void __lockfunc __release_kernel_lock(void); __release_kernel_lock(); \ } while (0) +/* + * Non-SMP kernels will never block on the kernel lock, + * so we are better off returning a constant zero from + * reacquire_kernel_lock() so that the compiler can see + * it at compile-time. + */ +#if defined(CONFIG_SMP) && !defined(CONFIG_PREEMPT_BKL) +# define return_value_on_smp return +#else +# define return_value_on_smp +#endif + static inline int reacquire_kernel_lock(struct task_struct *task) { if (unlikely(task->lock_depth >= 0)) - return __reacquire_kernel_lock(); + return_value_on_smp __reacquire_kernel_lock(); return 0; } diff --git a/trunk/include/linux/stacktrace.h b/trunk/include/linux/stacktrace.h index 5da9794b2d78..e7fa657d0c49 100644 --- a/trunk/include/linux/stacktrace.h +++ b/trunk/include/linux/stacktrace.h @@ -9,13 +9,10 @@ struct stack_trace { }; extern void save_stack_trace(struct stack_trace *trace); -extern void save_stack_trace_tsk(struct task_struct *tsk, - struct stack_trace *trace); extern void print_stack_trace(struct stack_trace *trace, int spaces); #else # define save_stack_trace(trace) do { } while (0) -# define save_stack_trace_tsk(tsk, trace) do { } while (0) # define print_stack_trace(trace, spaces) do { } while (0) #endif diff --git a/trunk/include/linux/topology.h b/trunk/include/linux/topology.h index 2352f46160d3..47729f18bfdf 100644 --- a/trunk/include/linux/topology.h +++ b/trunk/include/linux/topology.h @@ -5,7 +5,7 @@ * * Copyright (C) 2002, IBM Corp. * - * All rights reserved. + * All rights reserved. * * 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 @@ -103,7 +103,6 @@ .forkexec_idx = 0, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ - | SD_BALANCE_FORK \ | SD_BALANCE_EXEC \ | SD_WAKE_AFFINE \ | SD_WAKE_IDLE \ @@ -135,7 +134,6 @@ .forkexec_idx = 1, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ - | SD_BALANCE_FORK \ | SD_BALANCE_EXEC \ | SD_WAKE_AFFINE \ | SD_WAKE_IDLE \ @@ -167,7 +165,6 @@ .forkexec_idx = 1, \ .flags = SD_LOAD_BALANCE \ | SD_BALANCE_NEWIDLE \ - | SD_BALANCE_FORK \ | SD_BALANCE_EXEC \ | SD_WAKE_AFFINE \ | BALANCE_FOR_PKG_POWER,\ diff --git a/trunk/include/media/cs5345.h b/trunk/include/media/cs5345.h deleted file mode 100644 index 6ccae24e65ed..000000000000 --- a/trunk/include/media/cs5345.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - cs5345.h - definition for cs5345 inputs and outputs - - Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl) - - 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 _CS5345_H_ -#define _CS5345_H_ - -/* CS5345 HW inputs */ -#define CS5345_IN_MIC 0 -#define CS5345_IN_1 1 -#define CS5345_IN_2 2 -#define CS5345_IN_3 3 -#define CS5345_IN_4 4 -#define CS5345_IN_5 5 -#define CS5345_IN_6 6 - -#define CS5345_MCLK_1 0x00 -#define CS5345_MCLK_1_5 0x10 -#define CS5345_MCLK_2 0x20 -#define CS5345_MCLK_3 0x30 -#define CS5345_MCLK_4 0x40 - -#endif diff --git a/trunk/include/media/cx2341x.h b/trunk/include/media/cx2341x.h index 5f4608e88476..af8071d7620d 100644 --- a/trunk/include/media/cx2341x.h +++ b/trunk/include/media/cx2341x.h @@ -83,7 +83,7 @@ struct cx2341x_mpeg_params { #define CX2341X_MBOX_MAX_DATA 16 extern const u32 cx2341x_mpeg_ctrls[]; -typedef int (*cx2341x_mbox_func)(void *priv, u32 cmd, int in, int out, +typedef int (*cx2341x_mbox_func)(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); int cx2341x_update(void *priv, cx2341x_mbox_func func, const struct cx2341x_mpeg_params *old, diff --git a/trunk/include/media/cx25840.h b/trunk/include/media/cx25840.h index cd599ad29fb2..8e7e52d659a0 100644 --- a/trunk/include/media/cx25840.h +++ b/trunk/include/media/cx25840.h @@ -49,25 +49,6 @@ enum cx25840_video_input { CX25840_SVIDEO2 = 0x620, CX25840_SVIDEO3 = 0x730, CX25840_SVIDEO4 = 0x840, - - /* Allow frames to specify specific input configurations */ - CX25840_VIN1_CH1 = 0x80000000, - CX25840_VIN2_CH1 = 0x80000001, - CX25840_VIN3_CH1 = 0x80000002, - CX25840_VIN4_CH1 = 0x80000003, - CX25840_VIN5_CH1 = 0x80000004, - CX25840_VIN6_CH1 = 0x80000005, - CX25840_VIN7_CH1 = 0x80000006, - CX25840_VIN8_CH1 = 0x80000007, - CX25840_VIN4_CH2 = 0x80000000, - CX25840_VIN5_CH2 = 0x80000010, - CX25840_VIN6_CH2 = 0x80000020, - CX25840_NONE_CH2 = 0x80000030, - CX25840_VIN7_CH3 = 0x80000000, - CX25840_VIN8_CH3 = 0x80000040, - CX25840_NONE0_CH3 = 0x80000080, - CX25840_NONE1_CH3 = 0x800000c0, - CX25840_SVIDEO_ON = 0x80000100, }; enum cx25840_audio_input { diff --git a/trunk/include/media/ir-common.h b/trunk/include/media/ir-common.h index 831547d79683..7a785fa77212 100644 --- a/trunk/include/media/ir-common.h +++ b/trunk/include/media/ir-common.h @@ -97,6 +97,7 @@ int ir_dump_samples(u32 *samples, int count); int ir_decode_biphase(u32 *samples, int count, int low, int high); int ir_decode_pulsedistance(u32 *samples, int count, int low, int high); +u32 ir_rc5_decode(unsigned int code); void ir_rc5_timer_end(unsigned long data); void ir_rc5_timer_keyup(unsigned long data); @@ -140,8 +141,6 @@ extern IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; -extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE]; -extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE]; #endif diff --git a/trunk/include/media/m52790.h b/trunk/include/media/m52790.h deleted file mode 100644 index 7ddffae31a67..000000000000 --- a/trunk/include/media/m52790.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - m52790.h - definition for m52790 inputs and outputs - - Copyright (C) 2007 Hans Verkuil (hverkuil@xs4all.nl) - - 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 _M52790_H_ -#define _M52790_H_ - -/* Input routing switch 1 */ - -#define M52790_SW1_IN_MASK 0x0003 -#define M52790_SW1_IN_TUNER 0x0000 -#define M52790_SW1_IN_V2 0x0001 -#define M52790_SW1_IN_V3 0x0002 -#define M52790_SW1_IN_V4 0x0003 - -/* Selects component input instead of composite */ -#define M52790_SW1_YCMIX 0x0004 - - -/* Input routing switch 2 */ - -#define M52790_SW2_IN_MASK 0x0300 -#define M52790_SW2_IN_TUNER 0x0000 -#define M52790_SW2_IN_V2 0x0100 -#define M52790_SW2_IN_V3 0x0200 -#define M52790_SW2_IN_V4 0x0300 - -/* Selects component input instead of composite */ -#define M52790_SW2_YCMIX 0x0400 - - -/* Output routing switch 1 */ - -/* Enable 6dB amplifier for composite out */ -#define M52790_SW1_V_AMP 0x0008 - -/* Enable 6dB amplifier for component out */ -#define M52790_SW1_YC_AMP 0x0010 - -/* Audio output mode */ -#define M52790_SW1_AUDIO_MASK 0x00c0 -#define M52790_SW1_AUDIO_MUTE 0x0000 -#define M52790_SW1_AUDIO_R 0x0040 -#define M52790_SW1_AUDIO_L 0x0080 -#define M52790_SW1_AUDIO_STEREO 0x00c0 - - -/* Output routing switch 2 */ - -/* Enable 6dB amplifier for composite out */ -#define M52790_SW2_V_AMP 0x0800 - -/* Enable 6dB amplifier for component out */ -#define M52790_SW2_YC_AMP 0x1000 - -/* Audio output mode */ -#define M52790_SW2_AUDIO_MASK 0xc000 -#define M52790_SW2_AUDIO_MUTE 0x0000 -#define M52790_SW2_AUDIO_R 0x4000 -#define M52790_SW2_AUDIO_L 0x8000 -#define M52790_SW2_AUDIO_STEREO 0xc000 - - -/* Common values */ -#define M52790_IN_TUNER (M52790_SW1_IN_TUNER | M52790_SW2_IN_TUNER) -#define M52790_IN_V2 (M52790_SW1_IN_V2 | M52790_SW2_IN_V2) -#define M52790_IN_V3 (M52790_SW1_IN_V3 | M52790_SW2_IN_V3) -#define M52790_IN_V4 (M52790_SW1_IN_V4 | M52790_SW2_IN_V4) - -#define M52790_OUT_STEREO (M52790_SW1_AUDIO_STEREO | \ - M52790_SW2_AUDIO_STEREO) -#define M52790_OUT_AMP_STEREO (M52790_SW1_AUDIO_STEREO | \ - M52790_SW1_V_AMP | \ - M52790_SW2_AUDIO_STEREO | \ - M52790_SW2_V_AMP) - -#endif diff --git a/trunk/include/media/saa7146_vv.h b/trunk/include/media/saa7146_vv.h index 89c442eb8849..e49f7e156061 100644 --- a/trunk/include/media/saa7146_vv.h +++ b/trunk/include/media/saa7146_vv.h @@ -1,6 +1,7 @@ #ifndef __SAA7146_VV__ #define __SAA7146_VV__ +#include #include #include #include diff --git a/trunk/include/media/tuner.h b/trunk/include/media/tuner.h index 1bf24a6ed8f1..c03dceb92605 100644 --- a/trunk/include/media/tuner.h +++ b/trunk/include/media/tuner.h @@ -24,6 +24,8 @@ #include +extern int tuner_debug; + #define ADDR_UNSET (255) #define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */ @@ -115,13 +117,12 @@ #define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */ #define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */ #define TUNER_SAMSUNG_TCPN_2121P30A 70 /* Hauppauge PVR-500MCE NTSC */ -#define TUNER_XC2028 71 +#define TUNER_XCEIVE_XC3028 71 #define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */ #define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */ #define TUNER_TDA9887 74 /* This tuner should be used only internally */ #define TUNER_TEA5761 75 /* Only FM Radio Tuner */ -#define TUNER_XC5000 76 /* Xceive Silicon Tuner */ /* tv card specific */ #define TDA9887_PRESENT (1<<0) diff --git a/trunk/include/media/v4l2-chip-ident.h b/trunk/include/media/v4l2-chip-ident.h index 032bb75f69c2..8ae42c41dd08 100644 --- a/trunk/include/media/v4l2-chip-ident.h +++ b/trunk/include/media/v4l2-chip-ident.h @@ -68,9 +68,6 @@ enum { /* module vp27smpx: just ident 2700 */ V4L2_IDENT_VP27SMPX = 2700, - /* module cs5345: just ident 5345 */ - V4L2_IDENT_CS5345 = 5345, - /* module wm8739: just ident 8739 */ V4L2_IDENT_WM8739 = 8739, @@ -86,9 +83,6 @@ enum { /* module upd64083: just ident 64083 */ V4L2_IDENT_UPD64083 = 64083, - /* module m52790: just ident 52790 */ - V4L2_IDENT_M52790 = 52790, - /* module msp34xx: reserved range 34000-34999 */ V4L2_IDENT_MSP3400B = 34002, V4L2_IDENT_MSP3410B = 34102, diff --git a/trunk/include/media/v4l2-common.h b/trunk/include/media/v4l2-common.h index 475d0d8275e0..181a40c46a52 100644 --- a/trunk/include/media/v4l2-common.h +++ b/trunk/include/media/v4l2-common.h @@ -104,17 +104,6 @@ int v4l2_chip_match_host(u32 id_type, u32 chip_id); /* ------------------------------------------------------------------------- */ -/* Helper function for I2C legacy drivers */ - -struct i2c_driver; -struct i2c_adapter; -struct i2c_client; - -int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, - const char *name, int (*probe)(struct i2c_client *)); - -/* ------------------------------------------------------------------------- */ - /* Internal ioctls */ /* VIDIOC_INT_DECODE_VBI_LINE */ @@ -127,11 +116,6 @@ struct v4l2_decode_vbi_line { u32 type; /* VBI service type (V4L2_SLICED_*). 0 if no service found */ }; -struct v4l2_priv_tun_config { - int tuner; - void *priv; -}; - /* audio ioctls */ /* v4l device was opened in Radio mode, to be replaced by VIDIOC_INT_S_TUNER_MODE */ @@ -147,7 +131,7 @@ struct v4l2_priv_tun_config { #define TUNER_SET_STANDBY _IOW('d', 91, int) /* Sets tda9887 specific stuff, like port1, port2 and qss */ -#define TUNER_SET_CONFIG _IOW('d', 92, struct v4l2_priv_tun_config) +#define TDA9887_SET_CONFIG _IOW('d', 92, int) /* Switch the tuner to a specific tuner mode. Replacement of AUDC_SET_RADIO */ #define VIDIOC_INT_S_TUNER_MODE _IOW('d', 93, enum v4l2_tuner_type) diff --git a/trunk/include/media/v4l2-i2c-drv-legacy.h b/trunk/include/media/v4l2-i2c-drv-legacy.h deleted file mode 100644 index 241854229d6f..000000000000 --- a/trunk/include/media/v4l2-i2c-drv-legacy.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * v4l2-i2c-drv-legacy.h - contains I2C handling code that's identical - * for all V4L2 I2C drivers. Use this header if the - * I2C driver is used by both legacy drivers and - * drivers converted to the bus-based I2C API. - * - * Copyright (C) 2007 Hans Verkuil - * - * 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. - */ - -struct v4l2_i2c_driver_data { - const char * const name; - int driverid; - int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); - int (*probe)(struct i2c_client *client); - int (*remove)(struct i2c_client *client); - int (*suspend)(struct i2c_client *client, pm_message_t state); - int (*resume)(struct i2c_client *client); - int (*legacy_probe)(struct i2c_adapter *adapter); - int legacy_class; -}; - -static struct v4l2_i2c_driver_data v4l2_i2c_data; -static struct i2c_client_address_data addr_data; -static struct i2c_driver v4l2_i2c_driver_legacy; -static char v4l2_i2c_drv_name_legacy[32]; - -static int v4l2_i2c_drv_attach_legacy(struct i2c_adapter *adapter, int address, int kind) -{ - return v4l2_i2c_attach(adapter, address, &v4l2_i2c_driver_legacy, - v4l2_i2c_drv_name_legacy, v4l2_i2c_data.probe); -} - -static int v4l2_i2c_drv_probe_legacy(struct i2c_adapter *adapter) -{ - if (v4l2_i2c_data.legacy_probe) { - if (v4l2_i2c_data.legacy_probe(adapter)) - return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy); - return 0; - } - if (adapter->class & v4l2_i2c_data.legacy_class) - return i2c_probe(adapter, &addr_data, v4l2_i2c_drv_attach_legacy); - return 0; -} - -static int v4l2_i2c_drv_detach_legacy(struct i2c_client *client) -{ - int err; - - if (v4l2_i2c_data.remove) - v4l2_i2c_data.remove(client); - - err = i2c_detach_client(client); - if (err) - return err; - kfree(client); - - return 0; -} - -static int v4l2_i2c_drv_suspend_helper(struct i2c_client *client, pm_message_t state) -{ - return v4l2_i2c_data.suspend ? v4l2_i2c_data.suspend(client, state) : 0; -} - -static int v4l2_i2c_drv_resume_helper(struct i2c_client *client) -{ - return v4l2_i2c_data.resume ? v4l2_i2c_data.resume(client) : 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver v4l2_i2c_driver_legacy = { - .driver = { - .owner = THIS_MODULE, - }, - .attach_adapter = v4l2_i2c_drv_probe_legacy, - .detach_client = v4l2_i2c_drv_detach_legacy, - .suspend = v4l2_i2c_drv_suspend_helper, - .resume = v4l2_i2c_drv_resume_helper, -}; - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver v4l2_i2c_driver = { - .suspend = v4l2_i2c_drv_suspend_helper, - .resume = v4l2_i2c_drv_resume_helper, -}; - -static int __init v4l2_i2c_drv_init(void) -{ - int err; - - strlcpy(v4l2_i2c_drv_name_legacy, v4l2_i2c_data.name, sizeof(v4l2_i2c_drv_name_legacy)); - strlcat(v4l2_i2c_drv_name_legacy, "'", sizeof(v4l2_i2c_drv_name_legacy)); - - if (v4l2_i2c_data.legacy_class == 0) - v4l2_i2c_data.legacy_class = I2C_CLASS_TV_ANALOG; - - v4l2_i2c_driver_legacy.driver.name = v4l2_i2c_drv_name_legacy; - v4l2_i2c_driver_legacy.id = v4l2_i2c_data.driverid; - v4l2_i2c_driver_legacy.command = v4l2_i2c_data.command; - err = i2c_add_driver(&v4l2_i2c_driver_legacy); - - if (err) - return err; - v4l2_i2c_driver.driver.name = v4l2_i2c_data.name; - v4l2_i2c_driver.id = v4l2_i2c_data.driverid; - v4l2_i2c_driver.command = v4l2_i2c_data.command; - v4l2_i2c_driver.probe = v4l2_i2c_data.probe; - v4l2_i2c_driver.remove = v4l2_i2c_data.remove; - err = i2c_add_driver(&v4l2_i2c_driver); - if (err) - i2c_del_driver(&v4l2_i2c_driver_legacy); - return err; -} - -static void __exit v4l2_i2c_drv_cleanup(void) -{ - i2c_del_driver(&v4l2_i2c_driver_legacy); - i2c_del_driver(&v4l2_i2c_driver); -} - -module_init(v4l2_i2c_drv_init); -module_exit(v4l2_i2c_drv_cleanup); diff --git a/trunk/include/media/v4l2-i2c-drv.h b/trunk/include/media/v4l2-i2c-drv.h deleted file mode 100644 index 9e4bab276915..000000000000 --- a/trunk/include/media/v4l2-i2c-drv.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * v4l2-i2c-drv.h - contains I2C handling code that's identical for - * all V4L2 I2C drivers. Use this header if the - * I2C driver is only used by drivers converted - * to the bus-based I2C API. - * - * Copyright (C) 2007 Hans Verkuil - * - * 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 __V4L2_I2C_DRV_H__ -#define __V4L2_I2C_DRV_H__ - -#include - -struct v4l2_i2c_driver_data { - const char * const name; - int driverid; - int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); - int (*probe)(struct i2c_client *client); - int (*remove)(struct i2c_client *client); - int (*suspend)(struct i2c_client *client, pm_message_t state); - int (*resume)(struct i2c_client *client); - int (*legacy_probe)(struct i2c_adapter *adapter); - int legacy_class; -}; - -static struct v4l2_i2c_driver_data v4l2_i2c_data; -static struct i2c_driver v4l2_i2c_driver; - - -/* Bus-based I2C implementation for kernels >= 2.6.22 */ - -static int __init v4l2_i2c_drv_init(void) -{ - v4l2_i2c_driver.driver.name = v4l2_i2c_data.name; - v4l2_i2c_driver.id = v4l2_i2c_data.driverid; - v4l2_i2c_driver.command = v4l2_i2c_data.command; - v4l2_i2c_driver.probe = v4l2_i2c_data.probe; - v4l2_i2c_driver.remove = v4l2_i2c_data.remove; - v4l2_i2c_driver.suspend = v4l2_i2c_data.suspend; - v4l2_i2c_driver.resume = v4l2_i2c_data.resume; - return i2c_add_driver(&v4l2_i2c_driver); -} - - -static void __exit v4l2_i2c_drv_cleanup(void) -{ - i2c_del_driver(&v4l2_i2c_driver); -} - -module_init(v4l2_i2c_drv_init); -module_exit(v4l2_i2c_drv_cleanup); - -#endif /* __V4L2_I2C_DRV_H__ */ diff --git a/trunk/include/media/v4l2-int-device.h b/trunk/include/media/v4l2-int-device.h index c8b80e0f0651..066ebfc4f983 100644 --- a/trunk/include/media/v4l2-int-device.h +++ b/trunk/include/media/v4l2-int-device.h @@ -44,8 +44,9 @@ enum v4l2_int_type { struct v4l2_int_device; struct v4l2_int_master { - int (*attach)(struct v4l2_int_device *slave); - void (*detach)(struct v4l2_int_device *slave); + int (*attach)(struct v4l2_int_device *master, + struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *master); }; typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); diff --git a/trunk/include/media/videobuf-core.h b/trunk/include/media/videobuf-core.h index 97f14d469595..4fd5d0eaa935 100644 --- a/trunk/include/media/videobuf-core.h +++ b/trunk/include/media/videobuf-core.h @@ -56,13 +56,13 @@ struct videobuf_mapping { }; enum videobuf_state { - VIDEOBUF_NEEDS_INIT = 0, - VIDEOBUF_PREPARED = 1, - VIDEOBUF_QUEUED = 2, - VIDEOBUF_ACTIVE = 3, - VIDEOBUF_DONE = 4, - VIDEOBUF_ERROR = 5, - VIDEOBUF_IDLE = 6, + STATE_NEEDS_INIT = 0, + STATE_PREPARED = 1, + STATE_QUEUED = 2, + STATE_ACTIVE = 3, + STATE_DONE = 4, + STATE_ERROR = 5, + STATE_IDLE = 6, }; struct videobuf_buffer { @@ -162,14 +162,12 @@ struct videobuf_queue { struct videobuf_queue_ops *ops; struct videobuf_qtype_ops *int_ops; - unsigned int streaming:1; - unsigned int reading:1; - unsigned int is_mmapped:1; - /* capture via mmap() + ioctl(QBUF/DQBUF) */ + unsigned int streaming; struct list_head stream; /* capture via read() */ + unsigned int reading; unsigned int read_off; struct videobuf_buffer *read_buf; diff --git a/trunk/include/net/if_inet6.h b/trunk/include/net/if_inet6.h index b24508abb850..448eccb20638 100644 --- a/trunk/include/net/if_inet6.h +++ b/trunk/include/net/if_inet6.h @@ -269,21 +269,18 @@ static inline void ipv6_arcnet_mc_map(const struct in6_addr *addr, char *buf) buf[0] = 0x00; } -static inline void ipv6_ib_mc_map(const struct in6_addr *addr, - const unsigned char *broadcast, char *buf) +static inline void ipv6_ib_mc_map(struct in6_addr *addr, char *buf) { - unsigned char scope = broadcast[5] & 0xF; - buf[0] = 0; /* Reserved */ buf[1] = 0xff; /* Multicast QPN */ buf[2] = 0xff; buf[3] = 0xff; buf[4] = 0xff; - buf[5] = 0x10 | scope; /* scope from broadcast address */ + buf[5] = 0x12; /* link local scope */ buf[6] = 0x60; /* IPv6 signature */ buf[7] = 0x1b; - buf[8] = broadcast[8]; /* P_Key */ - buf[9] = broadcast[9]; + buf[8] = 0; /* P_Key */ + buf[9] = 0; memcpy(buf + 10, addr->s6_addr + 6, 10); } #endif diff --git a/trunk/include/net/ip.h b/trunk/include/net/ip.h index 50c8889b1b8d..840dd91b513b 100644 --- a/trunk/include/net/ip.h +++ b/trunk/include/net/ip.h @@ -266,22 +266,20 @@ static inline void ip_eth_mc_map(__be32 naddr, char *buf) * Leave P_Key as 0 to be filled in by driver. */ -static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf) +static inline void ip_ib_mc_map(__be32 naddr, char *buf) { __u32 addr; - unsigned char scope = broadcast[5] & 0xF; - buf[0] = 0; /* Reserved */ buf[1] = 0xff; /* Multicast QPN */ buf[2] = 0xff; buf[3] = 0xff; addr = ntohl(naddr); buf[4] = 0xff; - buf[5] = 0x10 | scope; /* scope from broadcast address */ + buf[5] = 0x12; /* link local scope */ buf[6] = 0x40; /* IPv4 signature */ buf[7] = 0x1b; - buf[8] = broadcast[8]; /* P_Key */ - buf[9] = broadcast[9]; + buf[8] = 0; /* P_Key */ + buf[9] = 0; buf[10] = 0; buf[11] = 0; buf[12] = 0; diff --git a/trunk/include/rdma/ib_mad.h b/trunk/include/rdma/ib_mad.h index 7228c056b9e9..8ec3799e42e1 100644 --- a/trunk/include/rdma/ib_mad.h +++ b/trunk/include/rdma/ib_mad.h @@ -230,9 +230,7 @@ struct ib_class_port_info * @seg_count: The number of RMPP segments allocated for this send. * @seg_size: Size of each RMPP segment. * @timeout_ms: Time to wait for a response. - * @retries: Number of times to retry a request for a response. For MADs - * using RMPP, this applies per window. On completion, returns the number - * of retries needed to complete the transfer. + * @retries: Number of times to retry a request for a response. * * Users are responsible for initializing the MAD buffer itself, with the * exception of any RMPP header. Additional segment buffer space allocated diff --git a/trunk/include/rdma/rdma_user_cm.h b/trunk/include/rdma/rdma_user_cm.h index c55705460b87..9749c1b34d00 100644 --- a/trunk/include/rdma/rdma_user_cm.h +++ b/trunk/include/rdma/rdma_user_cm.h @@ -60,8 +60,7 @@ enum { RDMA_USER_CM_CMD_SET_OPTION, RDMA_USER_CM_CMD_NOTIFY, RDMA_USER_CM_CMD_JOIN_MCAST, - RDMA_USER_CM_CMD_LEAVE_MCAST, - RDMA_USER_CM_CMD_MIGRATE_ID + RDMA_USER_CM_CMD_LEAVE_MCAST }; /* @@ -231,14 +230,4 @@ struct rdma_ucm_set_option { __u32 optlen; }; -struct rdma_ucm_migrate_id { - __u64 response; - __u32 id; - __u32 fd; -}; - -struct rdma_ucm_migrate_resp { - __u32 events_reported; -}; - #endif /* RDMA_USER_CM_H */ diff --git a/trunk/init/Kconfig b/trunk/init/Kconfig index 0eda68f0ad54..f5becd2a12f6 100644 --- a/trunk/init/Kconfig +++ b/trunk/init/Kconfig @@ -763,31 +763,3 @@ source "block/Kconfig" config PREEMPT_NOTIFIERS bool - -choice - prompt "RCU implementation type:" - default CLASSIC_RCU - -config CLASSIC_RCU - bool "Classic RCU" - help - This option selects the classic RCU implementation that is - designed for best read-side performance on non-realtime - systems. - - Say Y if you are unsure. - -config PREEMPT_RCU - bool "Preemptible RCU" - depends on PREEMPT - help - This option reduces the latency of the kernel by making certain - RCU sections preemptible. Normally RCU code is non-preemptible, if - this option is selected then read-only RCU sections become - preemptible. This helps latency, but may expose bugs due to - now-naive assumptions about each RCU read-side critical section - remaining on a given CPU through its execution. - - Say N if you are unsure. - -endchoice diff --git a/trunk/init/main.c b/trunk/init/main.c index f287ca5862b9..80b04b6c5157 100644 --- a/trunk/init/main.c +++ b/trunk/init/main.c @@ -607,7 +607,6 @@ asmlinkage void __init start_kernel(void) vfs_caches_init_early(); cpuset_init_early(); mem_init(); - cpu_hotplug_init(); kmem_cache_init(); setup_per_cpu_pageset(); numa_policy_init(); diff --git a/trunk/kernel/Kconfig.hz b/trunk/kernel/Kconfig.hz index 526128a2e622..4af15802ccd4 100644 --- a/trunk/kernel/Kconfig.hz +++ b/trunk/kernel/Kconfig.hz @@ -54,5 +54,3 @@ config HZ default 300 if HZ_300 default 1000 if HZ_1000 -config SCHED_HRTICK - def_bool HIGH_RES_TIMERS && X86 diff --git a/trunk/kernel/Kconfig.preempt b/trunk/kernel/Kconfig.preempt index 0669b70fa6a3..c64ce9c14207 100644 --- a/trunk/kernel/Kconfig.preempt +++ b/trunk/kernel/Kconfig.preempt @@ -52,13 +52,14 @@ config PREEMPT endchoice -config RCU_TRACE - bool "Enable tracing for RCU - currently stats in debugfs" - select DEBUG_FS +config PREEMPT_BKL + bool "Preempt The Big Kernel Lock" + depends on SMP || PREEMPT default y help - This option provides tracing in RCU which presents stats - in debugfs for debugging RCU implementation. + This option reduces the latency of the kernel by making the + big kernel lock preemptible. - Say Y here if you want to enable RCU tracing + Say Y here if you are building a kernel for a desktop system. Say N if you are unsure. + diff --git a/trunk/kernel/Makefile b/trunk/kernel/Makefile index 390d42146267..dfa96956dae0 100644 --- a/trunk/kernel/Makefile +++ b/trunk/kernel/Makefile @@ -52,17 +52,11 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o -obj-$(CONFIG_CLASSIC_RCU) += rcuclassic.o -obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o -ifeq ($(CONFIG_PREEMPT_RCU),y) -obj-$(CONFIG_RCU_TRACE) += rcupreempt_trace.o -endif obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o obj-$(CONFIG_MARKERS) += marker.o -obj-$(CONFIG_LATENCYTOP) += latencytop.o ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff --git a/trunk/kernel/cpu.c b/trunk/kernel/cpu.c index e0d3a4f56ecb..6b3a0c15144f 100644 --- a/trunk/kernel/cpu.c +++ b/trunk/kernel/cpu.c @@ -15,8 +15,9 @@ #include #include -/* Serializes the updates to cpu_online_map, cpu_present_map */ +/* This protects CPUs going up and down... */ static DEFINE_MUTEX(cpu_add_remove_lock); +static DEFINE_MUTEX(cpu_bitmask_lock); static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); @@ -25,123 +26,52 @@ static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); */ static int cpu_hotplug_disabled; -static struct { - struct task_struct *active_writer; - struct mutex lock; /* Synchronizes accesses to refcount, */ - /* - * Also blocks the new readers during - * an ongoing cpu hotplug operation. - */ - int refcount; - wait_queue_head_t writer_queue; -} cpu_hotplug; - -#define writer_exists() (cpu_hotplug.active_writer != NULL) - -void __init cpu_hotplug_init(void) -{ - cpu_hotplug.active_writer = NULL; - mutex_init(&cpu_hotplug.lock); - cpu_hotplug.refcount = 0; - init_waitqueue_head(&cpu_hotplug.writer_queue); -} - #ifdef CONFIG_HOTPLUG_CPU -void get_online_cpus(void) +/* Crappy recursive lock-takers in cpufreq! Complain loudly about idiots */ +static struct task_struct *recursive; +static int recursive_depth; + +void lock_cpu_hotplug(void) { - might_sleep(); - if (cpu_hotplug.active_writer == current) + struct task_struct *tsk = current; + + if (tsk == recursive) { + static int warnings = 10; + if (warnings) { + printk(KERN_ERR "Lukewarm IQ detected in hotplug locking\n"); + WARN_ON(1); + warnings--; + } + recursive_depth++; return; - mutex_lock(&cpu_hotplug.lock); - cpu_hotplug.refcount++; - mutex_unlock(&cpu_hotplug.lock); - + } + mutex_lock(&cpu_bitmask_lock); + recursive = tsk; } -EXPORT_SYMBOL_GPL(get_online_cpus); +EXPORT_SYMBOL_GPL(lock_cpu_hotplug); -void put_online_cpus(void) +void unlock_cpu_hotplug(void) { - if (cpu_hotplug.active_writer == current) + WARN_ON(recursive != current); + if (recursive_depth) { + recursive_depth--; return; - mutex_lock(&cpu_hotplug.lock); - cpu_hotplug.refcount--; - - if (unlikely(writer_exists()) && !cpu_hotplug.refcount) - wake_up(&cpu_hotplug.writer_queue); - - mutex_unlock(&cpu_hotplug.lock); - + } + recursive = NULL; + mutex_unlock(&cpu_bitmask_lock); } -EXPORT_SYMBOL_GPL(put_online_cpus); +EXPORT_SYMBOL_GPL(unlock_cpu_hotplug); #endif /* CONFIG_HOTPLUG_CPU */ -/* - * The following two API's must be used when attempting - * to serialize the updates to cpu_online_map, cpu_present_map. - */ -void cpu_maps_update_begin(void) -{ - mutex_lock(&cpu_add_remove_lock); -} - -void cpu_maps_update_done(void) -{ - mutex_unlock(&cpu_add_remove_lock); -} - -/* - * This ensures that the hotplug operation can begin only when the - * refcount goes to zero. - * - * Note that during a cpu-hotplug operation, the new readers, if any, - * will be blocked by the cpu_hotplug.lock - * - * Since cpu_maps_update_begin is always called after invoking - * cpu_maps_update_begin, we can be sure that only one writer is active. - * - * Note that theoretically, there is a possibility of a livelock: - * - Refcount goes to zero, last reader wakes up the sleeping - * writer. - * - Last reader unlocks the cpu_hotplug.lock. - * - A new reader arrives at this moment, bumps up the refcount. - * - The writer acquires the cpu_hotplug.lock finds the refcount - * non zero and goes to sleep again. - * - * However, this is very difficult to achieve in practice since - * get_online_cpus() not an api which is called all that often. - * - */ -static void cpu_hotplug_begin(void) -{ - DECLARE_WAITQUEUE(wait, current); - - mutex_lock(&cpu_hotplug.lock); - - cpu_hotplug.active_writer = current; - add_wait_queue_exclusive(&cpu_hotplug.writer_queue, &wait); - while (cpu_hotplug.refcount) { - set_current_state(TASK_UNINTERRUPTIBLE); - mutex_unlock(&cpu_hotplug.lock); - schedule(); - mutex_lock(&cpu_hotplug.lock); - } - remove_wait_queue_locked(&cpu_hotplug.writer_queue, &wait); -} - -static void cpu_hotplug_done(void) -{ - cpu_hotplug.active_writer = NULL; - mutex_unlock(&cpu_hotplug.lock); -} /* Need to know about CPUs going up/down? */ int __cpuinit register_cpu_notifier(struct notifier_block *nb) { int ret; - cpu_maps_update_begin(); + mutex_lock(&cpu_add_remove_lock); ret = raw_notifier_chain_register(&cpu_chain, nb); - cpu_maps_update_done(); + mutex_unlock(&cpu_add_remove_lock); return ret; } @@ -151,9 +81,9 @@ EXPORT_SYMBOL(register_cpu_notifier); void unregister_cpu_notifier(struct notifier_block *nb) { - cpu_maps_update_begin(); + mutex_lock(&cpu_add_remove_lock); raw_notifier_chain_unregister(&cpu_chain, nb); - cpu_maps_update_done(); + mutex_unlock(&cpu_add_remove_lock); } EXPORT_SYMBOL(unregister_cpu_notifier); @@ -217,7 +147,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) if (!cpu_online(cpu)) return -EINVAL; - cpu_hotplug_begin(); + raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu); err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls); if (err == NOTIFY_BAD) { @@ -236,7 +166,9 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) cpu_clear(cpu, tmp); set_cpus_allowed(current, tmp); + mutex_lock(&cpu_bitmask_lock); p = __stop_machine_run(take_cpu_down, &tcd_param, cpu); + mutex_unlock(&cpu_bitmask_lock); if (IS_ERR(p) || cpu_online(cpu)) { /* CPU didn't die: tell everyone. Can't complain. */ @@ -270,7 +202,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen) out_allowed: set_cpus_allowed(current, old_allowed); out_release: - cpu_hotplug_done(); + raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu); return err; } @@ -278,13 +210,13 @@ int cpu_down(unsigned int cpu) { int err = 0; - cpu_maps_update_begin(); + mutex_lock(&cpu_add_remove_lock); if (cpu_hotplug_disabled) err = -EBUSY; else err = _cpu_down(cpu, 0); - cpu_maps_update_done(); + mutex_unlock(&cpu_add_remove_lock); return err; } #endif /*CONFIG_HOTPLUG_CPU*/ @@ -299,7 +231,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) if (cpu_online(cpu) || !cpu_present(cpu)) return -EINVAL; - cpu_hotplug_begin(); + raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu); ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls); if (ret == NOTIFY_BAD) { @@ -311,7 +243,9 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) } /* Arch-specific enabling code. */ + mutex_lock(&cpu_bitmask_lock); ret = __cpu_up(cpu); + mutex_unlock(&cpu_bitmask_lock); if (ret != 0) goto out_notify; BUG_ON(!cpu_online(cpu)); @@ -323,7 +257,7 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen) if (ret != 0) __raw_notifier_call_chain(&cpu_chain, CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL); - cpu_hotplug_done(); + raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu); return ret; } @@ -341,13 +275,13 @@ int __cpuinit cpu_up(unsigned int cpu) return -EINVAL; } - cpu_maps_update_begin(); + mutex_lock(&cpu_add_remove_lock); if (cpu_hotplug_disabled) err = -EBUSY; else err = _cpu_up(cpu, 0); - cpu_maps_update_done(); + mutex_unlock(&cpu_add_remove_lock); return err; } @@ -358,7 +292,7 @@ int disable_nonboot_cpus(void) { int cpu, first_cpu, error = 0; - cpu_maps_update_begin(); + mutex_lock(&cpu_add_remove_lock); first_cpu = first_cpu(cpu_online_map); /* We take down all of the non-boot CPUs in one shot to avoid races * with the userspace trying to use the CPU hotplug at the same time @@ -385,7 +319,7 @@ int disable_nonboot_cpus(void) } else { printk(KERN_ERR "Non-boot CPUs are not disabled\n"); } - cpu_maps_update_done(); + mutex_unlock(&cpu_add_remove_lock); return error; } @@ -394,7 +328,7 @@ void enable_nonboot_cpus(void) int cpu, error; /* Allow everyone to use the CPU hotplug again */ - cpu_maps_update_begin(); + mutex_lock(&cpu_add_remove_lock); cpu_hotplug_disabled = 0; if (cpus_empty(frozen_cpus)) goto out; @@ -410,6 +344,6 @@ void enable_nonboot_cpus(void) } cpus_clear(frozen_cpus); out: - cpu_maps_update_done(); + mutex_unlock(&cpu_add_remove_lock); } #endif /* CONFIG_PM_SLEEP_SMP */ diff --git a/trunk/kernel/cpuset.c b/trunk/kernel/cpuset.c index cfaf6419d817..50f5dc463688 100644 --- a/trunk/kernel/cpuset.c +++ b/trunk/kernel/cpuset.c @@ -537,10 +537,10 @@ static int cpusets_overlap(struct cpuset *a, struct cpuset *b) * * Call with cgroup_mutex held. May take callback_mutex during * call due to the kfifo_alloc() and kmalloc() calls. May nest - * a call to the get_online_cpus()/put_online_cpus() pair. + * a call to the lock_cpu_hotplug()/unlock_cpu_hotplug() pair. * Must not be called holding callback_mutex, because we must not - * call get_online_cpus() while holding callback_mutex. Elsewhere - * the kernel nests callback_mutex inside get_online_cpus() calls. + * call lock_cpu_hotplug() while holding callback_mutex. Elsewhere + * the kernel nests callback_mutex inside lock_cpu_hotplug() calls. * So the reverse nesting would risk an ABBA deadlock. * * The three key local variables below are: @@ -691,9 +691,9 @@ static void rebuild_sched_domains(void) rebuild: /* Have scheduler rebuild sched domains */ - get_online_cpus(); + lock_cpu_hotplug(); partition_sched_domains(ndoms, doms); - put_online_cpus(); + unlock_cpu_hotplug(); done: if (q && !IS_ERR(q)) @@ -1617,10 +1617,10 @@ static struct cgroup_subsys_state *cpuset_create( * * If the cpuset being removed has its flag 'sched_load_balance' * enabled, then simulate turning sched_load_balance off, which - * will call rebuild_sched_domains(). The get_online_cpus() + * will call rebuild_sched_domains(). The lock_cpu_hotplug() * call in rebuild_sched_domains() must not be made while holding * callback_mutex. Elsewhere the kernel nests callback_mutex inside - * get_online_cpus() calls. So the reverse nesting would risk an + * lock_cpu_hotplug() calls. So the reverse nesting would risk an * ABBA deadlock. */ diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index 39d22b3357de..8dd8ff281009 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -1045,10 +1045,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, copy_flags(clone_flags, p); INIT_LIST_HEAD(&p->children); INIT_LIST_HEAD(&p->sibling); -#ifdef CONFIG_PREEMPT_RCU - p->rcu_read_lock_nesting = 0; - p->rcu_flipctr_idx = 0; -#endif /* #ifdef CONFIG_PREEMPT_RCU */ p->vfork_done = NULL; spin_lock_init(&p->alloc_lock); @@ -1063,11 +1059,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->prev_utime = cputime_zero; p->prev_stime = cputime_zero; -#ifdef CONFIG_DETECT_SOFTLOCKUP - p->last_switch_count = 0; - p->last_switch_timestamp = 0; -#endif - #ifdef CONFIG_TASK_XACCT p->rchar = 0; /* I/O counter: bytes read */ p->wchar = 0; /* I/O counter: bytes written */ @@ -1205,7 +1196,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, #ifdef TIF_SYSCALL_EMU clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); #endif - clear_all_latency_tracing(p); /* Our parent execution domain becomes current domain These must match for thread signalling to apply */ @@ -1247,7 +1237,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, * parent's CPU). This avoids alot of nasty races. */ p->cpus_allowed = current->cpus_allowed; - p->rt.nr_cpus_allowed = current->rt.nr_cpus_allowed; if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed) || !cpu_online(task_cpu(p)))) set_task_cpu(p, smp_processor_id()); diff --git a/trunk/kernel/hrtimer.c b/trunk/kernel/hrtimer.c index bd5d6b5060bc..f994bb8065e6 100644 --- a/trunk/kernel/hrtimer.c +++ b/trunk/kernel/hrtimer.c @@ -325,22 +325,6 @@ unsigned long ktime_divns(const ktime_t kt, s64 div) } #endif /* BITS_PER_LONG >= 64 */ -/* - * Check, whether the timer is on the callback pending list - */ -static inline int hrtimer_cb_pending(const struct hrtimer *timer) -{ - return timer->state & HRTIMER_STATE_PENDING; -} - -/* - * Remove a timer from the callback pending list - */ -static inline void hrtimer_remove_cb_pending(struct hrtimer *timer) -{ - list_del_init(&timer->cb_entry); -} - /* High resolution timer related functions */ #ifdef CONFIG_HIGH_RES_TIMERS @@ -509,6 +493,22 @@ void hres_timers_resume(void) retrigger_next_event(NULL); } +/* + * Check, whether the timer is on the callback pending list + */ +static inline int hrtimer_cb_pending(const struct hrtimer *timer) +{ + return timer->state & HRTIMER_STATE_PENDING; +} + +/* + * Remove a timer from the callback pending list + */ +static inline void hrtimer_remove_cb_pending(struct hrtimer *timer) +{ + list_del_init(&timer->cb_entry); +} + /* * Initialize the high resolution related parts of cpu_base */ @@ -516,6 +516,7 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { base->expires_next.tv64 = KTIME_MAX; base->hres_active = 0; + INIT_LIST_HEAD(&base->cb_pending); } /* @@ -523,6 +524,7 @@ static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) */ static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { + INIT_LIST_HEAD(&timer->cb_entry); } /* @@ -616,13 +618,10 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, { return 0; } +static inline int hrtimer_cb_pending(struct hrtimer *timer) { return 0; } +static inline void hrtimer_remove_cb_pending(struct hrtimer *timer) { } static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { } static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { } -static inline int hrtimer_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base) -{ - return 0; -} #endif /* CONFIG_HIGH_RES_TIMERS */ @@ -1002,7 +1001,6 @@ void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, clock_id = CLOCK_MONOTONIC; timer->base = &cpu_base->clock_base[clock_id]; - INIT_LIST_HEAD(&timer->cb_entry); hrtimer_init_timer_hres(timer); #ifdef CONFIG_TIMER_STATS @@ -1032,85 +1030,6 @@ int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp) } EXPORT_SYMBOL_GPL(hrtimer_get_res); -static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base) -{ - spin_lock_irq(&cpu_base->lock); - - while (!list_empty(&cpu_base->cb_pending)) { - enum hrtimer_restart (*fn)(struct hrtimer *); - struct hrtimer *timer; - int restart; - - timer = list_entry(cpu_base->cb_pending.next, - struct hrtimer, cb_entry); - - timer_stats_account_hrtimer(timer); - - fn = timer->function; - __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0); - spin_unlock_irq(&cpu_base->lock); - - restart = fn(timer); - - spin_lock_irq(&cpu_base->lock); - - timer->state &= ~HRTIMER_STATE_CALLBACK; - if (restart == HRTIMER_RESTART) { - BUG_ON(hrtimer_active(timer)); - /* - * Enqueue the timer, allow reprogramming of the event - * device - */ - enqueue_hrtimer(timer, timer->base, 1); - } else if (hrtimer_active(timer)) { - /* - * If the timer was rearmed on another CPU, reprogram - * the event device. - */ - if (timer->base->first == &timer->node) - hrtimer_reprogram(timer, timer->base); - } - } - spin_unlock_irq(&cpu_base->lock); -} - -static void __run_hrtimer(struct hrtimer *timer) -{ - struct hrtimer_clock_base *base = timer->base; - struct hrtimer_cpu_base *cpu_base = base->cpu_base; - enum hrtimer_restart (*fn)(struct hrtimer *); - int restart; - - __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0); - timer_stats_account_hrtimer(timer); - - fn = timer->function; - if (timer->cb_mode == HRTIMER_CB_IRQSAFE_NO_SOFTIRQ) { - /* - * Used for scheduler timers, avoid lock inversion with - * rq->lock and tasklist_lock. - * - * These timers are required to deal with enqueue expiry - * themselves and are not allowed to migrate. - */ - spin_unlock(&cpu_base->lock); - restart = fn(timer); - spin_lock(&cpu_base->lock); - } else - restart = fn(timer); - - /* - * Note: We clear the CALLBACK bit after enqueue_hrtimer to avoid - * reprogramming of the event hardware. This happens at the end of this - * function anyway. - */ - if (restart != HRTIMER_NORESTART) { - BUG_ON(timer->state != HRTIMER_STATE_CALLBACK); - enqueue_hrtimer(timer, base, 0); - } - timer->state &= ~HRTIMER_STATE_CALLBACK; -} - #ifdef CONFIG_HIGH_RES_TIMERS /* @@ -1168,7 +1087,21 @@ void hrtimer_interrupt(struct clock_event_device *dev) continue; } - __run_hrtimer(timer); + __remove_hrtimer(timer, base, + HRTIMER_STATE_CALLBACK, 0); + timer_stats_account_hrtimer(timer); + + /* + * Note: We clear the CALLBACK bit after + * enqueue_hrtimer to avoid reprogramming of + * the event hardware. This happens at the end + * of this function anyway. + */ + if (timer->function(timer) != HRTIMER_NORESTART) { + BUG_ON(timer->state != HRTIMER_STATE_CALLBACK); + enqueue_hrtimer(timer, base, 0); + } + timer->state &= ~HRTIMER_STATE_CALLBACK; } spin_unlock(&cpu_base->lock); base++; @@ -1189,41 +1122,52 @@ void hrtimer_interrupt(struct clock_event_device *dev) static void run_hrtimer_softirq(struct softirq_action *h) { - run_hrtimer_pending(&__get_cpu_var(hrtimer_bases)); -} + struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); -#endif /* CONFIG_HIGH_RES_TIMERS */ + spin_lock_irq(&cpu_base->lock); -/* - * Called from timer softirq every jiffy, expire hrtimers: - * - * For HRT its the fall back code to run the softirq in the timer - * softirq context in case the hrtimer initialization failed or has - * not been done yet. - */ -void hrtimer_run_pending(void) -{ - struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); + while (!list_empty(&cpu_base->cb_pending)) { + enum hrtimer_restart (*fn)(struct hrtimer *); + struct hrtimer *timer; + int restart; - if (hrtimer_hres_active()) - return; + timer = list_entry(cpu_base->cb_pending.next, + struct hrtimer, cb_entry); - /* - * This _is_ ugly: We have to check in the softirq context, - * whether we can switch to highres and / or nohz mode. The - * clocksource switch happens in the timer interrupt with - * xtime_lock held. Notification from there only sets the - * check bit in the tick_oneshot code, otherwise we might - * deadlock vs. xtime_lock. - */ - if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) - hrtimer_switch_to_hres(); + timer_stats_account_hrtimer(timer); + + fn = timer->function; + __remove_hrtimer(timer, timer->base, HRTIMER_STATE_CALLBACK, 0); + spin_unlock_irq(&cpu_base->lock); + + restart = fn(timer); + + spin_lock_irq(&cpu_base->lock); - run_hrtimer_pending(cpu_base); + timer->state &= ~HRTIMER_STATE_CALLBACK; + if (restart == HRTIMER_RESTART) { + BUG_ON(hrtimer_active(timer)); + /* + * Enqueue the timer, allow reprogramming of the event + * device + */ + enqueue_hrtimer(timer, timer->base, 1); + } else if (hrtimer_active(timer)) { + /* + * If the timer was rearmed on another CPU, reprogram + * the event device. + */ + if (timer->base->first == &timer->node) + hrtimer_reprogram(timer, timer->base); + } + } + spin_unlock_irq(&cpu_base->lock); } +#endif /* CONFIG_HIGH_RES_TIMERS */ + /* - * Called from hardirq context every jiffy + * Expire the per base hrtimer-queue: */ static inline void run_hrtimer_queue(struct hrtimer_cpu_base *cpu_base, int index) @@ -1237,27 +1181,46 @@ static inline void run_hrtimer_queue(struct hrtimer_cpu_base *cpu_base, if (base->get_softirq_time) base->softirq_time = base->get_softirq_time(); - spin_lock(&cpu_base->lock); + spin_lock_irq(&cpu_base->lock); while ((node = base->first)) { struct hrtimer *timer; + enum hrtimer_restart (*fn)(struct hrtimer *); + int restart; timer = rb_entry(node, struct hrtimer, node); if (base->softirq_time.tv64 <= timer->expires.tv64) break; - if (timer->cb_mode == HRTIMER_CB_SOFTIRQ) { - __remove_hrtimer(timer, base, HRTIMER_STATE_PENDING, 0); - list_add_tail(&timer->cb_entry, - &base->cpu_base->cb_pending); - continue; - } +#ifdef CONFIG_HIGH_RES_TIMERS + WARN_ON_ONCE(timer->cb_mode == HRTIMER_CB_IRQSAFE_NO_SOFTIRQ); +#endif + timer_stats_account_hrtimer(timer); + + fn = timer->function; + __remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0); + spin_unlock_irq(&cpu_base->lock); + + restart = fn(timer); - __run_hrtimer(timer); + spin_lock_irq(&cpu_base->lock); + + timer->state &= ~HRTIMER_STATE_CALLBACK; + if (restart != HRTIMER_NORESTART) { + BUG_ON(hrtimer_active(timer)); + enqueue_hrtimer(timer, base, 0); + } } - spin_unlock(&cpu_base->lock); + spin_unlock_irq(&cpu_base->lock); } +/* + * Called from timer softirq every jiffy, expire hrtimers: + * + * For HRT its the fall back code to run the softirq in the timer + * softirq context in case the hrtimer initialization failed or has + * not been done yet. + */ void hrtimer_run_queues(void) { struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); @@ -1266,6 +1229,18 @@ void hrtimer_run_queues(void) if (hrtimer_hres_active()) return; + /* + * This _is_ ugly: We have to check in the softirq context, + * whether we can switch to highres and / or nohz mode. The + * clocksource switch happens in the timer interrupt with + * xtime_lock held. Notification from there only sets the + * check bit in the tick_oneshot code, otherwise we might + * deadlock vs. xtime_lock. + */ + if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) + if (hrtimer_switch_to_hres()) + return; + hrtimer_get_softirq_time(cpu_base); for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) @@ -1293,7 +1268,7 @@ void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) sl->timer.function = hrtimer_wakeup; sl->task = task; #ifdef CONFIG_HIGH_RES_TIMERS - sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ; + sl->timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_RESTART; #endif } @@ -1304,8 +1279,6 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod do { set_current_state(TASK_INTERRUPTIBLE); hrtimer_start(&t->timer, t->timer.expires, mode); - if (!hrtimer_active(&t->timer)) - t->task = NULL; if (likely(t->task)) schedule(); @@ -1416,7 +1389,6 @@ static void __cpuinit init_hrtimers_cpu(int cpu) for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) cpu_base->clock_base[i].cpu_base = cpu_base; - INIT_LIST_HEAD(&cpu_base->cb_pending); hrtimer_init_hres(cpu_base); } diff --git a/trunk/kernel/kthread.c b/trunk/kernel/kthread.c index 0ac887882f90..dcfe724300eb 100644 --- a/trunk/kernel/kthread.c +++ b/trunk/kernel/kthread.c @@ -15,8 +15,6 @@ #include #include -#define KTHREAD_NICE_LEVEL (-5) - static DEFINE_SPINLOCK(kthread_create_lock); static LIST_HEAD(kthread_create_list); struct task_struct *kthreadd_task; @@ -96,18 +94,10 @@ static void create_kthread(struct kthread_create_info *create) if (pid < 0) { create->result = ERR_PTR(pid); } else { - struct sched_param param = { .sched_priority = 0 }; wait_for_completion(&create->started); read_lock(&tasklist_lock); create->result = find_task_by_pid(pid); read_unlock(&tasklist_lock); - /* - * root may have changed our (kthreadd's) priority or CPU mask. - * The kernel thread should not inherit these properties. - */ - sched_setscheduler(create->result, SCHED_NORMAL, ¶m); - set_user_nice(create->result, KTHREAD_NICE_LEVEL); - set_cpus_allowed(create->result, CPU_MASK_ALL); } complete(&create->done); } @@ -231,7 +221,7 @@ int kthreadd(void *unused) /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); - set_user_nice(tsk, KTHREAD_NICE_LEVEL); + set_user_nice(tsk, -5); set_cpus_allowed(tsk, CPU_MASK_ALL); current->flags |= PF_NOFREEZE; diff --git a/trunk/kernel/latencytop.c b/trunk/kernel/latencytop.c deleted file mode 100644 index b4e3c85abe74..000000000000 --- a/trunk/kernel/latencytop.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * latencytop.c: Latency display infrastructure - * - * (C) Copyright 2008 Intel Corporation - * Author: Arjan van de Ven - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static DEFINE_SPINLOCK(latency_lock); - -#define MAXLR 128 -static struct latency_record latency_record[MAXLR]; - -int latencytop_enabled; - -void clear_all_latency_tracing(struct task_struct *p) -{ - unsigned long flags; - - if (!latencytop_enabled) - return; - - spin_lock_irqsave(&latency_lock, flags); - memset(&p->latency_record, 0, sizeof(p->latency_record)); - p->latency_record_count = 0; - spin_unlock_irqrestore(&latency_lock, flags); -} - -static void clear_global_latency_tracing(void) -{ - unsigned long flags; - - spin_lock_irqsave(&latency_lock, flags); - memset(&latency_record, 0, sizeof(latency_record)); - spin_unlock_irqrestore(&latency_lock, flags); -} - -static void __sched -account_global_scheduler_latency(struct task_struct *tsk, struct latency_record *lat) -{ - int firstnonnull = MAXLR + 1; - int i; - - if (!latencytop_enabled) - return; - - /* skip kernel threads for now */ - if (!tsk->mm) - return; - - for (i = 0; i < MAXLR; i++) { - int q; - int same = 1; - /* Nothing stored: */ - if (!latency_record[i].backtrace[0]) { - if (firstnonnull > i) - firstnonnull = i; - continue; - } - for (q = 0 ; q < LT_BACKTRACEDEPTH ; q++) { - if (latency_record[i].backtrace[q] != - lat->backtrace[q]) - same = 0; - if (same && lat->backtrace[q] == 0) - break; - if (same && lat->backtrace[q] == ULONG_MAX) - break; - } - if (same) { - latency_record[i].count++; - latency_record[i].time += lat->time; - if (lat->time > latency_record[i].max) - latency_record[i].max = lat->time; - return; - } - } - - i = firstnonnull; - if (i >= MAXLR - 1) - return; - - /* Allocted a new one: */ - memcpy(&latency_record[i], lat, sizeof(struct latency_record)); -} - -static inline void store_stacktrace(struct task_struct *tsk, struct latency_record *lat) -{ - struct stack_trace trace; - - memset(&trace, 0, sizeof(trace)); - trace.max_entries = LT_BACKTRACEDEPTH; - trace.entries = &lat->backtrace[0]; - trace.skip = 0; - save_stack_trace_tsk(tsk, &trace); -} - -void __sched -account_scheduler_latency(struct task_struct *tsk, int usecs, int inter) -{ - unsigned long flags; - int i, q; - struct latency_record lat; - - if (!latencytop_enabled) - return; - - /* Long interruptible waits are generally user requested... */ - if (inter && usecs > 5000) - return; - - memset(&lat, 0, sizeof(lat)); - lat.count = 1; - lat.time = usecs; - lat.max = usecs; - store_stacktrace(tsk, &lat); - - spin_lock_irqsave(&latency_lock, flags); - - account_global_scheduler_latency(tsk, &lat); - - /* - * short term hack; if we're > 32 we stop; future we recycle: - */ - tsk->latency_record_count++; - if (tsk->latency_record_count >= LT_SAVECOUNT) - goto out_unlock; - - for (i = 0; i < LT_SAVECOUNT ; i++) { - struct latency_record *mylat; - int same = 1; - mylat = &tsk->latency_record[i]; - for (q = 0 ; q < LT_BACKTRACEDEPTH ; q++) { - if (mylat->backtrace[q] != - lat.backtrace[q]) - same = 0; - if (same && lat.backtrace[q] == 0) - break; - if (same && lat.backtrace[q] == ULONG_MAX) - break; - } - if (same) { - mylat->count++; - mylat->time += lat.time; - if (lat.time > mylat->max) - mylat->max = lat.time; - goto out_unlock; - } - } - - /* Allocated a new one: */ - i = tsk->latency_record_count; - memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record)); - -out_unlock: - spin_unlock_irqrestore(&latency_lock, flags); -} - -static int lstats_show(struct seq_file *m, void *v) -{ - int i; - - seq_puts(m, "Latency Top version : v0.1\n"); - - for (i = 0; i < MAXLR; i++) { - if (latency_record[i].backtrace[0]) { - int q; - seq_printf(m, "%i %li %li ", - latency_record[i].count, - latency_record[i].time, - latency_record[i].max); - for (q = 0; q < LT_BACKTRACEDEPTH; q++) { - char sym[KSYM_NAME_LEN]; - char *c; - if (!latency_record[i].backtrace[q]) - break; - if (latency_record[i].backtrace[q] == ULONG_MAX) - break; - sprint_symbol(sym, latency_record[i].backtrace[q]); - c = strchr(sym, '+'); - if (c) - *c = 0; - seq_printf(m, "%s ", sym); - } - seq_printf(m, "\n"); - } - } - return 0; -} - -static ssize_t -lstats_write(struct file *file, const char __user *buf, size_t count, - loff_t *offs) -{ - clear_global_latency_tracing(); - - return count; -} - -static int lstats_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, lstats_show, NULL); -} - -static struct file_operations lstats_fops = { - .open = lstats_open, - .read = seq_read, - .write = lstats_write, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init init_lstats_procfs(void) -{ - struct proc_dir_entry *pe; - - pe = create_proc_entry("latency_stats", 0644, NULL); - if (!pe) - return -ENOMEM; - - pe->proc_fops = &lstats_fops; - - return 0; -} -__initcall(init_lstats_procfs); diff --git a/trunk/kernel/lockdep.c b/trunk/kernel/lockdep.c index 3574379f4d62..e2c07ece367d 100644 --- a/trunk/kernel/lockdep.c +++ b/trunk/kernel/lockdep.c @@ -3206,11 +3206,7 @@ void debug_show_all_locks(void) EXPORT_SYMBOL_GPL(debug_show_all_locks); -/* - * Careful: only use this function if you are sure that - * the task cannot run in parallel! - */ -void __debug_show_held_locks(struct task_struct *task) +void debug_show_held_locks(struct task_struct *task) { if (unlikely(!debug_locks)) { printk("INFO: lockdep is turned off.\n"); @@ -3218,12 +3214,6 @@ void __debug_show_held_locks(struct task_struct *task) } lockdep_print_held_locks(task); } -EXPORT_SYMBOL_GPL(__debug_show_held_locks); - -void debug_show_held_locks(struct task_struct *task) -{ - __debug_show_held_locks(task); -} EXPORT_SYMBOL_GPL(debug_show_held_locks); diff --git a/trunk/kernel/module.c b/trunk/kernel/module.c index 1bb4c5e0d56e..dcb8a2cbf75e 100644 --- a/trunk/kernel/module.c +++ b/trunk/kernel/module.c @@ -496,8 +496,6 @@ static struct module_attribute modinfo_##field = { \ MODINFO_ATTR(version); MODINFO_ATTR(srcversion); -static char last_unloaded_module[MODULE_NAME_LEN+1]; - #ifdef CONFIG_MODULE_UNLOAD /* Init the unload section of the module. */ static void module_unload_init(struct module *mod) @@ -721,8 +719,6 @@ sys_delete_module(const char __user *name_user, unsigned int flags) mod->exit(); mutex_lock(&module_mutex); } - /* Store the name of the last unloaded module for diagnostic purposes */ - sprintf(last_unloaded_module, mod->name); free_module(mod); out: @@ -2361,30 +2357,21 @@ static void m_stop(struct seq_file *m, void *p) mutex_unlock(&module_mutex); } -static char *module_flags(struct module *mod, char *buf) +static char *taint_flags(unsigned int taints, char *buf) { int bx = 0; - if (mod->taints || - mod->state == MODULE_STATE_GOING || - mod->state == MODULE_STATE_COMING) { + if (taints) { buf[bx++] = '('; - if (mod->taints & TAINT_PROPRIETARY_MODULE) + if (taints & TAINT_PROPRIETARY_MODULE) buf[bx++] = 'P'; - if (mod->taints & TAINT_FORCED_MODULE) + if (taints & TAINT_FORCED_MODULE) buf[bx++] = 'F'; /* * TAINT_FORCED_RMMOD: could be added. * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't * apply to modules. */ - - /* Show a - for module-is-being-unloaded */ - if (mod->state == MODULE_STATE_GOING) - buf[bx++] = '-'; - /* Show a + for module-is-being-loaded */ - if (mod->state == MODULE_STATE_COMING) - buf[bx++] = '+'; buf[bx++] = ')'; } buf[bx] = '\0'; @@ -2411,7 +2398,7 @@ static int m_show(struct seq_file *m, void *p) /* Taints info */ if (mod->taints) - seq_printf(m, " %s", module_flags(mod, buf)); + seq_printf(m, " %s", taint_flags(mod->taints, buf)); seq_printf(m, "\n"); return 0; @@ -2506,9 +2493,7 @@ void print_modules(void) printk("Modules linked in:"); list_for_each_entry(mod, &modules, list) - printk(" %s%s", mod->name, module_flags(mod, buf)); - if (last_unloaded_module[0]) - printk(" [last unloaded: %s]", last_unloaded_module); + printk(" %s%s", mod->name, taint_flags(mod->taints, buf)); printk("\n"); } diff --git a/trunk/kernel/posix-cpu-timers.c b/trunk/kernel/posix-cpu-timers.c index 0b7c82ac467e..68c96376e84a 100644 --- a/trunk/kernel/posix-cpu-timers.c +++ b/trunk/kernel/posix-cpu-timers.c @@ -967,7 +967,6 @@ static void check_thread_timers(struct task_struct *tsk, { int maxfire; struct list_head *timers = tsk->cpu_timers; - struct signal_struct *const sig = tsk->signal; maxfire = 20; tsk->it_prof_expires = cputime_zero; @@ -1012,35 +1011,6 @@ static void check_thread_timers(struct task_struct *tsk, t->firing = 1; list_move_tail(&t->entry, firing); } - - /* - * Check for the special case thread timers. - */ - if (sig->rlim[RLIMIT_RTTIME].rlim_cur != RLIM_INFINITY) { - unsigned long hard = sig->rlim[RLIMIT_RTTIME].rlim_max; - unsigned long *soft = &sig->rlim[RLIMIT_RTTIME].rlim_cur; - - if (hard != RLIM_INFINITY && - tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) { - /* - * At the hard limit, we just die. - * No need to calculate anything else now. - */ - __group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk); - return; - } - if (tsk->rt.timeout > DIV_ROUND_UP(*soft, USEC_PER_SEC/HZ)) { - /* - * At the soft limit, send a SIGXCPU every second. - */ - if (sig->rlim[RLIMIT_RTTIME].rlim_cur - < sig->rlim[RLIMIT_RTTIME].rlim_max) { - sig->rlim[RLIMIT_RTTIME].rlim_cur += - USEC_PER_SEC; - } - __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk); - } - } } /* diff --git a/trunk/kernel/printk.c b/trunk/kernel/printk.c index 423a8c765a57..89011bf8c106 100644 --- a/trunk/kernel/printk.c +++ b/trunk/kernel/printk.c @@ -573,6 +573,11 @@ static int __init printk_time_setup(char *str) __setup("time", printk_time_setup); +__attribute__((weak)) unsigned long long printk_clock(void) +{ + return sched_clock(); +} + /* Check if we have any console registered that can be called early in boot. */ static int have_callable_console(void) { @@ -623,57 +628,30 @@ asmlinkage int printk(const char *fmt, ...) /* cpu currently holding logbuf_lock */ static volatile unsigned int printk_cpu = UINT_MAX; -const char printk_recursion_bug_msg [] = - KERN_CRIT "BUG: recent printk recursion!\n"; -static int printk_recursion_bug; - asmlinkage int vprintk(const char *fmt, va_list args) { - static int log_level_unknown = 1; - static char printk_buf[1024]; - unsigned long flags; - int printed_len = 0; - int this_cpu; + int printed_len; char *p; + static char printk_buf[1024]; + static int log_level_unknown = 1; boot_delay_msec(); preempt_disable(); - /* This stops the holder of console_sem just where we want him */ - raw_local_irq_save(flags); - this_cpu = smp_processor_id(); - - /* - * Ouch, printk recursed into itself! - */ - if (unlikely(printk_cpu == this_cpu)) { - /* - * If a crash is occurring during printk() on this CPU, - * then try to get the crash message out but make sure - * we can't deadlock. Otherwise just return to avoid the - * recursion and return - but flag the recursion so that - * it can be printed at the next appropriate moment: - */ - if (!oops_in_progress) { - printk_recursion_bug = 1; - goto out_restore_irqs; - } + if (unlikely(oops_in_progress) && printk_cpu == smp_processor_id()) + /* If a crash is occurring during printk() on this CPU, + * make sure we can't deadlock */ zap_locks(); - } + /* This stops the holder of console_sem just where we want him */ + raw_local_irq_save(flags); lockdep_off(); spin_lock(&logbuf_lock); - printk_cpu = this_cpu; + printk_cpu = smp_processor_id(); - if (printk_recursion_bug) { - printk_recursion_bug = 0; - strcpy(printk_buf, printk_recursion_bug_msg); - printed_len = sizeof(printk_recursion_bug_msg); - } /* Emit the output into the temporary buffer */ - printed_len += vscnprintf(printk_buf + printed_len, - sizeof(printk_buf), fmt, args); + printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); /* * Copy the output into log_buf. If the caller didn't provide @@ -702,9 +680,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) loglev_char = default_message_loglevel + '0'; } - t = 0; - if (system_state != SYSTEM_BOOTING) - t = ktime_to_ns(ktime_get()); + t = printk_clock(); nanosec_rem = do_div(t, 1000000000); tlen = sprintf(tbuf, "<%c>[%5lu.%06lu] ", @@ -768,7 +744,6 @@ asmlinkage int vprintk(const char *fmt, va_list args) printk_cpu = UINT_MAX; spin_unlock(&logbuf_lock); lockdep_on(); -out_restore_irqs: raw_local_irq_restore(flags); } diff --git a/trunk/kernel/profile.c b/trunk/kernel/profile.c index e64c2da11c0f..5e95330e5120 100644 --- a/trunk/kernel/profile.c +++ b/trunk/kernel/profile.c @@ -52,7 +52,7 @@ static DEFINE_PER_CPU(int, cpu_profile_flip); static DEFINE_MUTEX(profile_flip_mutex); #endif /* CONFIG_SMP */ -static int __init profile_setup(char *str) +static int __init profile_setup(char * str) { static char __initdata schedstr[] = "schedule"; static char __initdata sleepstr[] = "sleep"; @@ -104,28 +104,28 @@ __setup("profile=", profile_setup); void __init profile_init(void) { - if (!prof_on) + if (!prof_on) return; - + /* only text is profiled */ prof_len = (_etext - _stext) >> prof_shift; prof_buffer = alloc_bootmem(prof_len*sizeof(atomic_t)); } /* Profile event notifications */ - + #ifdef CONFIG_PROFILING - + static BLOCKING_NOTIFIER_HEAD(task_exit_notifier); static ATOMIC_NOTIFIER_HEAD(task_free_notifier); static BLOCKING_NOTIFIER_HEAD(munmap_notifier); - -void profile_task_exit(struct task_struct *task) + +void profile_task_exit(struct task_struct * task) { blocking_notifier_call_chain(&task_exit_notifier, 0, task); } - -int profile_handoff_task(struct task_struct *task) + +int profile_handoff_task(struct task_struct * task) { int ret; ret = atomic_notifier_call_chain(&task_free_notifier, 0, task); @@ -137,55 +137,52 @@ void profile_munmap(unsigned long addr) blocking_notifier_call_chain(&munmap_notifier, 0, (void *)addr); } -int task_handoff_register(struct notifier_block *n) +int task_handoff_register(struct notifier_block * n) { return atomic_notifier_chain_register(&task_free_notifier, n); } -EXPORT_SYMBOL_GPL(task_handoff_register); -int task_handoff_unregister(struct notifier_block *n) +int task_handoff_unregister(struct notifier_block * n) { return atomic_notifier_chain_unregister(&task_free_notifier, n); } -EXPORT_SYMBOL_GPL(task_handoff_unregister); -int profile_event_register(enum profile_type type, struct notifier_block *n) +int profile_event_register(enum profile_type type, struct notifier_block * n) { int err = -EINVAL; - + switch (type) { - case PROFILE_TASK_EXIT: - err = blocking_notifier_chain_register( - &task_exit_notifier, n); - break; - case PROFILE_MUNMAP: - err = blocking_notifier_chain_register( - &munmap_notifier, n); - break; + case PROFILE_TASK_EXIT: + err = blocking_notifier_chain_register( + &task_exit_notifier, n); + break; + case PROFILE_MUNMAP: + err = blocking_notifier_chain_register( + &munmap_notifier, n); + break; } - + return err; } -EXPORT_SYMBOL_GPL(profile_event_register); -int profile_event_unregister(enum profile_type type, struct notifier_block *n) + +int profile_event_unregister(enum profile_type type, struct notifier_block * n) { int err = -EINVAL; - + switch (type) { - case PROFILE_TASK_EXIT: - err = blocking_notifier_chain_unregister( - &task_exit_notifier, n); - break; - case PROFILE_MUNMAP: - err = blocking_notifier_chain_unregister( - &munmap_notifier, n); - break; + case PROFILE_TASK_EXIT: + err = blocking_notifier_chain_unregister( + &task_exit_notifier, n); + break; + case PROFILE_MUNMAP: + err = blocking_notifier_chain_unregister( + &munmap_notifier, n); + break; } return err; } -EXPORT_SYMBOL_GPL(profile_event_unregister); int register_timer_hook(int (*hook)(struct pt_regs *)) { @@ -194,7 +191,6 @@ int register_timer_hook(int (*hook)(struct pt_regs *)) timer_hook = hook; return 0; } -EXPORT_SYMBOL_GPL(register_timer_hook); void unregister_timer_hook(int (*hook)(struct pt_regs *)) { @@ -203,7 +199,13 @@ void unregister_timer_hook(int (*hook)(struct pt_regs *)) /* make sure all CPUs see the NULL hook */ synchronize_sched(); /* Allow ongoing interrupts to complete. */ } + +EXPORT_SYMBOL_GPL(register_timer_hook); EXPORT_SYMBOL_GPL(unregister_timer_hook); +EXPORT_SYMBOL_GPL(task_handoff_register); +EXPORT_SYMBOL_GPL(task_handoff_unregister); +EXPORT_SYMBOL_GPL(profile_event_register); +EXPORT_SYMBOL_GPL(profile_event_unregister); #endif /* CONFIG_PROFILING */ @@ -364,7 +366,7 @@ static int __devinit profile_cpu_callback(struct notifier_block *info, per_cpu(cpu_profile_hits, cpu)[0] = page_address(page); } break; -out_free: + out_free: page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]); per_cpu(cpu_profile_hits, cpu)[1] = NULL; __free_page(page); @@ -407,6 +409,7 @@ void profile_hits(int type, void *__pc, unsigned int nr_hits) atomic_add(nr_hits, &prof_buffer[min(pc, prof_len - 1)]); } #endif /* !CONFIG_SMP */ + EXPORT_SYMBOL_GPL(profile_hits); void profile_tick(int type) @@ -424,7 +427,7 @@ void profile_tick(int type) #include #include -static int prof_cpu_mask_read_proc(char *page, char **start, off_t off, +static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { int len = cpumask_scnprintf(page, count, *(cpumask_t *)data); @@ -434,8 +437,8 @@ static int prof_cpu_mask_read_proc(char *page, char **start, off_t off, return len; } -static int prof_cpu_mask_write_proc(struct file *file, - const char __user *buffer, unsigned long count, void *data) +static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, + unsigned long count, void *data) { cpumask_t *mask = (cpumask_t *)data; unsigned long full_count = count, err; @@ -454,8 +457,7 @@ void create_prof_cpu_mask(struct proc_dir_entry *root_irq_dir) struct proc_dir_entry *entry; /* create /proc/irq/prof_cpu_mask */ - entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); - if (!entry) + if (!(entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir))) return; entry->data = (void *)&prof_cpu_mask; entry->read_proc = prof_cpu_mask_read_proc; @@ -473,7 +475,7 @@ read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; ssize_t read; - char *pnt; + char * pnt; unsigned int sample_step = 1 << prof_shift; profile_flip_buffers(); @@ -484,12 +486,12 @@ read_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos) read = 0; while (p < sizeof(unsigned int) && count > 0) { - if (put_user(*((char *)(&sample_step)+p), buf)) + if (put_user(*((char *)(&sample_step)+p),buf)) return -EFAULT; buf++; p++; count--; read++; } pnt = (char *)prof_buffer + p - sizeof(atomic_t); - if (copy_to_user(buf, (void *)pnt, count)) + if (copy_to_user(buf,(void *)pnt,count)) return -EFAULT; read += count; *ppos += read; @@ -506,7 +508,7 @@ static ssize_t write_profile(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { #ifdef CONFIG_SMP - extern int setup_profiling_timer(unsigned int multiplier); + extern int setup_profiling_timer (unsigned int multiplier); if (count == sizeof(int)) { unsigned int multiplier; @@ -589,8 +591,7 @@ static int __init create_proc_profile(void) return 0; if (create_hash_tables()) return -1; - entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL); - if (!entry) + if (!(entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL))) return 0; entry->proc_fops = &proc_profile_operations; entry->size = (1+prof_len) * sizeof(atomic_t); diff --git a/trunk/kernel/rcuclassic.c b/trunk/kernel/rcuclassic.c deleted file mode 100644 index f4ffbd0f306f..000000000000 --- a/trunk/kernel/rcuclassic.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2001 - * - * Authors: Dipankar Sarma - * Manfred Spraul - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -static struct lock_class_key rcu_lock_key; -struct lockdep_map rcu_lock_map = - STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key); -EXPORT_SYMBOL_GPL(rcu_lock_map); -#endif - - -/* Definition for rcupdate control block. */ -static struct rcu_ctrlblk rcu_ctrlblk = { - .cur = -300, - .completed = -300, - .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock), - .cpumask = CPU_MASK_NONE, -}; -static struct rcu_ctrlblk rcu_bh_ctrlblk = { - .cur = -300, - .completed = -300, - .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock), - .cpumask = CPU_MASK_NONE, -}; - -DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L }; -DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L }; - -static int blimit = 10; -static int qhimark = 10000; -static int qlowmark = 100; - -#ifdef CONFIG_SMP -static void force_quiescent_state(struct rcu_data *rdp, - struct rcu_ctrlblk *rcp) -{ - int cpu; - cpumask_t cpumask; - set_need_resched(); - if (unlikely(!rcp->signaled)) { - rcp->signaled = 1; - /* - * Don't send IPI to itself. With irqs disabled, - * rdp->cpu is the current cpu. - */ - cpumask = rcp->cpumask; - cpu_clear(rdp->cpu, cpumask); - for_each_cpu_mask(cpu, cpumask) - smp_send_reschedule(cpu); - } -} -#else -static inline void force_quiescent_state(struct rcu_data *rdp, - struct rcu_ctrlblk *rcp) -{ - set_need_resched(); -} -#endif - -/** - * call_rcu - Queue an RCU callback for invocation after a grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual update function to be invoked after the grace period - * - * The update function will be invoked some time after a full grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. RCU read-side critical - * sections are delimited by rcu_read_lock() and rcu_read_unlock(), - * and may be nested. - */ -void call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) -{ - unsigned long flags; - struct rcu_data *rdp; - - head->func = func; - head->next = NULL; - local_irq_save(flags); - rdp = &__get_cpu_var(rcu_data); - *rdp->nxttail = head; - rdp->nxttail = &head->next; - if (unlikely(++rdp->qlen > qhimark)) { - rdp->blimit = INT_MAX; - force_quiescent_state(rdp, &rcu_ctrlblk); - } - local_irq_restore(flags); -} -EXPORT_SYMBOL_GPL(call_rcu); - -/** - * call_rcu_bh - Queue an RCU for invocation after a quicker grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual update function to be invoked after the grace period - * - * The update function will be invoked some time after a full grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. call_rcu_bh() assumes - * that the read-side critical sections end on completion of a softirq - * handler. This means that read-side critical sections in process - * context must not be interrupted by softirqs. This interface is to be - * used when most of the read-side critical sections are in softirq context. - * RCU read-side critical sections are delimited by rcu_read_lock() and - * rcu_read_unlock(), * if in interrupt context or rcu_read_lock_bh() - * and rcu_read_unlock_bh(), if in process context. These may be nested. - */ -void call_rcu_bh(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)) -{ - unsigned long flags; - struct rcu_data *rdp; - - head->func = func; - head->next = NULL; - local_irq_save(flags); - rdp = &__get_cpu_var(rcu_bh_data); - *rdp->nxttail = head; - rdp->nxttail = &head->next; - - if (unlikely(++rdp->qlen > qhimark)) { - rdp->blimit = INT_MAX; - force_quiescent_state(rdp, &rcu_bh_ctrlblk); - } - - local_irq_restore(flags); -} -EXPORT_SYMBOL_GPL(call_rcu_bh); - -/* - * Return the number of RCU batches processed thus far. Useful - * for debug and statistics. - */ -long rcu_batches_completed(void) -{ - return rcu_ctrlblk.completed; -} -EXPORT_SYMBOL_GPL(rcu_batches_completed); - -/* - * Return the number of RCU batches processed thus far. Useful - * for debug and statistics. - */ -long rcu_batches_completed_bh(void) -{ - return rcu_bh_ctrlblk.completed; -} -EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); - -/* Raises the softirq for processing rcu_callbacks. */ -static inline void raise_rcu_softirq(void) -{ - raise_softirq(RCU_SOFTIRQ); - /* - * The smp_mb() here is required to ensure that this cpu's - * __rcu_process_callbacks() reads the most recently updated - * value of rcu->cur. - */ - smp_mb(); -} - -/* - * Invoke the completed RCU callbacks. They are expected to be in - * a per-cpu list. - */ -static void rcu_do_batch(struct rcu_data *rdp) -{ - struct rcu_head *next, *list; - int count = 0; - - list = rdp->donelist; - while (list) { - next = list->next; - prefetch(next); - list->func(list); - list = next; - if (++count >= rdp->blimit) - break; - } - rdp->donelist = list; - - local_irq_disable(); - rdp->qlen -= count; - local_irq_enable(); - if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark) - rdp->blimit = blimit; - - if (!rdp->donelist) - rdp->donetail = &rdp->donelist; - else - raise_rcu_softirq(); -} - -/* - * Grace period handling: - * The grace period handling consists out of two steps: - * - A new grace period is started. - * This is done by rcu_start_batch. The start is not broadcasted to - * all cpus, they must pick this up by comparing rcp->cur with - * rdp->quiescbatch. All cpus are recorded in the - * rcu_ctrlblk.cpumask bitmap. - * - All cpus must go through a quiescent state. - * Since the start of the grace period is not broadcasted, at least two - * calls to rcu_check_quiescent_state are required: - * The first call just notices that a new grace period is running. The - * following calls check if there was a quiescent state since the beginning - * of the grace period. If so, it updates rcu_ctrlblk.cpumask. If - * the bitmap is empty, then the grace period is completed. - * rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace - * period (if necessary). - */ -/* - * Register a new batch of callbacks, and start it up if there is currently no - * active batch and the batch to be registered has not already occurred. - * Caller must hold rcu_ctrlblk.lock. - */ -static void rcu_start_batch(struct rcu_ctrlblk *rcp) -{ - if (rcp->next_pending && - rcp->completed == rcp->cur) { - rcp->next_pending = 0; - /* - * next_pending == 0 must be visible in - * __rcu_process_callbacks() before it can see new value of cur. - */ - smp_wmb(); - rcp->cur++; - - /* - * Accessing nohz_cpu_mask before incrementing rcp->cur needs a - * Barrier Otherwise it can cause tickless idle CPUs to be - * included in rcp->cpumask, which will extend graceperiods - * unnecessarily. - */ - smp_mb(); - cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask); - - rcp->signaled = 0; - } -} - -/* - * cpu went through a quiescent state since the beginning of the grace period. - * Clear it from the cpu mask and complete the grace period if it was the last - * cpu. Start another grace period if someone has further entries pending - */ -static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp) -{ - cpu_clear(cpu, rcp->cpumask); - if (cpus_empty(rcp->cpumask)) { - /* batch completed ! */ - rcp->completed = rcp->cur; - rcu_start_batch(rcp); - } -} - -/* - * Check if the cpu has gone through a quiescent state (say context - * switch). If so and if it already hasn't done so in this RCU - * quiescent cycle, then indicate that it has done so. - */ -static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - if (rdp->quiescbatch != rcp->cur) { - /* start new grace period: */ - rdp->qs_pending = 1; - rdp->passed_quiesc = 0; - rdp->quiescbatch = rcp->cur; - return; - } - - /* Grace period already completed for this cpu? - * qs_pending is checked instead of the actual bitmap to avoid - * cacheline trashing. - */ - if (!rdp->qs_pending) - return; - - /* - * Was there a quiescent state since the beginning of the grace - * period? If no, then exit and wait for the next call. - */ - if (!rdp->passed_quiesc) - return; - rdp->qs_pending = 0; - - spin_lock(&rcp->lock); - /* - * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync - * during cpu startup. Ignore the quiescent state. - */ - if (likely(rdp->quiescbatch == rcp->cur)) - cpu_quiet(rdp->cpu, rcp); - - spin_unlock(&rcp->lock); -} - - -#ifdef CONFIG_HOTPLUG_CPU - -/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing - * locking requirements, the list it's pulling from has to belong to a cpu - * which is dead and hence not processing interrupts. - */ -static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list, - struct rcu_head **tail) -{ - local_irq_disable(); - *this_rdp->nxttail = list; - if (list) - this_rdp->nxttail = tail; - local_irq_enable(); -} - -static void __rcu_offline_cpu(struct rcu_data *this_rdp, - struct rcu_ctrlblk *rcp, struct rcu_data *rdp) -{ - /* if the cpu going offline owns the grace period - * we can block indefinitely waiting for it, so flush - * it here - */ - spin_lock_bh(&rcp->lock); - if (rcp->cur != rcp->completed) - cpu_quiet(rdp->cpu, rcp); - spin_unlock_bh(&rcp->lock); - rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail); - rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail); - rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail); -} - -static void rcu_offline_cpu(int cpu) -{ - struct rcu_data *this_rdp = &get_cpu_var(rcu_data); - struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data); - - __rcu_offline_cpu(this_rdp, &rcu_ctrlblk, - &per_cpu(rcu_data, cpu)); - __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk, - &per_cpu(rcu_bh_data, cpu)); - put_cpu_var(rcu_data); - put_cpu_var(rcu_bh_data); -} - -#else - -static void rcu_offline_cpu(int cpu) -{ -} - -#endif - -/* - * This does the RCU processing work from softirq context. - */ -static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) { - *rdp->donetail = rdp->curlist; - rdp->donetail = rdp->curtail; - rdp->curlist = NULL; - rdp->curtail = &rdp->curlist; - } - - if (rdp->nxtlist && !rdp->curlist) { - local_irq_disable(); - rdp->curlist = rdp->nxtlist; - rdp->curtail = rdp->nxttail; - rdp->nxtlist = NULL; - rdp->nxttail = &rdp->nxtlist; - local_irq_enable(); - - /* - * start the next batch of callbacks - */ - - /* determine batch number */ - rdp->batch = rcp->cur + 1; - /* see the comment and corresponding wmb() in - * the rcu_start_batch() - */ - smp_rmb(); - - if (!rcp->next_pending) { - /* and start it/schedule start if it's a new batch */ - spin_lock(&rcp->lock); - rcp->next_pending = 1; - rcu_start_batch(rcp); - spin_unlock(&rcp->lock); - } - } - - rcu_check_quiescent_state(rcp, rdp); - if (rdp->donelist) - rcu_do_batch(rdp); -} - -static void rcu_process_callbacks(struct softirq_action *unused) -{ - __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data)); - __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); -} - -static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) -{ - /* This cpu has pending rcu entries and the grace period - * for them has completed. - */ - if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) - return 1; - - /* This cpu has no pending entries, but there are new entries */ - if (!rdp->curlist && rdp->nxtlist) - return 1; - - /* This cpu has finished callbacks to invoke */ - if (rdp->donelist) - return 1; - - /* The rcu core waits for a quiescent state from the cpu */ - if (rdp->quiescbatch != rcp->cur || rdp->qs_pending) - return 1; - - /* nothing to do */ - return 0; -} - -/* - * Check to see if there is any immediate RCU-related work to be done - * by the current CPU, returning 1 if so. This function is part of the - * RCU implementation; it is -not- an exported member of the RCU API. - */ -int rcu_pending(int cpu) -{ - return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || - __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); -} - -/* - * Check to see if any future RCU-related work will need to be done - * by the current CPU, even if none need be done immediately, returning - * 1 if so. This function is part of the RCU implementation; it is -not- - * an exported member of the RCU API. - */ -int rcu_needs_cpu(int cpu) -{ - struct rcu_data *rdp = &per_cpu(rcu_data, cpu); - struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu); - - return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu)); -} - -void rcu_check_callbacks(int cpu, int user) -{ - if (user || - (idle_cpu(cpu) && !in_softirq() && - hardirq_count() <= (1 << HARDIRQ_SHIFT))) { - rcu_qsctr_inc(cpu); - rcu_bh_qsctr_inc(cpu); - } else if (!in_softirq()) - rcu_bh_qsctr_inc(cpu); - raise_rcu_softirq(); -} - -static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, - struct rcu_data *rdp) -{ - memset(rdp, 0, sizeof(*rdp)); - rdp->curtail = &rdp->curlist; - rdp->nxttail = &rdp->nxtlist; - rdp->donetail = &rdp->donelist; - rdp->quiescbatch = rcp->completed; - rdp->qs_pending = 0; - rdp->cpu = cpu; - rdp->blimit = blimit; -} - -static void __cpuinit rcu_online_cpu(int cpu) -{ - struct rcu_data *rdp = &per_cpu(rcu_data, cpu); - struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu); - - rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp); - rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp); - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL); -} - -static int __cpuinit rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - long cpu = (long)hcpu; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - rcu_online_cpu(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - rcu_offline_cpu(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - -static struct notifier_block __cpuinitdata rcu_nb = { - .notifier_call = rcu_cpu_notify, -}; - -/* - * Initializes rcu mechanism. Assumed to be called early. - * That is before local timer(SMP) or jiffie timer (uniproc) is setup. - * Note that rcu_qsctr and friends are implicitly - * initialized due to the choice of ``0'' for RCU_CTR_INVALID. - */ -void __init __rcu_init(void) -{ - rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, - (void *)(long)smp_processor_id()); - /* Register notifier for non-boot CPUs */ - register_cpu_notifier(&rcu_nb); -} - -module_param(blimit, int, 0); -module_param(qhimark, int, 0); -module_param(qlowmark, int, 0); diff --git a/trunk/kernel/rcupdate.c b/trunk/kernel/rcupdate.c index 760dfc233a00..f2c1a04e9b18 100644 --- a/trunk/kernel/rcupdate.c +++ b/trunk/kernel/rcupdate.c @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * Copyright IBM Corporation, 2001 + * Copyright (C) IBM Corporation, 2001 * * Authors: Dipankar Sarma * Manfred Spraul @@ -35,57 +35,165 @@ #include #include #include +#include #include #include #include #include +#include #include +#include #include #include #include #include -#include -struct rcu_synchronize { - struct rcu_head head; - struct completion completion; +#ifdef CONFIG_DEBUG_LOCK_ALLOC +static struct lock_class_key rcu_lock_key; +struct lockdep_map rcu_lock_map = + STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key); + +EXPORT_SYMBOL_GPL(rcu_lock_map); +#endif + +/* Definition for rcupdate control block. */ +static struct rcu_ctrlblk rcu_ctrlblk = { + .cur = -300, + .completed = -300, + .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock), + .cpumask = CPU_MASK_NONE, +}; +static struct rcu_ctrlblk rcu_bh_ctrlblk = { + .cur = -300, + .completed = -300, + .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock), + .cpumask = CPU_MASK_NONE, }; -static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL}; +DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L }; +DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L }; + +/* Fake initialization required by compiler */ +static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL}; +static int blimit = 10; +static int qhimark = 10000; +static int qlowmark = 100; + static atomic_t rcu_barrier_cpu_count; static DEFINE_MUTEX(rcu_barrier_mutex); static struct completion rcu_barrier_completion; -/* Because of FASTCALL declaration of complete, we use this wrapper */ -static void wakeme_after_rcu(struct rcu_head *head) +#ifdef CONFIG_SMP +static void force_quiescent_state(struct rcu_data *rdp, + struct rcu_ctrlblk *rcp) { - struct rcu_synchronize *rcu; - - rcu = container_of(head, struct rcu_synchronize, head); - complete(&rcu->completion); + int cpu; + cpumask_t cpumask; + set_need_resched(); + if (unlikely(!rcp->signaled)) { + rcp->signaled = 1; + /* + * Don't send IPI to itself. With irqs disabled, + * rdp->cpu is the current cpu. + */ + cpumask = rcp->cpumask; + cpu_clear(rdp->cpu, cpumask); + for_each_cpu_mask(cpu, cpumask) + smp_send_reschedule(cpu); + } +} +#else +static inline void force_quiescent_state(struct rcu_data *rdp, + struct rcu_ctrlblk *rcp) +{ + set_need_resched(); } +#endif /** - * synchronize_rcu - wait until a grace period has elapsed. + * call_rcu - Queue an RCU callback for invocation after a grace period. + * @head: structure to be used for queueing the RCU updates. + * @func: actual update function to be invoked after the grace period * - * Control will return to the caller some time after a full grace - * period has elapsed, in other words after all currently executing RCU + * The update function will be invoked some time after a full grace + * period elapses, in other words after all currently executing RCU * read-side critical sections have completed. RCU read-side critical * sections are delimited by rcu_read_lock() and rcu_read_unlock(), * and may be nested. */ -void synchronize_rcu(void) +void fastcall call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *rcu)) { - struct rcu_synchronize rcu; + unsigned long flags; + struct rcu_data *rdp; - init_completion(&rcu.completion); - /* Will wake me after RCU finished */ - call_rcu(&rcu.head, wakeme_after_rcu); + head->func = func; + head->next = NULL; + local_irq_save(flags); + rdp = &__get_cpu_var(rcu_data); + *rdp->nxttail = head; + rdp->nxttail = &head->next; + if (unlikely(++rdp->qlen > qhimark)) { + rdp->blimit = INT_MAX; + force_quiescent_state(rdp, &rcu_ctrlblk); + } + local_irq_restore(flags); +} - /* Wait for it */ - wait_for_completion(&rcu.completion); +/** + * call_rcu_bh - Queue an RCU for invocation after a quicker grace period. + * @head: structure to be used for queueing the RCU updates. + * @func: actual update function to be invoked after the grace period + * + * The update function will be invoked some time after a full grace + * period elapses, in other words after all currently executing RCU + * read-side critical sections have completed. call_rcu_bh() assumes + * that the read-side critical sections end on completion of a softirq + * handler. This means that read-side critical sections in process + * context must not be interrupted by softirqs. This interface is to be + * used when most of the read-side critical sections are in softirq context. + * RCU read-side critical sections are delimited by rcu_read_lock() and + * rcu_read_unlock(), * if in interrupt context or rcu_read_lock_bh() + * and rcu_read_unlock_bh(), if in process context. These may be nested. + */ +void fastcall call_rcu_bh(struct rcu_head *head, + void (*func)(struct rcu_head *rcu)) +{ + unsigned long flags; + struct rcu_data *rdp; + + head->func = func; + head->next = NULL; + local_irq_save(flags); + rdp = &__get_cpu_var(rcu_bh_data); + *rdp->nxttail = head; + rdp->nxttail = &head->next; + + if (unlikely(++rdp->qlen > qhimark)) { + rdp->blimit = INT_MAX; + force_quiescent_state(rdp, &rcu_bh_ctrlblk); + } + + local_irq_restore(flags); +} + +/* + * Return the number of RCU batches processed thus far. Useful + * for debug and statistics. + */ +long rcu_batches_completed(void) +{ + return rcu_ctrlblk.completed; +} + +/* + * Return the number of RCU batches processed thus far. Useful + * for debug and statistics. + */ +long rcu_batches_completed_bh(void) +{ + return rcu_bh_ctrlblk.completed; } -EXPORT_SYMBOL_GPL(synchronize_rcu); static void rcu_barrier_callback(struct rcu_head *notused) { @@ -99,8 +207,10 @@ static void rcu_barrier_callback(struct rcu_head *notused) static void rcu_barrier_func(void *notused) { int cpu = smp_processor_id(); - struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu); + struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + struct rcu_head *head; + head = &rdp->barrier; atomic_inc(&rcu_barrier_cpu_count); call_rcu(head, rcu_barrier_callback); } @@ -115,24 +225,420 @@ void rcu_barrier(void) mutex_lock(&rcu_barrier_mutex); init_completion(&rcu_barrier_completion); atomic_set(&rcu_barrier_cpu_count, 0); - /* - * The queueing of callbacks in all CPUs must be atomic with - * respect to RCU, otherwise one CPU may queue a callback, - * wait for a grace period, decrement barrier count and call - * complete(), while other CPUs have not yet queued anything. - * So, we need to make sure that grace periods cannot complete - * until all the callbacks are queued. - */ - rcu_read_lock(); on_each_cpu(rcu_barrier_func, NULL, 0, 1); - rcu_read_unlock(); wait_for_completion(&rcu_barrier_completion); mutex_unlock(&rcu_barrier_mutex); } EXPORT_SYMBOL_GPL(rcu_barrier); +/* + * Invoke the completed RCU callbacks. They are expected to be in + * a per-cpu list. + */ +static void rcu_do_batch(struct rcu_data *rdp) +{ + struct rcu_head *next, *list; + int count = 0; + + list = rdp->donelist; + while (list) { + next = list->next; + prefetch(next); + list->func(list); + list = next; + if (++count >= rdp->blimit) + break; + } + rdp->donelist = list; + + local_irq_disable(); + rdp->qlen -= count; + local_irq_enable(); + if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark) + rdp->blimit = blimit; + + if (!rdp->donelist) + rdp->donetail = &rdp->donelist; + else + tasklet_schedule(&per_cpu(rcu_tasklet, rdp->cpu)); +} + +/* + * Grace period handling: + * The grace period handling consists out of two steps: + * - A new grace period is started. + * This is done by rcu_start_batch. The start is not broadcasted to + * all cpus, they must pick this up by comparing rcp->cur with + * rdp->quiescbatch. All cpus are recorded in the + * rcu_ctrlblk.cpumask bitmap. + * - All cpus must go through a quiescent state. + * Since the start of the grace period is not broadcasted, at least two + * calls to rcu_check_quiescent_state are required: + * The first call just notices that a new grace period is running. The + * following calls check if there was a quiescent state since the beginning + * of the grace period. If so, it updates rcu_ctrlblk.cpumask. If + * the bitmap is empty, then the grace period is completed. + * rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace + * period (if necessary). + */ +/* + * Register a new batch of callbacks, and start it up if there is currently no + * active batch and the batch to be registered has not already occurred. + * Caller must hold rcu_ctrlblk.lock. + */ +static void rcu_start_batch(struct rcu_ctrlblk *rcp) +{ + if (rcp->next_pending && + rcp->completed == rcp->cur) { + rcp->next_pending = 0; + /* + * next_pending == 0 must be visible in + * __rcu_process_callbacks() before it can see new value of cur. + */ + smp_wmb(); + rcp->cur++; + + /* + * Accessing nohz_cpu_mask before incrementing rcp->cur needs a + * Barrier Otherwise it can cause tickless idle CPUs to be + * included in rcp->cpumask, which will extend graceperiods + * unnecessarily. + */ + smp_mb(); + cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask); + + rcp->signaled = 0; + } +} + +/* + * cpu went through a quiescent state since the beginning of the grace period. + * Clear it from the cpu mask and complete the grace period if it was the last + * cpu. Start another grace period if someone has further entries pending + */ +static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp) +{ + cpu_clear(cpu, rcp->cpumask); + if (cpus_empty(rcp->cpumask)) { + /* batch completed ! */ + rcp->completed = rcp->cur; + rcu_start_batch(rcp); + } +} + +/* + * Check if the cpu has gone through a quiescent state (say context + * switch). If so and if it already hasn't done so in this RCU + * quiescent cycle, then indicate that it has done so. + */ +static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp, + struct rcu_data *rdp) +{ + if (rdp->quiescbatch != rcp->cur) { + /* start new grace period: */ + rdp->qs_pending = 1; + rdp->passed_quiesc = 0; + rdp->quiescbatch = rcp->cur; + return; + } + + /* Grace period already completed for this cpu? + * qs_pending is checked instead of the actual bitmap to avoid + * cacheline trashing. + */ + if (!rdp->qs_pending) + return; + + /* + * Was there a quiescent state since the beginning of the grace + * period? If no, then exit and wait for the next call. + */ + if (!rdp->passed_quiesc) + return; + rdp->qs_pending = 0; + + spin_lock(&rcp->lock); + /* + * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync + * during cpu startup. Ignore the quiescent state. + */ + if (likely(rdp->quiescbatch == rcp->cur)) + cpu_quiet(rdp->cpu, rcp); + + spin_unlock(&rcp->lock); +} + + +#ifdef CONFIG_HOTPLUG_CPU + +/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing + * locking requirements, the list it's pulling from has to belong to a cpu + * which is dead and hence not processing interrupts. + */ +static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list, + struct rcu_head **tail) +{ + local_irq_disable(); + *this_rdp->nxttail = list; + if (list) + this_rdp->nxttail = tail; + local_irq_enable(); +} + +static void __rcu_offline_cpu(struct rcu_data *this_rdp, + struct rcu_ctrlblk *rcp, struct rcu_data *rdp) +{ + /* if the cpu going offline owns the grace period + * we can block indefinitely waiting for it, so flush + * it here + */ + spin_lock_bh(&rcp->lock); + if (rcp->cur != rcp->completed) + cpu_quiet(rdp->cpu, rcp); + spin_unlock_bh(&rcp->lock); + rcu_move_batch(this_rdp, rdp->curlist, rdp->curtail); + rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail); + rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail); +} + +static void rcu_offline_cpu(int cpu) +{ + struct rcu_data *this_rdp = &get_cpu_var(rcu_data); + struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data); + + __rcu_offline_cpu(this_rdp, &rcu_ctrlblk, + &per_cpu(rcu_data, cpu)); + __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk, + &per_cpu(rcu_bh_data, cpu)); + put_cpu_var(rcu_data); + put_cpu_var(rcu_bh_data); + tasklet_kill_immediate(&per_cpu(rcu_tasklet, cpu), cpu); +} + +#else + +static void rcu_offline_cpu(int cpu) +{ +} + +#endif + +/* + * This does the RCU processing work from tasklet context. + */ +static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp, + struct rcu_data *rdp) +{ + if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) { + *rdp->donetail = rdp->curlist; + rdp->donetail = rdp->curtail; + rdp->curlist = NULL; + rdp->curtail = &rdp->curlist; + } + + if (rdp->nxtlist && !rdp->curlist) { + local_irq_disable(); + rdp->curlist = rdp->nxtlist; + rdp->curtail = rdp->nxttail; + rdp->nxtlist = NULL; + rdp->nxttail = &rdp->nxtlist; + local_irq_enable(); + + /* + * start the next batch of callbacks + */ + + /* determine batch number */ + rdp->batch = rcp->cur + 1; + /* see the comment and corresponding wmb() in + * the rcu_start_batch() + */ + smp_rmb(); + + if (!rcp->next_pending) { + /* and start it/schedule start if it's a new batch */ + spin_lock(&rcp->lock); + rcp->next_pending = 1; + rcu_start_batch(rcp); + spin_unlock(&rcp->lock); + } + } + + rcu_check_quiescent_state(rcp, rdp); + if (rdp->donelist) + rcu_do_batch(rdp); +} + +static void rcu_process_callbacks(unsigned long unused) +{ + __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data)); + __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data)); +} + +static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) +{ + /* This cpu has pending rcu entries and the grace period + * for them has completed. + */ + if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) + return 1; + + /* This cpu has no pending entries, but there are new entries */ + if (!rdp->curlist && rdp->nxtlist) + return 1; + + /* This cpu has finished callbacks to invoke */ + if (rdp->donelist) + return 1; + + /* The rcu core waits for a quiescent state from the cpu */ + if (rdp->quiescbatch != rcp->cur || rdp->qs_pending) + return 1; + + /* nothing to do */ + return 0; +} + +/* + * Check to see if there is any immediate RCU-related work to be done + * by the current CPU, returning 1 if so. This function is part of the + * RCU implementation; it is -not- an exported member of the RCU API. + */ +int rcu_pending(int cpu) +{ + return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || + __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); +} + +/* + * Check to see if any future RCU-related work will need to be done + * by the current CPU, even if none need be done immediately, returning + * 1 if so. This function is part of the RCU implementation; it is -not- + * an exported member of the RCU API. + */ +int rcu_needs_cpu(int cpu) +{ + struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu); + + return (!!rdp->curlist || !!rdp_bh->curlist || rcu_pending(cpu)); +} + +void rcu_check_callbacks(int cpu, int user) +{ + if (user || + (idle_cpu(cpu) && !in_softirq() && + hardirq_count() <= (1 << HARDIRQ_SHIFT))) { + rcu_qsctr_inc(cpu); + rcu_bh_qsctr_inc(cpu); + } else if (!in_softirq()) + rcu_bh_qsctr_inc(cpu); + tasklet_schedule(&per_cpu(rcu_tasklet, cpu)); +} + +static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, + struct rcu_data *rdp) +{ + memset(rdp, 0, sizeof(*rdp)); + rdp->curtail = &rdp->curlist; + rdp->nxttail = &rdp->nxtlist; + rdp->donetail = &rdp->donelist; + rdp->quiescbatch = rcp->completed; + rdp->qs_pending = 0; + rdp->cpu = cpu; + rdp->blimit = blimit; +} + +static void __cpuinit rcu_online_cpu(int cpu) +{ + struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu); + + rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp); + rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp); + tasklet_init(&per_cpu(rcu_tasklet, cpu), rcu_process_callbacks, 0UL); +} + +static int __cpuinit rcu_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + long cpu = (long)hcpu; + switch (action) { + case CPU_UP_PREPARE: + case CPU_UP_PREPARE_FROZEN: + rcu_online_cpu(cpu); + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: + rcu_offline_cpu(cpu); + break; + default: + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata rcu_nb = { + .notifier_call = rcu_cpu_notify, +}; + +/* + * Initializes rcu mechanism. Assumed to be called early. + * That is before local timer(SMP) or jiffie timer (uniproc) is setup. + * Note that rcu_qsctr and friends are implicitly + * initialized due to the choice of ``0'' for RCU_CTR_INVALID. + */ void __init rcu_init(void) { - __rcu_init(); + rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, + (void *)(long)smp_processor_id()); + /* Register notifier for non-boot CPUs */ + register_cpu_notifier(&rcu_nb); +} + +struct rcu_synchronize { + struct rcu_head head; + struct completion completion; +}; + +/* Because of FASTCALL declaration of complete, we use this wrapper */ +static void wakeme_after_rcu(struct rcu_head *head) +{ + struct rcu_synchronize *rcu; + + rcu = container_of(head, struct rcu_synchronize, head); + complete(&rcu->completion); } +/** + * synchronize_rcu - wait until a grace period has elapsed. + * + * Control will return to the caller some time after a full grace + * period has elapsed, in other words after all currently executing RCU + * read-side critical sections have completed. RCU read-side critical + * sections are delimited by rcu_read_lock() and rcu_read_unlock(), + * and may be nested. + * + * If your read-side code is not protected by rcu_read_lock(), do -not- + * use synchronize_rcu(). + */ +void synchronize_rcu(void) +{ + struct rcu_synchronize rcu; + + init_completion(&rcu.completion); + /* Will wake me after RCU finished */ + call_rcu(&rcu.head, wakeme_after_rcu); + + /* Wait for it */ + wait_for_completion(&rcu.completion); +} + +module_param(blimit, int, 0); +module_param(qhimark, int, 0); +module_param(qlowmark, int, 0); +EXPORT_SYMBOL_GPL(rcu_batches_completed); +EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); +EXPORT_SYMBOL_GPL(call_rcu); +EXPORT_SYMBOL_GPL(call_rcu_bh); +EXPORT_SYMBOL_GPL(synchronize_rcu); diff --git a/trunk/kernel/rcupreempt.c b/trunk/kernel/rcupreempt.c deleted file mode 100644 index 987cfb7ade89..000000000000 --- a/trunk/kernel/rcupreempt.c +++ /dev/null @@ -1,953 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion, realtime implementation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2006 - * - * Authors: Paul E. McKenney - * With thanks to Esben Nielsen, Bill Huey, and Ingo Molnar - * for pushing me away from locks and towards counters, and - * to Suparna Bhattacharya for pushing me completely away - * from atomic instructions on the read side. - * - * Papers: http://www.rdrop.com/users/paulmck/RCU - * - * Design Document: http://lwn.net/Articles/253651/ - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Macro that prevents the compiler from reordering accesses, but does - * absolutely -nothing- to prevent CPUs from reordering. This is used - * only to mediate communication between mainline code and hardware - * interrupt and NMI handlers. - */ -#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) - -/* - * PREEMPT_RCU data structures. - */ - -/* - * GP_STAGES specifies the number of times the state machine has - * to go through the all the rcu_try_flip_states (see below) - * in a single Grace Period. - * - * GP in GP_STAGES stands for Grace Period ;) - */ -#define GP_STAGES 2 -struct rcu_data { - spinlock_t lock; /* Protect rcu_data fields. */ - long completed; /* Number of last completed batch. */ - int waitlistcount; - struct tasklet_struct rcu_tasklet; - struct rcu_head *nextlist; - struct rcu_head **nexttail; - struct rcu_head *waitlist[GP_STAGES]; - struct rcu_head **waittail[GP_STAGES]; - struct rcu_head *donelist; - struct rcu_head **donetail; - long rcu_flipctr[2]; -#ifdef CONFIG_RCU_TRACE - struct rcupreempt_trace trace; -#endif /* #ifdef CONFIG_RCU_TRACE */ -}; - -/* - * States for rcu_try_flip() and friends. - */ - -enum rcu_try_flip_states { - - /* - * Stay here if nothing is happening. Flip the counter if somthing - * starts happening. Denoted by "I" - */ - rcu_try_flip_idle_state, - - /* - * Wait here for all CPUs to notice that the counter has flipped. This - * prevents the old set of counters from ever being incremented once - * we leave this state, which in turn is necessary because we cannot - * test any individual counter for zero -- we can only check the sum. - * Denoted by "A". - */ - rcu_try_flip_waitack_state, - - /* - * Wait here for the sum of the old per-CPU counters to reach zero. - * Denoted by "Z". - */ - rcu_try_flip_waitzero_state, - - /* - * Wait here for each of the other CPUs to execute a memory barrier. - * This is necessary to ensure that these other CPUs really have - * completed executing their RCU read-side critical sections, despite - * their CPUs wildly reordering memory. Denoted by "M". - */ - rcu_try_flip_waitmb_state, -}; - -struct rcu_ctrlblk { - spinlock_t fliplock; /* Protect state-machine transitions. */ - long completed; /* Number of last completed batch. */ - enum rcu_try_flip_states rcu_try_flip_state; /* The current state of - the rcu state machine */ -}; - -static DEFINE_PER_CPU(struct rcu_data, rcu_data); -static struct rcu_ctrlblk rcu_ctrlblk = { - .fliplock = __SPIN_LOCK_UNLOCKED(rcu_ctrlblk.fliplock), - .completed = 0, - .rcu_try_flip_state = rcu_try_flip_idle_state, -}; - - -#ifdef CONFIG_RCU_TRACE -static char *rcu_try_flip_state_names[] = - { "idle", "waitack", "waitzero", "waitmb" }; -#endif /* #ifdef CONFIG_RCU_TRACE */ - -static cpumask_t rcu_cpu_online_map __read_mostly = CPU_MASK_NONE; - -/* - * Enum and per-CPU flag to determine when each CPU has seen - * the most recent counter flip. - */ - -enum rcu_flip_flag_values { - rcu_flip_seen, /* Steady/initial state, last flip seen. */ - /* Only GP detector can update. */ - rcu_flipped /* Flip just completed, need confirmation. */ - /* Only corresponding CPU can update. */ -}; -static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_flip_flag_values, rcu_flip_flag) - = rcu_flip_seen; - -/* - * Enum and per-CPU flag to determine when each CPU has executed the - * needed memory barrier to fence in memory references from its last RCU - * read-side critical section in the just-completed grace period. - */ - -enum rcu_mb_flag_values { - rcu_mb_done, /* Steady/initial state, no mb()s required. */ - /* Only GP detector can update. */ - rcu_mb_needed /* Flip just completed, need an mb(). */ - /* Only corresponding CPU can update. */ -}; -static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_mb_flag_values, rcu_mb_flag) - = rcu_mb_done; - -/* - * RCU_DATA_ME: find the current CPU's rcu_data structure. - * RCU_DATA_CPU: find the specified CPU's rcu_data structure. - */ -#define RCU_DATA_ME() (&__get_cpu_var(rcu_data)) -#define RCU_DATA_CPU(cpu) (&per_cpu(rcu_data, cpu)) - -/* - * Helper macro for tracing when the appropriate rcu_data is not - * cached in a local variable, but where the CPU number is so cached. - */ -#define RCU_TRACE_CPU(f, cpu) RCU_TRACE(f, &(RCU_DATA_CPU(cpu)->trace)); - -/* - * Helper macro for tracing when the appropriate rcu_data is not - * cached in a local variable. - */ -#define RCU_TRACE_ME(f) RCU_TRACE(f, &(RCU_DATA_ME()->trace)); - -/* - * Helper macro for tracing when the appropriate rcu_data is pointed - * to by a local variable. - */ -#define RCU_TRACE_RDP(f, rdp) RCU_TRACE(f, &((rdp)->trace)); - -/* - * Return the number of RCU batches processed thus far. Useful - * for debug and statistics. - */ -long rcu_batches_completed(void) -{ - return rcu_ctrlblk.completed; -} -EXPORT_SYMBOL_GPL(rcu_batches_completed); - -EXPORT_SYMBOL_GPL(rcu_batches_completed_bh); - -void __rcu_read_lock(void) -{ - int idx; - struct task_struct *t = current; - int nesting; - - nesting = ACCESS_ONCE(t->rcu_read_lock_nesting); - if (nesting != 0) { - - /* An earlier rcu_read_lock() covers us, just count it. */ - - t->rcu_read_lock_nesting = nesting + 1; - - } else { - unsigned long flags; - - /* - * We disable interrupts for the following reasons: - * - If we get scheduling clock interrupt here, and we - * end up acking the counter flip, it's like a promise - * that we will never increment the old counter again. - * Thus we will break that promise if that - * scheduling clock interrupt happens between the time - * we pick the .completed field and the time that we - * increment our counter. - * - * - We don't want to be preempted out here. - * - * NMIs can still occur, of course, and might themselves - * contain rcu_read_lock(). - */ - - local_irq_save(flags); - - /* - * Outermost nesting of rcu_read_lock(), so increment - * the current counter for the current CPU. Use volatile - * casts to prevent the compiler from reordering. - */ - - idx = ACCESS_ONCE(rcu_ctrlblk.completed) & 0x1; - ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])++; - - /* - * Now that the per-CPU counter has been incremented, we - * are protected from races with rcu_read_lock() invoked - * from NMI handlers on this CPU. We can therefore safely - * increment the nesting counter, relieving further NMIs - * of the need to increment the per-CPU counter. - */ - - ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting + 1; - - /* - * Now that we have preventing any NMIs from storing - * to the ->rcu_flipctr_idx, we can safely use it to - * remember which counter to decrement in the matching - * rcu_read_unlock(). - */ - - ACCESS_ONCE(t->rcu_flipctr_idx) = idx; - local_irq_restore(flags); - } -} -EXPORT_SYMBOL_GPL(__rcu_read_lock); - -void __rcu_read_unlock(void) -{ - int idx; - struct task_struct *t = current; - int nesting; - - nesting = ACCESS_ONCE(t->rcu_read_lock_nesting); - if (nesting > 1) { - - /* - * We are still protected by the enclosing rcu_read_lock(), - * so simply decrement the counter. - */ - - t->rcu_read_lock_nesting = nesting - 1; - - } else { - unsigned long flags; - - /* - * Disable local interrupts to prevent the grace-period - * detection state machine from seeing us half-done. - * NMIs can still occur, of course, and might themselves - * contain rcu_read_lock() and rcu_read_unlock(). - */ - - local_irq_save(flags); - - /* - * Outermost nesting of rcu_read_unlock(), so we must - * decrement the current counter for the current CPU. - * This must be done carefully, because NMIs can - * occur at any point in this code, and any rcu_read_lock() - * and rcu_read_unlock() pairs in the NMI handlers - * must interact non-destructively with this code. - * Lots of volatile casts, and -very- careful ordering. - * - * Changes to this code, including this one, must be - * inspected, validated, and tested extremely carefully!!! - */ - - /* - * First, pick up the index. - */ - - idx = ACCESS_ONCE(t->rcu_flipctr_idx); - - /* - * Now that we have fetched the counter index, it is - * safe to decrement the per-task RCU nesting counter. - * After this, any interrupts or NMIs will increment and - * decrement the per-CPU counters. - */ - ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting - 1; - - /* - * It is now safe to decrement this task's nesting count. - * NMIs that occur after this statement will route their - * rcu_read_lock() calls through this "else" clause, and - * will thus start incrementing the per-CPU counter on - * their own. They will also clobber ->rcu_flipctr_idx, - * but that is OK, since we have already fetched it. - */ - - ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])--; - local_irq_restore(flags); - } -} -EXPORT_SYMBOL_GPL(__rcu_read_unlock); - -/* - * If a global counter flip has occurred since the last time that we - * advanced callbacks, advance them. Hardware interrupts must be - * disabled when calling this function. - */ -static void __rcu_advance_callbacks(struct rcu_data *rdp) -{ - int cpu; - int i; - int wlc = 0; - - if (rdp->completed != rcu_ctrlblk.completed) { - if (rdp->waitlist[GP_STAGES - 1] != NULL) { - *rdp->donetail = rdp->waitlist[GP_STAGES - 1]; - rdp->donetail = rdp->waittail[GP_STAGES - 1]; - RCU_TRACE_RDP(rcupreempt_trace_move2done, rdp); - } - for (i = GP_STAGES - 2; i >= 0; i--) { - if (rdp->waitlist[i] != NULL) { - rdp->waitlist[i + 1] = rdp->waitlist[i]; - rdp->waittail[i + 1] = rdp->waittail[i]; - wlc++; - } else { - rdp->waitlist[i + 1] = NULL; - rdp->waittail[i + 1] = - &rdp->waitlist[i + 1]; - } - } - if (rdp->nextlist != NULL) { - rdp->waitlist[0] = rdp->nextlist; - rdp->waittail[0] = rdp->nexttail; - wlc++; - rdp->nextlist = NULL; - rdp->nexttail = &rdp->nextlist; - RCU_TRACE_RDP(rcupreempt_trace_move2wait, rdp); - } else { - rdp->waitlist[0] = NULL; - rdp->waittail[0] = &rdp->waitlist[0]; - } - rdp->waitlistcount = wlc; - rdp->completed = rcu_ctrlblk.completed; - } - - /* - * Check to see if this CPU needs to report that it has seen - * the most recent counter flip, thereby declaring that all - * subsequent rcu_read_lock() invocations will respect this flip. - */ - - cpu = raw_smp_processor_id(); - if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) { - smp_mb(); /* Subsequent counter accesses must see new value */ - per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen; - smp_mb(); /* Subsequent RCU read-side critical sections */ - /* seen -after- acknowledgement. */ - } -} - -/* - * Get here when RCU is idle. Decide whether we need to - * move out of idle state, and return non-zero if so. - * "Straightforward" approach for the moment, might later - * use callback-list lengths, grace-period duration, or - * some such to determine when to exit idle state. - * Might also need a pre-idle test that does not acquire - * the lock, but let's get the simple case working first... - */ - -static int -rcu_try_flip_idle(void) -{ - int cpu; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_i1); - if (!rcu_pending(smp_processor_id())) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1); - return 0; - } - - /* - * Do the flip. - */ - - RCU_TRACE_ME(rcupreempt_trace_try_flip_g1); - rcu_ctrlblk.completed++; /* stands in for rcu_try_flip_g2 */ - - /* - * Need a memory barrier so that other CPUs see the new - * counter value before they see the subsequent change of all - * the rcu_flip_flag instances to rcu_flipped. - */ - - smp_mb(); /* see above block comment. */ - - /* Now ask each CPU for acknowledgement of the flip. */ - - for_each_cpu_mask(cpu, rcu_cpu_online_map) - per_cpu(rcu_flip_flag, cpu) = rcu_flipped; - - return 1; -} - -/* - * Wait for CPUs to acknowledge the flip. - */ - -static int -rcu_try_flip_waitack(void) -{ - int cpu; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_a1); - for_each_cpu_mask(cpu, rcu_cpu_online_map) - if (per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1); - return 0; - } - - /* - * Make sure our checks above don't bleed into subsequent - * waiting for the sum of the counters to reach zero. - */ - - smp_mb(); /* see above block comment. */ - RCU_TRACE_ME(rcupreempt_trace_try_flip_a2); - return 1; -} - -/* - * Wait for collective ``last'' counter to reach zero, - * then tell all CPUs to do an end-of-grace-period memory barrier. - */ - -static int -rcu_try_flip_waitzero(void) -{ - int cpu; - int lastidx = !(rcu_ctrlblk.completed & 0x1); - int sum = 0; - - /* Check to see if the sum of the "last" counters is zero. */ - - RCU_TRACE_ME(rcupreempt_trace_try_flip_z1); - for_each_cpu_mask(cpu, rcu_cpu_online_map) - sum += RCU_DATA_CPU(cpu)->rcu_flipctr[lastidx]; - if (sum != 0) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1); - return 0; - } - - /* - * This ensures that the other CPUs see the call for - * memory barriers -after- the sum to zero has been - * detected here - */ - smp_mb(); /* ^^^^^^^^^^^^ */ - - /* Call for a memory barrier from each CPU. */ - for_each_cpu_mask(cpu, rcu_cpu_online_map) - per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_z2); - return 1; -} - -/* - * Wait for all CPUs to do their end-of-grace-period memory barrier. - * Return 0 once all CPUs have done so. - */ - -static int -rcu_try_flip_waitmb(void) -{ - int cpu; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_m1); - for_each_cpu_mask(cpu, rcu_cpu_online_map) - if (per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_me1); - return 0; - } - - smp_mb(); /* Ensure that the above checks precede any following flip. */ - RCU_TRACE_ME(rcupreempt_trace_try_flip_m2); - return 1; -} - -/* - * Attempt a single flip of the counters. Remember, a single flip does - * -not- constitute a grace period. Instead, the interval between - * at least GP_STAGES consecutive flips is a grace period. - * - * If anyone is nuts enough to run this CONFIG_PREEMPT_RCU implementation - * on a large SMP, they might want to use a hierarchical organization of - * the per-CPU-counter pairs. - */ -static void rcu_try_flip(void) -{ - unsigned long flags; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_1); - if (unlikely(!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, flags))) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_e1); - return; - } - - /* - * Take the next transition(s) through the RCU grace-period - * flip-counter state machine. - */ - - switch (rcu_ctrlblk.rcu_try_flip_state) { - case rcu_try_flip_idle_state: - if (rcu_try_flip_idle()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_waitack_state; - break; - case rcu_try_flip_waitack_state: - if (rcu_try_flip_waitack()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_waitzero_state; - break; - case rcu_try_flip_waitzero_state: - if (rcu_try_flip_waitzero()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_waitmb_state; - break; - case rcu_try_flip_waitmb_state: - if (rcu_try_flip_waitmb()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_idle_state; - } - spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); -} - -/* - * Check to see if this CPU needs to do a memory barrier in order to - * ensure that any prior RCU read-side critical sections have committed - * their counter manipulations and critical-section memory references - * before declaring the grace period to be completed. - */ -static void rcu_check_mb(int cpu) -{ - if (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed) { - smp_mb(); /* Ensure RCU read-side accesses are visible. */ - per_cpu(rcu_mb_flag, cpu) = rcu_mb_done; - } -} - -void rcu_check_callbacks(int cpu, int user) -{ - unsigned long flags; - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - rcu_check_mb(cpu); - if (rcu_ctrlblk.completed == rdp->completed) - rcu_try_flip(); - spin_lock_irqsave(&rdp->lock, flags); - RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); - __rcu_advance_callbacks(rdp); - if (rdp->donelist == NULL) { - spin_unlock_irqrestore(&rdp->lock, flags); - } else { - spin_unlock_irqrestore(&rdp->lock, flags); - raise_softirq(RCU_SOFTIRQ); - } -} - -/* - * Needed by dynticks, to make sure all RCU processing has finished - * when we go idle: - */ -void rcu_advance_callbacks(int cpu, int user) -{ - unsigned long flags; - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - if (rcu_ctrlblk.completed == rdp->completed) { - rcu_try_flip(); - if (rcu_ctrlblk.completed == rdp->completed) - return; - } - spin_lock_irqsave(&rdp->lock, flags); - RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); - __rcu_advance_callbacks(rdp); - spin_unlock_irqrestore(&rdp->lock, flags); -} - -#ifdef CONFIG_HOTPLUG_CPU -#define rcu_offline_cpu_enqueue(srclist, srctail, dstlist, dsttail) do { \ - *dsttail = srclist; \ - if (srclist != NULL) { \ - dsttail = srctail; \ - srclist = NULL; \ - srctail = &srclist;\ - } \ - } while (0) - -void rcu_offline_cpu(int cpu) -{ - int i; - struct rcu_head *list = NULL; - unsigned long flags; - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - struct rcu_head **tail = &list; - - /* - * Remove all callbacks from the newly dead CPU, retaining order. - * Otherwise rcu_barrier() will fail - */ - - spin_lock_irqsave(&rdp->lock, flags); - rcu_offline_cpu_enqueue(rdp->donelist, rdp->donetail, list, tail); - for (i = GP_STAGES - 1; i >= 0; i--) - rcu_offline_cpu_enqueue(rdp->waitlist[i], rdp->waittail[i], - list, tail); - rcu_offline_cpu_enqueue(rdp->nextlist, rdp->nexttail, list, tail); - spin_unlock_irqrestore(&rdp->lock, flags); - rdp->waitlistcount = 0; - - /* Disengage the newly dead CPU from the grace-period computation. */ - - spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags); - rcu_check_mb(cpu); - if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) { - smp_mb(); /* Subsequent counter accesses must see new value */ - per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen; - smp_mb(); /* Subsequent RCU read-side critical sections */ - /* seen -after- acknowledgement. */ - } - - RCU_DATA_ME()->rcu_flipctr[0] += RCU_DATA_CPU(cpu)->rcu_flipctr[0]; - RCU_DATA_ME()->rcu_flipctr[1] += RCU_DATA_CPU(cpu)->rcu_flipctr[1]; - - RCU_DATA_CPU(cpu)->rcu_flipctr[0] = 0; - RCU_DATA_CPU(cpu)->rcu_flipctr[1] = 0; - - cpu_clear(cpu, rcu_cpu_online_map); - - spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); - - /* - * Place the removed callbacks on the current CPU's queue. - * Make them all start a new grace period: simple approach, - * in theory could starve a given set of callbacks, but - * you would need to be doing some serious CPU hotplugging - * to make this happen. If this becomes a problem, adding - * a synchronize_rcu() to the hotplug path would be a simple - * fix. - */ - - rdp = RCU_DATA_ME(); - spin_lock_irqsave(&rdp->lock, flags); - *rdp->nexttail = list; - if (list) - rdp->nexttail = tail; - spin_unlock_irqrestore(&rdp->lock, flags); -} - -void __devinit rcu_online_cpu(int cpu) -{ - unsigned long flags; - - spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags); - cpu_set(cpu, rcu_cpu_online_map); - spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); -} - -#else /* #ifdef CONFIG_HOTPLUG_CPU */ - -void rcu_offline_cpu(int cpu) -{ -} - -void __devinit rcu_online_cpu(int cpu) -{ -} - -#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ - -static void rcu_process_callbacks(struct softirq_action *unused) -{ - unsigned long flags; - struct rcu_head *next, *list; - struct rcu_data *rdp = RCU_DATA_ME(); - - spin_lock_irqsave(&rdp->lock, flags); - list = rdp->donelist; - if (list == NULL) { - spin_unlock_irqrestore(&rdp->lock, flags); - return; - } - rdp->donelist = NULL; - rdp->donetail = &rdp->donelist; - RCU_TRACE_RDP(rcupreempt_trace_done_remove, rdp); - spin_unlock_irqrestore(&rdp->lock, flags); - while (list) { - next = list->next; - list->func(list); - list = next; - RCU_TRACE_ME(rcupreempt_trace_invoke); - } -} - -void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) -{ - unsigned long flags; - struct rcu_data *rdp; - - head->func = func; - head->next = NULL; - local_irq_save(flags); - rdp = RCU_DATA_ME(); - spin_lock(&rdp->lock); - __rcu_advance_callbacks(rdp); - *rdp->nexttail = head; - rdp->nexttail = &head->next; - RCU_TRACE_RDP(rcupreempt_trace_next_add, rdp); - spin_unlock(&rdp->lock); - local_irq_restore(flags); -} -EXPORT_SYMBOL_GPL(call_rcu); - -/* - * Wait until all currently running preempt_disable() code segments - * (including hardware-irq-disable segments) complete. Note that - * in -rt this does -not- necessarily result in all currently executing - * interrupt -handlers- having completed. - */ -void __synchronize_sched(void) -{ - cpumask_t oldmask; - int cpu; - - if (sched_getaffinity(0, &oldmask) < 0) - oldmask = cpu_possible_map; - for_each_online_cpu(cpu) { - sched_setaffinity(0, cpumask_of_cpu(cpu)); - schedule(); - } - sched_setaffinity(0, oldmask); -} -EXPORT_SYMBOL_GPL(__synchronize_sched); - -/* - * Check to see if any future RCU-related work will need to be done - * by the current CPU, even if none need be done immediately, returning - * 1 if so. Assumes that notifiers would take care of handling any - * outstanding requests from the RCU core. - * - * This function is part of the RCU implementation; it is -not- - * an exported member of the RCU API. - */ -int rcu_needs_cpu(int cpu) -{ - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - return (rdp->donelist != NULL || - !!rdp->waitlistcount || - rdp->nextlist != NULL); -} - -int rcu_pending(int cpu) -{ - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - /* The CPU has at least one callback queued somewhere. */ - - if (rdp->donelist != NULL || - !!rdp->waitlistcount || - rdp->nextlist != NULL) - return 1; - - /* The RCU core needs an acknowledgement from this CPU. */ - - if ((per_cpu(rcu_flip_flag, cpu) == rcu_flipped) || - (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed)) - return 1; - - /* This CPU has fallen behind the global grace-period number. */ - - if (rdp->completed != rcu_ctrlblk.completed) - return 1; - - /* Nothing needed from this CPU. */ - - return 0; -} - -static int __cpuinit rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - long cpu = (long)hcpu; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - rcu_online_cpu(cpu); - break; - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - case CPU_DEAD: - case CPU_DEAD_FROZEN: - rcu_offline_cpu(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - -static struct notifier_block __cpuinitdata rcu_nb = { - .notifier_call = rcu_cpu_notify, -}; - -void __init __rcu_init(void) -{ - int cpu; - int i; - struct rcu_data *rdp; - - printk(KERN_NOTICE "Preemptible RCU implementation.\n"); - for_each_possible_cpu(cpu) { - rdp = RCU_DATA_CPU(cpu); - spin_lock_init(&rdp->lock); - rdp->completed = 0; - rdp->waitlistcount = 0; - rdp->nextlist = NULL; - rdp->nexttail = &rdp->nextlist; - for (i = 0; i < GP_STAGES; i++) { - rdp->waitlist[i] = NULL; - rdp->waittail[i] = &rdp->waitlist[i]; - } - rdp->donelist = NULL; - rdp->donetail = &rdp->donelist; - rdp->rcu_flipctr[0] = 0; - rdp->rcu_flipctr[1] = 0; - } - register_cpu_notifier(&rcu_nb); - - /* - * We don't need protection against CPU-Hotplug here - * since - * a) If a CPU comes online while we are iterating over the - * cpu_online_map below, we would only end up making a - * duplicate call to rcu_online_cpu() which sets the corresponding - * CPU's mask in the rcu_cpu_online_map. - * - * b) A CPU cannot go offline at this point in time since the user - * does not have access to the sysfs interface, nor do we - * suspend the system. - */ - for_each_online_cpu(cpu) - rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE, (void *)(long) cpu); - - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks, NULL); -} - -/* - * Deprecated, use synchronize_rcu() or synchronize_sched() instead. - */ -void synchronize_kernel(void) -{ - synchronize_rcu(); -} - -#ifdef CONFIG_RCU_TRACE -long *rcupreempt_flipctr(int cpu) -{ - return &RCU_DATA_CPU(cpu)->rcu_flipctr[0]; -} -EXPORT_SYMBOL_GPL(rcupreempt_flipctr); - -int rcupreempt_flip_flag(int cpu) -{ - return per_cpu(rcu_flip_flag, cpu); -} -EXPORT_SYMBOL_GPL(rcupreempt_flip_flag); - -int rcupreempt_mb_flag(int cpu) -{ - return per_cpu(rcu_mb_flag, cpu); -} -EXPORT_SYMBOL_GPL(rcupreempt_mb_flag); - -char *rcupreempt_try_flip_state_name(void) -{ - return rcu_try_flip_state_names[rcu_ctrlblk.rcu_try_flip_state]; -} -EXPORT_SYMBOL_GPL(rcupreempt_try_flip_state_name); - -struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu) -{ - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - return &rdp->trace; -} -EXPORT_SYMBOL_GPL(rcupreempt_trace_cpu); - -#endif /* #ifdef RCU_TRACE */ diff --git a/trunk/kernel/rcupreempt_trace.c b/trunk/kernel/rcupreempt_trace.c deleted file mode 100644 index 49ac4947af24..000000000000 --- a/trunk/kernel/rcupreempt_trace.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Read-Copy Update tracing for realtime implementation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2006 - * - * Papers: http://www.rdrop.com/users/paulmck/RCU - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct mutex rcupreempt_trace_mutex; -static char *rcupreempt_trace_buf; -#define RCUPREEMPT_TRACE_BUF_SIZE 4096 - -void rcupreempt_trace_move2done(struct rcupreempt_trace *trace) -{ - trace->done_length += trace->wait_length; - trace->done_add += trace->wait_length; - trace->wait_length = 0; -} -void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace) -{ - trace->wait_length += trace->next_length; - trace->wait_add += trace->next_length; - trace->next_length = 0; -} -void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace) -{ - atomic_inc(&trace->rcu_try_flip_1); -} -void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace) -{ - atomic_inc(&trace->rcu_try_flip_e1); -} -void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_i1++; -} -void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_ie1++; -} -void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_g1++; -} -void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_a1++; -} -void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_ae1++; -} -void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_a2++; -} -void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_z1++; -} -void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_ze1++; -} -void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_z2++; -} -void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_m1++; -} -void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_me1++; -} -void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_m2++; -} -void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace) -{ - trace->rcu_check_callbacks++; -} -void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace) -{ - trace->done_remove += trace->done_length; - trace->done_length = 0; -} -void rcupreempt_trace_invoke(struct rcupreempt_trace *trace) -{ - atomic_inc(&trace->done_invoked); -} -void rcupreempt_trace_next_add(struct rcupreempt_trace *trace) -{ - trace->next_add++; - trace->next_length++; -} - -static void rcupreempt_trace_sum(struct rcupreempt_trace *sp) -{ - struct rcupreempt_trace *cp; - int cpu; - - memset(sp, 0, sizeof(*sp)); - for_each_possible_cpu(cpu) { - cp = rcupreempt_trace_cpu(cpu); - sp->next_length += cp->next_length; - sp->next_add += cp->next_add; - sp->wait_length += cp->wait_length; - sp->wait_add += cp->wait_add; - sp->done_length += cp->done_length; - sp->done_add += cp->done_add; - sp->done_remove += cp->done_remove; - atomic_set(&sp->done_invoked, atomic_read(&cp->done_invoked)); - sp->rcu_check_callbacks += cp->rcu_check_callbacks; - atomic_set(&sp->rcu_try_flip_1, - atomic_read(&cp->rcu_try_flip_1)); - atomic_set(&sp->rcu_try_flip_e1, - atomic_read(&cp->rcu_try_flip_e1)); - sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1; - sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1; - sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1; - sp->rcu_try_flip_a1 += cp->rcu_try_flip_a1; - sp->rcu_try_flip_ae1 += cp->rcu_try_flip_ae1; - sp->rcu_try_flip_a2 += cp->rcu_try_flip_a2; - sp->rcu_try_flip_z1 += cp->rcu_try_flip_z1; - sp->rcu_try_flip_ze1 += cp->rcu_try_flip_ze1; - sp->rcu_try_flip_z2 += cp->rcu_try_flip_z2; - sp->rcu_try_flip_m1 += cp->rcu_try_flip_m1; - sp->rcu_try_flip_me1 += cp->rcu_try_flip_me1; - sp->rcu_try_flip_m2 += cp->rcu_try_flip_m2; - } -} - -static ssize_t rcustats_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct rcupreempt_trace trace; - ssize_t bcount; - int cnt = 0; - - rcupreempt_trace_sum(&trace); - mutex_lock(&rcupreempt_trace_mutex); - snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "ggp=%ld rcc=%ld\n", - rcu_batches_completed(), - trace.rcu_check_callbacks); - snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "na=%ld nl=%ld wa=%ld wl=%ld da=%ld dl=%ld dr=%ld di=%d\n" - "1=%d e1=%d i1=%ld ie1=%ld g1=%ld a1=%ld ae1=%ld a2=%ld\n" - "z1=%ld ze1=%ld z2=%ld m1=%ld me1=%ld m2=%ld\n", - - trace.next_add, trace.next_length, - trace.wait_add, trace.wait_length, - trace.done_add, trace.done_length, - trace.done_remove, atomic_read(&trace.done_invoked), - atomic_read(&trace.rcu_try_flip_1), - atomic_read(&trace.rcu_try_flip_e1), - trace.rcu_try_flip_i1, trace.rcu_try_flip_ie1, - trace.rcu_try_flip_g1, - trace.rcu_try_flip_a1, trace.rcu_try_flip_ae1, - trace.rcu_try_flip_a2, - trace.rcu_try_flip_z1, trace.rcu_try_flip_ze1, - trace.rcu_try_flip_z2, - trace.rcu_try_flip_m1, trace.rcu_try_flip_me1, - trace.rcu_try_flip_m2); - bcount = simple_read_from_buffer(buffer, count, ppos, - rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); - mutex_unlock(&rcupreempt_trace_mutex); - return bcount; -} - -static ssize_t rcugp_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - long oldgp = rcu_batches_completed(); - ssize_t bcount; - - mutex_lock(&rcupreempt_trace_mutex); - synchronize_rcu(); - snprintf(rcupreempt_trace_buf, RCUPREEMPT_TRACE_BUF_SIZE, - "oldggp=%ld newggp=%ld\n", oldgp, rcu_batches_completed()); - bcount = simple_read_from_buffer(buffer, count, ppos, - rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); - mutex_unlock(&rcupreempt_trace_mutex); - return bcount; -} - -static ssize_t rcuctrs_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - int cnt = 0; - int cpu; - int f = rcu_batches_completed() & 0x1; - ssize_t bcount; - - mutex_lock(&rcupreempt_trace_mutex); - - cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE, - "CPU last cur F M\n"); - for_each_online_cpu(cpu) { - long *flipctr = rcupreempt_flipctr(cpu); - cnt += snprintf(&rcupreempt_trace_buf[cnt], - RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "%3d %4ld %3ld %d %d\n", - cpu, - flipctr[!f], - flipctr[f], - rcupreempt_flip_flag(cpu), - rcupreempt_mb_flag(cpu)); - } - cnt += snprintf(&rcupreempt_trace_buf[cnt], - RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "ggp = %ld, state = %s\n", - rcu_batches_completed(), - rcupreempt_try_flip_state_name()); - cnt += snprintf(&rcupreempt_trace_buf[cnt], - RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "\n"); - bcount = simple_read_from_buffer(buffer, count, ppos, - rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); - mutex_unlock(&rcupreempt_trace_mutex); - return bcount; -} - -static struct file_operations rcustats_fops = { - .owner = THIS_MODULE, - .read = rcustats_read, -}; - -static struct file_operations rcugp_fops = { - .owner = THIS_MODULE, - .read = rcugp_read, -}; - -static struct file_operations rcuctrs_fops = { - .owner = THIS_MODULE, - .read = rcuctrs_read, -}; - -static struct dentry *rcudir, *statdir, *ctrsdir, *gpdir; -static int rcupreempt_debugfs_init(void) -{ - rcudir = debugfs_create_dir("rcu", NULL); - if (!rcudir) - goto out; - statdir = debugfs_create_file("rcustats", 0444, rcudir, - NULL, &rcustats_fops); - if (!statdir) - goto free_out; - - gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops); - if (!gpdir) - goto free_out; - - ctrsdir = debugfs_create_file("rcuctrs", 0444, rcudir, - NULL, &rcuctrs_fops); - if (!ctrsdir) - goto free_out; - return 0; -free_out: - if (statdir) - debugfs_remove(statdir); - if (gpdir) - debugfs_remove(gpdir); - debugfs_remove(rcudir); -out: - return 1; -} - -static int __init rcupreempt_trace_init(void) -{ - mutex_init(&rcupreempt_trace_mutex); - rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL); - if (!rcupreempt_trace_buf) - return 1; - return rcupreempt_debugfs_init(); -} - -static void __exit rcupreempt_trace_cleanup(void) -{ - debugfs_remove(statdir); - debugfs_remove(gpdir); - debugfs_remove(ctrsdir); - debugfs_remove(rcudir); - kfree(rcupreempt_trace_buf); -} - - -module_init(rcupreempt_trace_init); -module_exit(rcupreempt_trace_cleanup); diff --git a/trunk/kernel/rcutorture.c b/trunk/kernel/rcutorture.c index fd599829e72a..c3e165c2318f 100644 --- a/trunk/kernel/rcutorture.c +++ b/trunk/kernel/rcutorture.c @@ -726,11 +726,11 @@ static void rcu_torture_shuffle_tasks(void) cpumask_t tmp_mask = CPU_MASK_ALL; int i; - get_online_cpus(); + lock_cpu_hotplug(); /* No point in shuffling if there is only one online CPU (ex: UP) */ if (num_online_cpus() == 1) { - put_online_cpus(); + unlock_cpu_hotplug(); return; } @@ -762,7 +762,7 @@ static void rcu_torture_shuffle_tasks(void) else rcu_idle_cpu--; - put_online_cpus(); + unlock_cpu_hotplug(); } /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the diff --git a/trunk/kernel/sched.c b/trunk/kernel/sched.c index 524285e46fa7..e76b11ca6df3 100644 --- a/trunk/kernel/sched.c +++ b/trunk/kernel/sched.c @@ -22,8 +22,6 @@ * by Peter Williams * 2007-05-06 Interactivity improvements to CFS by Mike Galbraith * 2007-07-01 Group scheduling enhancements by Srivatsa Vaddagiri - * 2007-11-29 RT balancing improvements by Steven Rostedt, Gregory Haskins, - * Thomas Gleixner, Mike Kravetz */ #include @@ -65,7 +63,6 @@ #include #include #include -#include #include #include @@ -99,9 +96,10 @@ unsigned long long __attribute__((weak)) sched_clock(void) #define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) /* - * Helpers for converting nanosecond timing to jiffy resolution + * Some helpers for converting nanosecond timing to jiffy resolution */ #define NS_TO_JIFFIES(TIME) ((unsigned long)(TIME) / (NSEC_PER_SEC / HZ)) +#define JIFFIES_TO_NS(TIME) ((TIME) * (NSEC_PER_SEC / HZ)) #define NICE_0_LOAD SCHED_LOAD_SCALE #define NICE_0_SHIFT SCHED_LOAD_SHIFT @@ -161,8 +159,6 @@ struct rt_prio_array { struct cfs_rq; -static LIST_HEAD(task_groups); - /* task group related information */ struct task_group { #ifdef CONFIG_FAIR_CGROUP_SCHED @@ -172,50 +168,10 @@ struct task_group { struct sched_entity **se; /* runqueue "owned" by this group on each cpu */ struct cfs_rq **cfs_rq; - - struct sched_rt_entity **rt_se; - struct rt_rq **rt_rq; - - unsigned int rt_ratio; - - /* - * shares assigned to a task group governs how much of cpu bandwidth - * is allocated to the group. The more shares a group has, the more is - * the cpu bandwidth allocated to it. - * - * For ex, lets say that there are three task groups, A, B and C which - * have been assigned shares 1000, 2000 and 3000 respectively. Then, - * cpu bandwidth allocated by the scheduler to task groups A, B and C - * should be: - * - * Bw(A) = 1000/(1000+2000+3000) * 100 = 16.66% - * Bw(B) = 2000/(1000+2000+3000) * 100 = 33.33% - * Bw(C) = 3000/(1000+2000+3000) * 100 = 50% - * - * The weight assigned to a task group's schedulable entities on every - * cpu (task_group.se[a_cpu]->load.weight) is derived from the task - * group's shares. For ex: lets say that task group A has been - * assigned shares of 1000 and there are two CPUs in a system. Then, - * - * tg_A->se[0]->load.weight = tg_A->se[1]->load.weight = 1000; - * - * Note: It's not necessary that each of a task's group schedulable - * entity have the same weight on all CPUs. If the group - * has 2 of its tasks on CPU0 and 1 task on CPU1, then a - * better distribution of weight could be: - * - * tg_A->se[0]->load.weight = 2/3 * 2000 = 1333 - * tg_A->se[1]->load.weight = 1/2 * 2000 = 667 - * - * rebalance_shares() is responsible for distributing the shares of a - * task groups like this among the group's schedulable entities across - * cpus. - * - */ unsigned long shares; - + /* spinlock to serialize modification to shares */ + spinlock_t lock; struct rcu_head rcu; - struct list_head list; }; /* Default task group's sched entity on each cpu */ @@ -223,51 +179,24 @@ static DEFINE_PER_CPU(struct sched_entity, init_sched_entity); /* Default task group's cfs_rq on each cpu */ static DEFINE_PER_CPU(struct cfs_rq, init_cfs_rq) ____cacheline_aligned_in_smp; -static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity); -static DEFINE_PER_CPU(struct rt_rq, init_rt_rq) ____cacheline_aligned_in_smp; - static struct sched_entity *init_sched_entity_p[NR_CPUS]; static struct cfs_rq *init_cfs_rq_p[NR_CPUS]; -static struct sched_rt_entity *init_sched_rt_entity_p[NR_CPUS]; -static struct rt_rq *init_rt_rq_p[NR_CPUS]; - -/* task_group_mutex serializes add/remove of task groups and also changes to - * a task group's cpu shares. - */ -static DEFINE_MUTEX(task_group_mutex); - -/* doms_cur_mutex serializes access to doms_cur[] array */ -static DEFINE_MUTEX(doms_cur_mutex); - -#ifdef CONFIG_SMP -/* kernel thread that runs rebalance_shares() periodically */ -static struct task_struct *lb_monitor_task; -static int load_balance_monitor(void *unused); -#endif - -static void set_se_shares(struct sched_entity *se, unsigned long shares); - /* Default task group. * Every task in system belong to this group at bootup. */ struct task_group init_task_group = { - .se = init_sched_entity_p, + .se = init_sched_entity_p, .cfs_rq = init_cfs_rq_p, - - .rt_se = init_sched_rt_entity_p, - .rt_rq = init_rt_rq_p, }; #ifdef CONFIG_FAIR_USER_SCHED -# define INIT_TASK_GROUP_LOAD (2*NICE_0_LOAD) +# define INIT_TASK_GRP_LOAD 2*NICE_0_LOAD #else -# define INIT_TASK_GROUP_LOAD NICE_0_LOAD +# define INIT_TASK_GRP_LOAD NICE_0_LOAD #endif -#define MIN_GROUP_SHARES 2 - -static int init_task_group_load = INIT_TASK_GROUP_LOAD; +static int init_task_group_load = INIT_TASK_GRP_LOAD; /* return group to which a task belongs */ static inline struct task_group *task_group(struct task_struct *p) @@ -286,42 +215,15 @@ static inline struct task_group *task_group(struct task_struct *p) } /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ -static inline void set_task_rq(struct task_struct *p, unsigned int cpu) +static inline void set_task_cfs_rq(struct task_struct *p, unsigned int cpu) { p->se.cfs_rq = task_group(p)->cfs_rq[cpu]; p->se.parent = task_group(p)->se[cpu]; - - p->rt.rt_rq = task_group(p)->rt_rq[cpu]; - p->rt.parent = task_group(p)->rt_se[cpu]; -} - -static inline void lock_task_group_list(void) -{ - mutex_lock(&task_group_mutex); -} - -static inline void unlock_task_group_list(void) -{ - mutex_unlock(&task_group_mutex); -} - -static inline void lock_doms_cur(void) -{ - mutex_lock(&doms_cur_mutex); -} - -static inline void unlock_doms_cur(void) -{ - mutex_unlock(&doms_cur_mutex); } #else -static inline void set_task_rq(struct task_struct *p, unsigned int cpu) { } -static inline void lock_task_group_list(void) { } -static inline void unlock_task_group_list(void) { } -static inline void lock_doms_cur(void) { } -static inline void unlock_doms_cur(void) { } +static inline void set_task_cfs_rq(struct task_struct *p, unsigned int cpu) { } #endif /* CONFIG_FAIR_GROUP_SCHED */ @@ -362,56 +264,10 @@ struct cfs_rq { /* Real-Time classes' related field in a runqueue: */ struct rt_rq { struct rt_prio_array active; - unsigned long rt_nr_running; -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED - int highest_prio; /* highest queued rt task prio */ -#endif -#ifdef CONFIG_SMP - unsigned long rt_nr_migratory; - int overloaded; -#endif - int rt_throttled; - u64 rt_time; - -#ifdef CONFIG_FAIR_GROUP_SCHED - struct rq *rq; - struct list_head leaf_rt_rq_list; - struct task_group *tg; - struct sched_rt_entity *rt_se; -#endif + int rt_load_balance_idx; + struct list_head *rt_load_balance_head, *rt_load_balance_curr; }; -#ifdef CONFIG_SMP - -/* - * We add the notion of a root-domain which will be used to define per-domain - * variables. Each exclusive cpuset essentially defines an island domain by - * fully partitioning the member cpus from any other cpuset. Whenever a new - * exclusive cpuset is created, we also create and attach a new root-domain - * object. - * - */ -struct root_domain { - atomic_t refcount; - cpumask_t span; - cpumask_t online; - - /* - * The "RT overload" flag: it gets set if a CPU has more than - * one runnable RT task. - */ - cpumask_t rto_mask; - atomic_t rto_count; -}; - -/* - * By default the system creates a single root-domain with all cpus as - * members (mimicking the global state we have today). - */ -static struct root_domain def_root_domain; - -#endif - /* * This is the main, per-CPU runqueue data structure. * @@ -440,15 +296,11 @@ struct rq { u64 nr_switches; struct cfs_rq cfs; - struct rt_rq rt; - u64 rt_period_expire; - int rt_throttled; - #ifdef CONFIG_FAIR_GROUP_SCHED /* list of leaf cfs_rq on this cpu: */ struct list_head leaf_cfs_rq_list; - struct list_head leaf_rt_rq_list; #endif + struct rt_rq rt; /* * This is part of a global counter where only the total sum @@ -465,7 +317,7 @@ struct rq { u64 clock, prev_clock_raw; s64 clock_max_delta; - unsigned int clock_warps, clock_overflows, clock_underflows; + unsigned int clock_warps, clock_overflows; u64 idle_clock; unsigned int clock_deep_idle_events; u64 tick_timestamp; @@ -473,7 +325,6 @@ struct rq { atomic_t nr_iowait; #ifdef CONFIG_SMP - struct root_domain *rd; struct sched_domain *sd; /* For active balancing */ @@ -486,12 +337,6 @@ struct rq { struct list_head migration_queue; #endif -#ifdef CONFIG_SCHED_HRTICK - unsigned long hrtick_flags; - ktime_t hrtick_expire; - struct hrtimer hrtick_timer; -#endif - #ifdef CONFIG_SCHEDSTATS /* latency stats */ struct sched_info rq_sched_info; @@ -518,6 +363,7 @@ struct rq { }; static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); +static DEFINE_MUTEX(sched_hotcpu_mutex); static inline void check_preempt_curr(struct rq *rq, struct task_struct *p) { @@ -595,23 +441,6 @@ static void update_rq_clock(struct rq *rq) #define task_rq(p) cpu_rq(task_cpu(p)) #define cpu_curr(cpu) (cpu_rq(cpu)->curr) -unsigned long rt_needs_cpu(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - u64 delta; - - if (!rq->rt_throttled) - return 0; - - if (rq->clock > rq->rt_period_expire) - return 1; - - delta = rq->rt_period_expire - rq->clock; - do_div(delta, NSEC_PER_SEC / HZ); - - return (unsigned long)delta; -} - /* * Tunables that become constants when CONFIG_SCHED_DEBUG is off: */ @@ -630,8 +459,6 @@ enum { SCHED_FEAT_START_DEBIT = 4, SCHED_FEAT_TREE_AVG = 8, SCHED_FEAT_APPROX_AVG = 16, - SCHED_FEAT_HRTICK = 32, - SCHED_FEAT_DOUBLE_TICK = 64, }; const_debug unsigned int sysctl_sched_features = @@ -639,9 +466,7 @@ const_debug unsigned int sysctl_sched_features = SCHED_FEAT_WAKEUP_PREEMPT * 1 | SCHED_FEAT_START_DEBIT * 1 | SCHED_FEAT_TREE_AVG * 0 | - SCHED_FEAT_APPROX_AVG * 0 | - SCHED_FEAT_HRTICK * 1 | - SCHED_FEAT_DOUBLE_TICK * 0; + SCHED_FEAT_APPROX_AVG * 0; #define sched_feat(x) (sysctl_sched_features & SCHED_FEAT_##x) @@ -651,21 +476,6 @@ const_debug unsigned int sysctl_sched_features = */ const_debug unsigned int sysctl_sched_nr_migrate = 32; -/* - * period over which we measure -rt task cpu usage in ms. - * default: 1s - */ -const_debug unsigned int sysctl_sched_rt_period = 1000; - -#define SCHED_RT_FRAC_SHIFT 16 -#define SCHED_RT_FRAC (1UL << SCHED_RT_FRAC_SHIFT) - -/* - * ratio of time -rt tasks may consume. - * default: 95% - */ -const_debug unsigned int sysctl_sched_rt_ratio = 62259; - /* * For kernel-internal use: high-speed (but slightly incorrect) per-cpu * clock constructed from sched_clock(): @@ -858,6 +668,7 @@ void sched_clock_idle_wakeup_event(u64 delta_ns) struct rq *rq = cpu_rq(smp_processor_id()); u64 now = sched_clock(); + touch_softlockup_watchdog(); rq->idle_clock += delta_ns; /* * Override the previous timestamp and ignore all @@ -869,177 +680,9 @@ void sched_clock_idle_wakeup_event(u64 delta_ns) rq->prev_clock_raw = now; rq->clock += delta_ns; spin_unlock(&rq->lock); - touch_softlockup_watchdog(); } EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event); -static void __resched_task(struct task_struct *p, int tif_bit); - -static inline void resched_task(struct task_struct *p) -{ - __resched_task(p, TIF_NEED_RESCHED); -} - -#ifdef CONFIG_SCHED_HRTICK -/* - * Use HR-timers to deliver accurate preemption points. - * - * Its all a bit involved since we cannot program an hrt while holding the - * rq->lock. So what we do is store a state in in rq->hrtick_* and ask for a - * reschedule event. - * - * When we get rescheduled we reprogram the hrtick_timer outside of the - * rq->lock. - */ -static inline void resched_hrt(struct task_struct *p) -{ - __resched_task(p, TIF_HRTICK_RESCHED); -} - -static inline void resched_rq(struct rq *rq) -{ - unsigned long flags; - - spin_lock_irqsave(&rq->lock, flags); - resched_task(rq->curr); - spin_unlock_irqrestore(&rq->lock, flags); -} - -enum { - HRTICK_SET, /* re-programm hrtick_timer */ - HRTICK_RESET, /* not a new slice */ -}; - -/* - * Use hrtick when: - * - enabled by features - * - hrtimer is actually high res - */ -static inline int hrtick_enabled(struct rq *rq) -{ - if (!sched_feat(HRTICK)) - return 0; - return hrtimer_is_hres_active(&rq->hrtick_timer); -} - -/* - * Called to set the hrtick timer state. - * - * called with rq->lock held and irqs disabled - */ -static void hrtick_start(struct rq *rq, u64 delay, int reset) -{ - assert_spin_locked(&rq->lock); - - /* - * preempt at: now + delay - */ - rq->hrtick_expire = - ktime_add_ns(rq->hrtick_timer.base->get_time(), delay); - /* - * indicate we need to program the timer - */ - __set_bit(HRTICK_SET, &rq->hrtick_flags); - if (reset) - __set_bit(HRTICK_RESET, &rq->hrtick_flags); - - /* - * New slices are called from the schedule path and don't need a - * forced reschedule. - */ - if (reset) - resched_hrt(rq->curr); -} - -static void hrtick_clear(struct rq *rq) -{ - if (hrtimer_active(&rq->hrtick_timer)) - hrtimer_cancel(&rq->hrtick_timer); -} - -/* - * Update the timer from the possible pending state. - */ -static void hrtick_set(struct rq *rq) -{ - ktime_t time; - int set, reset; - unsigned long flags; - - WARN_ON_ONCE(cpu_of(rq) != smp_processor_id()); - - spin_lock_irqsave(&rq->lock, flags); - set = __test_and_clear_bit(HRTICK_SET, &rq->hrtick_flags); - reset = __test_and_clear_bit(HRTICK_RESET, &rq->hrtick_flags); - time = rq->hrtick_expire; - clear_thread_flag(TIF_HRTICK_RESCHED); - spin_unlock_irqrestore(&rq->lock, flags); - - if (set) { - hrtimer_start(&rq->hrtick_timer, time, HRTIMER_MODE_ABS); - if (reset && !hrtimer_active(&rq->hrtick_timer)) - resched_rq(rq); - } else - hrtick_clear(rq); -} - -/* - * High-resolution timer tick. - * Runs from hardirq context with interrupts disabled. - */ -static enum hrtimer_restart hrtick(struct hrtimer *timer) -{ - struct rq *rq = container_of(timer, struct rq, hrtick_timer); - - WARN_ON_ONCE(cpu_of(rq) != smp_processor_id()); - - spin_lock(&rq->lock); - __update_rq_clock(rq); - rq->curr->sched_class->task_tick(rq, rq->curr, 1); - spin_unlock(&rq->lock); - - return HRTIMER_NORESTART; -} - -static inline void init_rq_hrtick(struct rq *rq) -{ - rq->hrtick_flags = 0; - hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - rq->hrtick_timer.function = hrtick; - rq->hrtick_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ; -} - -void hrtick_resched(void) -{ - struct rq *rq; - unsigned long flags; - - if (!test_thread_flag(TIF_HRTICK_RESCHED)) - return; - - local_irq_save(flags); - rq = cpu_rq(smp_processor_id()); - hrtick_set(rq); - local_irq_restore(flags); -} -#else -static inline void hrtick_clear(struct rq *rq) -{ -} - -static inline void hrtick_set(struct rq *rq) -{ -} - -static inline void init_rq_hrtick(struct rq *rq) -{ -} - -void hrtick_resched(void) -{ -} -#endif - /* * resched_task - mark a task 'to be rescheduled now'. * @@ -1053,16 +696,16 @@ void hrtick_resched(void) #define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) #endif -static void __resched_task(struct task_struct *p, int tif_bit) +static void resched_task(struct task_struct *p) { int cpu; assert_spin_locked(&task_rq(p)->lock); - if (unlikely(test_tsk_thread_flag(p, tif_bit))) + if (unlikely(test_tsk_thread_flag(p, TIF_NEED_RESCHED))) return; - set_tsk_thread_flag(p, tif_bit); + set_tsk_thread_flag(p, TIF_NEED_RESCHED); cpu = task_cpu(p); if (cpu == smp_processor_id()) @@ -1085,10 +728,10 @@ static void resched_cpu(int cpu) spin_unlock_irqrestore(&rq->lock, flags); } #else -static void __resched_task(struct task_struct *p, int tif_bit) +static inline void resched_task(struct task_struct *p) { assert_spin_locked(&task_rq(p)->lock); - set_tsk_thread_flag(p, tif_bit); + set_tsk_need_resched(p); } #endif @@ -1228,23 +871,6 @@ static void cpuacct_charge(struct task_struct *tsk, u64 cputime); static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) {} #endif -static inline void inc_cpu_load(struct rq *rq, unsigned long load) -{ - update_load_add(&rq->load, load); -} - -static inline void dec_cpu_load(struct rq *rq, unsigned long load) -{ - update_load_sub(&rq->load, load); -} - -#ifdef CONFIG_SMP -static unsigned long source_load(int cpu, int type); -static unsigned long target_load(int cpu, int type); -static unsigned long cpu_avg_load_per_task(int cpu); -static int task_hot(struct task_struct *p, u64 now, struct sched_domain *sd); -#endif /* CONFIG_SMP */ - #include "sched_stats.h" #include "sched_idletask.c" #include "sched_fair.c" @@ -1255,14 +881,41 @@ static int task_hot(struct task_struct *p, u64 now, struct sched_domain *sd); #define sched_class_highest (&rt_sched_class) +/* + * Update delta_exec, delta_fair fields for rq. + * + * delta_fair clock advances at a rate inversely proportional to + * total load (rq->load.weight) on the runqueue, while + * delta_exec advances at the same rate as wall-clock (provided + * cpu is not idle). + * + * delta_exec / delta_fair is a measure of the (smoothened) load on this + * runqueue over any given interval. This (smoothened) load is used + * during load balance. + * + * This function is called /before/ updating rq->load + * and when switching tasks. + */ +static inline void inc_load(struct rq *rq, const struct task_struct *p) +{ + update_load_add(&rq->load, p->se.load.weight); +} + +static inline void dec_load(struct rq *rq, const struct task_struct *p) +{ + update_load_sub(&rq->load, p->se.load.weight); +} + static void inc_nr_running(struct task_struct *p, struct rq *rq) { rq->nr_running++; + inc_load(rq, p); } static void dec_nr_running(struct task_struct *p, struct rq *rq) { rq->nr_running--; + dec_load(rq, p); } static void set_load_weight(struct task_struct *p) @@ -1386,7 +1039,7 @@ unsigned long weighted_cpuload(const int cpu) static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) { - set_task_rq(p, cpu); + set_task_cfs_rq(p, cpu); #ifdef CONFIG_SMP /* * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be @@ -1398,24 +1051,12 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) #endif } -static inline void check_class_changed(struct rq *rq, struct task_struct *p, - const struct sched_class *prev_class, - int oldprio, int running) -{ - if (prev_class != p->sched_class) { - if (prev_class->switched_from) - prev_class->switched_from(rq, p, running); - p->sched_class->switched_to(rq, p, running); - } else - p->sched_class->prio_changed(rq, p, oldprio, running); -} - #ifdef CONFIG_SMP /* * Is this task likely cache-hot: */ -static int +static inline int task_hot(struct task_struct *p, u64 now, struct sched_domain *sd) { s64 delta; @@ -1640,7 +1281,7 @@ static unsigned long target_load(int cpu, int type) /* * Return the average load per task on the cpu's run queue */ -static unsigned long cpu_avg_load_per_task(int cpu) +static inline unsigned long cpu_avg_load_per_task(int cpu) { struct rq *rq = cpu_rq(cpu); unsigned long total = weighted_cpuload(cpu); @@ -1797,6 +1438,58 @@ static int sched_balance_self(int cpu, int flag) #endif /* CONFIG_SMP */ +/* + * wake_idle() will wake a task on an idle cpu if task->cpu is + * not idle and an idle cpu is available. The span of cpus to + * search starts with cpus closest then further out as needed, + * so we always favor a closer, idle cpu. + * + * Returns the CPU we should wake onto. + */ +#if defined(ARCH_HAS_SCHED_WAKE_IDLE) +static int wake_idle(int cpu, struct task_struct *p) +{ + cpumask_t tmp; + struct sched_domain *sd; + int i; + + /* + * If it is idle, then it is the best cpu to run this task. + * + * This cpu is also the best, if it has more than one task already. + * Siblings must be also busy(in most cases) as they didn't already + * pickup the extra load from this cpu and hence we need not check + * sibling runqueue info. This will avoid the checks and cache miss + * penalities associated with that. + */ + if (idle_cpu(cpu) || cpu_rq(cpu)->nr_running > 1) + return cpu; + + for_each_domain(cpu, sd) { + if (sd->flags & SD_WAKE_IDLE) { + cpus_and(tmp, sd->span, p->cpus_allowed); + for_each_cpu_mask(i, tmp) { + if (idle_cpu(i)) { + if (i != task_cpu(p)) { + schedstat_inc(p, + se.nr_wakeups_idle); + } + return i; + } + } + } else { + break; + } + } + return cpu; +} +#else +static inline int wake_idle(int cpu, struct task_struct *p) +{ + return cpu; +} +#endif + /*** * try_to_wake_up - wake up a thread * @p: the to-be-woken-up thread @@ -1817,6 +1510,11 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync) unsigned long flags; long old_state; struct rq *rq; +#ifdef CONFIG_SMP + struct sched_domain *sd, *this_sd = NULL; + unsigned long load, this_load; + int new_cpu; +#endif rq = task_rq_lock(p, &flags); old_state = p->state; @@ -1834,9 +1532,92 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync) if (unlikely(task_running(rq, p))) goto out_activate; - cpu = p->sched_class->select_task_rq(p, sync); - if (cpu != orig_cpu) { - set_task_cpu(p, cpu); + new_cpu = cpu; + + schedstat_inc(rq, ttwu_count); + if (cpu == this_cpu) { + schedstat_inc(rq, ttwu_local); + goto out_set_cpu; + } + + for_each_domain(this_cpu, sd) { + if (cpu_isset(cpu, sd->span)) { + schedstat_inc(sd, ttwu_wake_remote); + this_sd = sd; + break; + } + } + + if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed))) + goto out_set_cpu; + + /* + * Check for affine wakeup and passive balancing possibilities. + */ + if (this_sd) { + int idx = this_sd->wake_idx; + unsigned int imbalance; + + imbalance = 100 + (this_sd->imbalance_pct - 100) / 2; + + load = source_load(cpu, idx); + this_load = target_load(this_cpu, idx); + + new_cpu = this_cpu; /* Wake to this CPU if we can */ + + if (this_sd->flags & SD_WAKE_AFFINE) { + unsigned long tl = this_load; + unsigned long tl_per_task; + + /* + * Attract cache-cold tasks on sync wakeups: + */ + if (sync && !task_hot(p, rq->clock, this_sd)) + goto out_set_cpu; + + schedstat_inc(p, se.nr_wakeups_affine_attempts); + tl_per_task = cpu_avg_load_per_task(this_cpu); + + /* + * If sync wakeup then subtract the (maximum possible) + * effect of the currently running task from the load + * of the current CPU: + */ + if (sync) + tl -= current->se.load.weight; + + if ((tl <= load && + tl + target_load(cpu, idx) <= tl_per_task) || + 100*(tl + p->se.load.weight) <= imbalance*load) { + /* + * This domain has SD_WAKE_AFFINE and + * p is cache cold in this domain, and + * there is no bad imbalance. + */ + schedstat_inc(this_sd, ttwu_move_affine); + schedstat_inc(p, se.nr_wakeups_affine); + goto out_set_cpu; + } + } + + /* + * Start passive balancing when half the imbalance_pct + * limit is reached. + */ + if (this_sd->flags & SD_WAKE_BALANCE) { + if (imbalance*this_load <= 100*load) { + schedstat_inc(this_sd, ttwu_move_balance); + schedstat_inc(p, se.nr_wakeups_passive); + goto out_set_cpu; + } + } + } + + new_cpu = cpu; /* Could not wake to this_cpu. Wake to cpu instead */ +out_set_cpu: + new_cpu = wake_idle(new_cpu, p); + if (new_cpu != cpu) { + set_task_cpu(p, new_cpu); task_rq_unlock(rq, &flags); /* might preempt at this point */ rq = task_rq_lock(p, &flags); @@ -1850,21 +1631,6 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync) cpu = task_cpu(p); } -#ifdef CONFIG_SCHEDSTATS - schedstat_inc(rq, ttwu_count); - if (cpu == this_cpu) - schedstat_inc(rq, ttwu_local); - else { - struct sched_domain *sd; - for_each_domain(this_cpu, sd) { - if (cpu_isset(cpu, sd->span)) { - schedstat_inc(sd, ttwu_wake_remote); - break; - } - } - } -#endif - out_activate: #endif /* CONFIG_SMP */ schedstat_inc(p, se.nr_wakeups); @@ -1883,10 +1649,6 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state, int sync) out_running: p->state = TASK_RUNNING; -#ifdef CONFIG_SMP - if (p->sched_class->task_wake_up) - p->sched_class->task_wake_up(rq, p); -#endif out: task_rq_unlock(rq, &flags); @@ -1929,7 +1691,7 @@ static void __sched_fork(struct task_struct *p) p->se.wait_max = 0; #endif - INIT_LIST_HEAD(&p->rt.run_list); + INIT_LIST_HEAD(&p->run_list); p->se.on_rq = 0; #ifdef CONFIG_PREEMPT_NOTIFIERS @@ -2009,10 +1771,6 @@ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags) inc_nr_running(p, rq); } check_preempt_curr(rq, p); -#ifdef CONFIG_SMP - if (p->sched_class->task_wake_up) - p->sched_class->task_wake_up(rq, p); -#endif task_rq_unlock(rq, &flags); } @@ -2133,11 +1891,6 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) prev_state = prev->state; finish_arch_switch(prev); finish_lock_switch(rq, prev); -#ifdef CONFIG_SMP - if (current->sched_class->post_schedule) - current->sched_class->post_schedule(rq); -#endif - fire_sched_in_preempt_notifiers(current); if (mm) mmdrop(mm); @@ -2371,13 +2124,11 @@ static void double_rq_unlock(struct rq *rq1, struct rq *rq2) /* * double_lock_balance - lock the busiest runqueue, this_rq is locked already. */ -static int double_lock_balance(struct rq *this_rq, struct rq *busiest) +static void double_lock_balance(struct rq *this_rq, struct rq *busiest) __releases(this_rq->lock) __acquires(busiest->lock) __acquires(this_rq->lock) { - int ret = 0; - if (unlikely(!irqs_disabled())) { /* printk() doesn't work good under rq->lock */ spin_unlock(&this_rq->lock); @@ -2388,11 +2139,9 @@ static int double_lock_balance(struct rq *this_rq, struct rq *busiest) spin_unlock(&this_rq->lock); spin_lock(&busiest->lock); spin_lock(&this_rq->lock); - ret = 1; } else spin_lock(&busiest->lock); } - return ret; } /* @@ -3736,14 +3485,12 @@ void scheduler_tick(void) /* * Let rq->clock advance by at least TICK_NSEC: */ - if (unlikely(rq->clock < next_tick)) { + if (unlikely(rq->clock < next_tick)) rq->clock = next_tick; - rq->clock_underflows++; - } rq->tick_timestamp = rq->clock; update_cpu_load(rq); - curr->sched_class->task_tick(rq, curr, 0); - update_sched_rt_period(rq); + if (curr != rq->idle) /* FIXME: needed? */ + curr->sched_class->task_tick(rq, curr); spin_unlock(&rq->lock); #ifdef CONFIG_SMP @@ -3889,8 +3636,6 @@ asmlinkage void __sched schedule(void) schedule_debug(prev); - hrtick_clear(rq); - /* * Do the rq-clock update outside the rq lock: */ @@ -3909,11 +3654,6 @@ asmlinkage void __sched schedule(void) switch_count = &prev->nvcsw; } -#ifdef CONFIG_SMP - if (prev->sched_class->pre_schedule) - prev->sched_class->pre_schedule(rq, prev); -#endif - if (unlikely(!rq->nr_running)) idle_balance(cpu, rq); @@ -3928,20 +3668,14 @@ asmlinkage void __sched schedule(void) ++*switch_count; context_switch(rq, prev, next); /* unlocks the rq */ - /* - * the context switch might have flipped the stack from under - * us, hence refresh the local variables. - */ - cpu = smp_processor_id(); - rq = cpu_rq(cpu); } else spin_unlock_irq(&rq->lock); - hrtick_set(rq); - - if (unlikely(reacquire_kernel_lock(current) < 0)) + if (unlikely(reacquire_kernel_lock(current) < 0)) { + cpu = smp_processor_id(); + rq = cpu_rq(cpu); goto need_resched_nonpreemptible; - + } preempt_enable_no_resched(); if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) goto need_resched; @@ -3957,9 +3691,10 @@ EXPORT_SYMBOL(schedule); asmlinkage void __sched preempt_schedule(void) { struct thread_info *ti = current_thread_info(); +#ifdef CONFIG_PREEMPT_BKL struct task_struct *task = current; int saved_lock_depth; - +#endif /* * If there is a non-zero preempt_count or interrupts are disabled, * we do not want to preempt the current task. Just return.. @@ -3975,10 +3710,14 @@ asmlinkage void __sched preempt_schedule(void) * clear ->lock_depth so that schedule() doesnt * auto-release the semaphore: */ +#ifdef CONFIG_PREEMPT_BKL saved_lock_depth = task->lock_depth; task->lock_depth = -1; +#endif schedule(); +#ifdef CONFIG_PREEMPT_BKL task->lock_depth = saved_lock_depth; +#endif sub_preempt_count(PREEMPT_ACTIVE); /* @@ -3999,9 +3738,10 @@ EXPORT_SYMBOL(preempt_schedule); asmlinkage void __sched preempt_schedule_irq(void) { struct thread_info *ti = current_thread_info(); +#ifdef CONFIG_PREEMPT_BKL struct task_struct *task = current; int saved_lock_depth; - +#endif /* Catch callers which need to be fixed */ BUG_ON(ti->preempt_count || !irqs_disabled()); @@ -4013,12 +3753,16 @@ asmlinkage void __sched preempt_schedule_irq(void) * clear ->lock_depth so that schedule() doesnt * auto-release the semaphore: */ +#ifdef CONFIG_PREEMPT_BKL saved_lock_depth = task->lock_depth; task->lock_depth = -1; +#endif local_irq_enable(); schedule(); local_irq_disable(); +#ifdef CONFIG_PREEMPT_BKL task->lock_depth = saved_lock_depth; +#endif sub_preempt_count(PREEMPT_ACTIVE); /* @@ -4275,7 +4019,6 @@ void rt_mutex_setprio(struct task_struct *p, int prio) unsigned long flags; int oldprio, on_rq, running; struct rq *rq; - const struct sched_class *prev_class = p->sched_class; BUG_ON(prio < 0 || prio > MAX_PRIO); @@ -4301,10 +4044,18 @@ void rt_mutex_setprio(struct task_struct *p, int prio) if (on_rq) { if (running) p->sched_class->set_curr_task(rq); - enqueue_task(rq, p, 0); - - check_class_changed(rq, p, prev_class, oldprio, running); + /* + * Reschedule if we are currently running on this runqueue and + * our priority decreased, or if we are not currently running on + * this runqueue and our priority is higher than the current's + */ + if (running) { + if (p->prio > oldprio) + resched_task(rq->curr); + } else { + check_preempt_curr(rq, p); + } } task_rq_unlock(rq, &flags); } @@ -4336,8 +4087,10 @@ void set_user_nice(struct task_struct *p, long nice) goto out_unlock; } on_rq = p->se.on_rq; - if (on_rq) + if (on_rq) { dequeue_task(rq, p, 0); + dec_load(rq, p); + } p->static_prio = NICE_TO_PRIO(nice); set_load_weight(p); @@ -4347,6 +4100,7 @@ void set_user_nice(struct task_struct *p, long nice) if (on_rq) { enqueue_task(rq, p, 0); + inc_load(rq, p); /* * If the task increased its priority or is running and * lowered its priority, then reschedule its CPU: @@ -4504,7 +4258,6 @@ int sched_setscheduler(struct task_struct *p, int policy, { int retval, oldprio, oldpolicy = -1, on_rq, running; unsigned long flags; - const struct sched_class *prev_class = p->sched_class; struct rq *rq; /* may grab non-irq protected spin_locks */ @@ -4598,10 +4351,18 @@ int sched_setscheduler(struct task_struct *p, int policy, if (on_rq) { if (running) p->sched_class->set_curr_task(rq); - activate_task(rq, p, 0); - - check_class_changed(rq, p, prev_class, oldprio, running); + /* + * Reschedule if we are currently running on this runqueue and + * our priority decreased, or if we are not currently running on + * this runqueue and our priority is higher than the current's + */ + if (running) { + if (p->prio > oldprio) + resched_task(rq->curr); + } else { + check_preempt_curr(rq, p); + } } __task_rq_unlock(rq); spin_unlock_irqrestore(&p->pi_lock, flags); @@ -4729,13 +4490,13 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask) struct task_struct *p; int retval; - get_online_cpus(); + mutex_lock(&sched_hotcpu_mutex); read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (!p) { read_unlock(&tasklist_lock); - put_online_cpus(); + mutex_unlock(&sched_hotcpu_mutex); return -ESRCH; } @@ -4775,7 +4536,7 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask) } out_unlock: put_task_struct(p); - put_online_cpus(); + mutex_unlock(&sched_hotcpu_mutex); return retval; } @@ -4832,7 +4593,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask) struct task_struct *p; int retval; - get_online_cpus(); + mutex_lock(&sched_hotcpu_mutex); read_lock(&tasklist_lock); retval = -ESRCH; @@ -4848,7 +4609,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask) out_unlock: read_unlock(&tasklist_lock); - put_online_cpus(); + mutex_unlock(&sched_hotcpu_mutex); return retval; } @@ -4922,8 +4683,7 @@ static void __cond_resched(void) } while (need_resched()); } -#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_VOLUNTARY) -int __sched _cond_resched(void) +int __sched cond_resched(void) { if (need_resched() && !(preempt_count() & PREEMPT_ACTIVE) && system_state == SYSTEM_RUNNING) { @@ -4932,8 +4692,7 @@ int __sched _cond_resched(void) } return 0; } -EXPORT_SYMBOL(_cond_resched); -#endif +EXPORT_SYMBOL(cond_resched); /* * cond_resched_lock() - if a reschedule is pending, drop the given lock, @@ -5131,7 +4890,7 @@ long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval) static const char stat_nam[] = "RSDTtZX"; -void sched_show_task(struct task_struct *p) +static void show_task(struct task_struct *p) { unsigned long free = 0; unsigned state; @@ -5161,7 +4920,8 @@ void sched_show_task(struct task_struct *p) printk(KERN_CONT "%5lu %5d %6d\n", free, task_pid_nr(p), task_pid_nr(p->real_parent)); - show_stack(p, NULL); + if (state != TASK_RUNNING) + show_stack(p, NULL); } void show_state_filter(unsigned long state_filter) @@ -5183,7 +4943,7 @@ void show_state_filter(unsigned long state_filter) */ touch_nmi_watchdog(); if (!state_filter || (p->state & state_filter)) - sched_show_task(p); + show_task(p); } while_each_thread(g, p); touch_all_softlockup_watchdogs(); @@ -5232,8 +4992,11 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) spin_unlock_irqrestore(&rq->lock, flags); /* Set the preempt count _outside_ the spinlocks! */ +#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL) + task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0); +#else task_thread_info(idle)->preempt_count = 0; - +#endif /* * The idle tasks have their own, simple scheduling class: */ @@ -5314,13 +5077,7 @@ int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask) goto out; } - if (p->sched_class->set_cpus_allowed) - p->sched_class->set_cpus_allowed(p, &new_mask); - else { - p->cpus_allowed = new_mask; - p->rt.nr_cpus_allowed = cpus_weight(new_mask); - } - + p->cpus_allowed = new_mask; /* Can the task run on the task's current CPU? If so, we're done */ if (cpu_isset(task_cpu(p), new_mask)) goto out; @@ -5812,6 +5569,9 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) struct rq *rq; switch (action) { + case CPU_LOCK_ACQUIRE: + mutex_lock(&sched_hotcpu_mutex); + break; case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: @@ -5830,15 +5590,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) case CPU_ONLINE_FROZEN: /* Strictly unnecessary, as first user will wake it. */ wake_up_process(cpu_rq(cpu)->migration_thread); - - /* Update our root-domain */ - rq = cpu_rq(cpu); - spin_lock_irqsave(&rq->lock, flags); - if (rq->rd) { - BUG_ON(!cpu_isset(cpu, rq->rd->span)); - cpu_set(cpu, rq->rd->online); - } - spin_unlock_irqrestore(&rq->lock, flags); break; #ifdef CONFIG_HOTPLUG_CPU @@ -5889,18 +5640,10 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu) } spin_unlock_irq(&rq->lock); break; - - case CPU_DOWN_PREPARE: - /* Update our root-domain */ - rq = cpu_rq(cpu); - spin_lock_irqsave(&rq->lock, flags); - if (rq->rd) { - BUG_ON(!cpu_isset(cpu, rq->rd->span)); - cpu_clear(cpu, rq->rd->online); - } - spin_unlock_irqrestore(&rq->lock, flags); - break; #endif + case CPU_LOCK_RELEASE: + mutex_unlock(&sched_hotcpu_mutex); + break; } return NOTIFY_OK; } @@ -6088,76 +5831,11 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent) return 1; } -static void rq_attach_root(struct rq *rq, struct root_domain *rd) -{ - unsigned long flags; - const struct sched_class *class; - - spin_lock_irqsave(&rq->lock, flags); - - if (rq->rd) { - struct root_domain *old_rd = rq->rd; - - for (class = sched_class_highest; class; class = class->next) { - if (class->leave_domain) - class->leave_domain(rq); - } - - cpu_clear(rq->cpu, old_rd->span); - cpu_clear(rq->cpu, old_rd->online); - - if (atomic_dec_and_test(&old_rd->refcount)) - kfree(old_rd); - } - - atomic_inc(&rd->refcount); - rq->rd = rd; - - cpu_set(rq->cpu, rd->span); - if (cpu_isset(rq->cpu, cpu_online_map)) - cpu_set(rq->cpu, rd->online); - - for (class = sched_class_highest; class; class = class->next) { - if (class->join_domain) - class->join_domain(rq); - } - - spin_unlock_irqrestore(&rq->lock, flags); -} - -static void init_rootdomain(struct root_domain *rd) -{ - memset(rd, 0, sizeof(*rd)); - - cpus_clear(rd->span); - cpus_clear(rd->online); -} - -static void init_defrootdomain(void) -{ - init_rootdomain(&def_root_domain); - atomic_set(&def_root_domain.refcount, 1); -} - -static struct root_domain *alloc_rootdomain(void) -{ - struct root_domain *rd; - - rd = kmalloc(sizeof(*rd), GFP_KERNEL); - if (!rd) - return NULL; - - init_rootdomain(rd); - - return rd; -} - /* - * Attach the domain 'sd' to 'cpu' as its base domain. Callers must + * Attach the domain 'sd' to 'cpu' as its base domain. Callers must * hold the hotplug lock. */ -static void -cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu) +static void cpu_attach_domain(struct sched_domain *sd, int cpu) { struct rq *rq = cpu_rq(cpu); struct sched_domain *tmp; @@ -6182,7 +5860,6 @@ cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu) sched_domain_debug(sd, cpu); - rq_attach_root(rq, rd); rcu_assign_pointer(rq->sd, sd); } @@ -6551,7 +6228,6 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) static int build_sched_domains(const cpumask_t *cpu_map) { int i; - struct root_domain *rd; #ifdef CONFIG_NUMA struct sched_group **sched_group_nodes = NULL; int sd_allnodes = 0; @@ -6568,12 +6244,6 @@ static int build_sched_domains(const cpumask_t *cpu_map) sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes; #endif - rd = alloc_rootdomain(); - if (!rd) { - printk(KERN_WARNING "Cannot alloc root domain\n"); - return -ENOMEM; - } - /* * Set up domains for cpus specified by the cpu_map. */ @@ -6790,7 +6460,7 @@ static int build_sched_domains(const cpumask_t *cpu_map) #else sd = &per_cpu(phys_domains, i); #endif - cpu_attach_domain(sd, rd, i); + cpu_attach_domain(sd, i); } return 0; @@ -6848,7 +6518,7 @@ static void detach_destroy_domains(const cpumask_t *cpu_map) unregister_sched_domain_sysctl(); for_each_cpu_mask(i, *cpu_map) - cpu_attach_domain(NULL, &def_root_domain, i); + cpu_attach_domain(NULL, i); synchronize_sched(); arch_destroy_sched_domains(cpu_map); } @@ -6878,8 +6548,6 @@ void partition_sched_domains(int ndoms_new, cpumask_t *doms_new) { int i, j; - lock_doms_cur(); - /* always unregister in case we don't destroy any domains */ unregister_sched_domain_sysctl(); @@ -6920,8 +6588,6 @@ void partition_sched_domains(int ndoms_new, cpumask_t *doms_new) ndoms_cur = ndoms_new; register_sched_domain_sysctl(); - - unlock_doms_cur(); } #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) @@ -6929,10 +6595,10 @@ static int arch_reinit_sched_domains(void) { int err; - get_online_cpus(); + mutex_lock(&sched_hotcpu_mutex); detach_destroy_domains(&cpu_online_map); err = arch_init_sched_domains(&cpu_online_map); - put_online_cpus(); + mutex_unlock(&sched_hotcpu_mutex); return err; } @@ -7043,12 +6709,12 @@ void __init sched_init_smp(void) { cpumask_t non_isolated_cpus; - get_online_cpus(); + mutex_lock(&sched_hotcpu_mutex); arch_init_sched_domains(&cpu_online_map); cpus_andnot(non_isolated_cpus, cpu_possible_map, cpu_isolated_map); if (cpus_empty(non_isolated_cpus)) cpu_set(smp_processor_id(), non_isolated_cpus); - put_online_cpus(); + mutex_unlock(&sched_hotcpu_mutex); /* XXX: Theoretical race here - CPU may be hotplugged now */ hotcpu_notifier(update_sched_domains, 0); @@ -7056,21 +6722,6 @@ void __init sched_init_smp(void) if (set_cpus_allowed(current, non_isolated_cpus) < 0) BUG(); sched_init_granularity(); - -#ifdef CONFIG_FAIR_GROUP_SCHED - if (nr_cpu_ids == 1) - return; - - lb_monitor_task = kthread_create(load_balance_monitor, NULL, - "group_balance"); - if (!IS_ERR(lb_monitor_task)) { - lb_monitor_task->flags |= PF_NOFREEZE; - wake_up_process(lb_monitor_task); - } else { - printk(KERN_ERR "Could not create load balance monitor thread" - "(error = %ld) \n", PTR_ERR(lb_monitor_task)); - } -#endif } #else void __init sched_init_smp(void) @@ -7095,87 +6746,13 @@ static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq) cfs_rq->min_vruntime = (u64)(-(1LL << 20)); } -static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) -{ - struct rt_prio_array *array; - int i; - - array = &rt_rq->active; - for (i = 0; i < MAX_RT_PRIO; i++) { - INIT_LIST_HEAD(array->queue + i); - __clear_bit(i, array->bitmap); - } - /* delimiter for bitsearch: */ - __set_bit(MAX_RT_PRIO, array->bitmap); - -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED - rt_rq->highest_prio = MAX_RT_PRIO; -#endif -#ifdef CONFIG_SMP - rt_rq->rt_nr_migratory = 0; - rt_rq->overloaded = 0; -#endif - - rt_rq->rt_time = 0; - rt_rq->rt_throttled = 0; - -#ifdef CONFIG_FAIR_GROUP_SCHED - rt_rq->rq = rq; -#endif -} - -#ifdef CONFIG_FAIR_GROUP_SCHED -static void init_tg_cfs_entry(struct rq *rq, struct task_group *tg, - struct cfs_rq *cfs_rq, struct sched_entity *se, - int cpu, int add) -{ - tg->cfs_rq[cpu] = cfs_rq; - init_cfs_rq(cfs_rq, rq); - cfs_rq->tg = tg; - if (add) - list_add(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list); - - tg->se[cpu] = se; - se->cfs_rq = &rq->cfs; - se->my_q = cfs_rq; - se->load.weight = tg->shares; - se->load.inv_weight = div64_64(1ULL<<32, se->load.weight); - se->parent = NULL; -} - -static void init_tg_rt_entry(struct rq *rq, struct task_group *tg, - struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, - int cpu, int add) -{ - tg->rt_rq[cpu] = rt_rq; - init_rt_rq(rt_rq, rq); - rt_rq->tg = tg; - rt_rq->rt_se = rt_se; - if (add) - list_add(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list); - - tg->rt_se[cpu] = rt_se; - rt_se->rt_rq = &rq->rt; - rt_se->my_q = rt_rq; - rt_se->parent = NULL; - INIT_LIST_HEAD(&rt_se->run_list); -} -#endif - void __init sched_init(void) { int highest_cpu = 0; int i, j; -#ifdef CONFIG_SMP - init_defrootdomain(); -#endif - -#ifdef CONFIG_FAIR_GROUP_SCHED - list_add(&init_task_group.list, &task_groups); -#endif - for_each_possible_cpu(i) { + struct rt_prio_array *array; struct rq *rq; rq = cpu_rq(i); @@ -7184,39 +6761,52 @@ void __init sched_init(void) rq->nr_running = 0; rq->clock = 1; init_cfs_rq(&rq->cfs, rq); - init_rt_rq(&rq->rt, rq); #ifdef CONFIG_FAIR_GROUP_SCHED - init_task_group.shares = init_task_group_load; INIT_LIST_HEAD(&rq->leaf_cfs_rq_list); - init_tg_cfs_entry(rq, &init_task_group, - &per_cpu(init_cfs_rq, i), - &per_cpu(init_sched_entity, i), i, 1); - - init_task_group.rt_ratio = sysctl_sched_rt_ratio; /* XXX */ - INIT_LIST_HEAD(&rq->leaf_rt_rq_list); - init_tg_rt_entry(rq, &init_task_group, - &per_cpu(init_rt_rq, i), - &per_cpu(init_sched_rt_entity, i), i, 1); + { + struct cfs_rq *cfs_rq = &per_cpu(init_cfs_rq, i); + struct sched_entity *se = + &per_cpu(init_sched_entity, i); + + init_cfs_rq_p[i] = cfs_rq; + init_cfs_rq(cfs_rq, rq); + cfs_rq->tg = &init_task_group; + list_add(&cfs_rq->leaf_cfs_rq_list, + &rq->leaf_cfs_rq_list); + + init_sched_entity_p[i] = se; + se->cfs_rq = &rq->cfs; + se->my_q = cfs_rq; + se->load.weight = init_task_group_load; + se->load.inv_weight = + div64_64(1ULL<<32, init_task_group_load); + se->parent = NULL; + } + init_task_group.shares = init_task_group_load; + spin_lock_init(&init_task_group.lock); #endif - rq->rt_period_expire = 0; - rq->rt_throttled = 0; for (j = 0; j < CPU_LOAD_IDX_MAX; j++) rq->cpu_load[j] = 0; #ifdef CONFIG_SMP rq->sd = NULL; - rq->rd = NULL; rq->active_balance = 0; rq->next_balance = jiffies; rq->push_cpu = 0; rq->cpu = i; rq->migration_thread = NULL; INIT_LIST_HEAD(&rq->migration_queue); - rq_attach_root(rq, &def_root_domain); #endif - init_rq_hrtick(rq); atomic_set(&rq->nr_iowait, 0); + + array = &rq->rt.active; + for (j = 0; j < MAX_RT_PRIO; j++) { + INIT_LIST_HEAD(array->queue + j); + __clear_bit(j, array->bitmap); + } highest_cpu = i; + /* delimiter for bitsearch: */ + __set_bit(MAX_RT_PRIO, array->bitmap); } set_load_weight(&init_task); @@ -7385,187 +6975,12 @@ void set_curr_task(int cpu, struct task_struct *p) #ifdef CONFIG_FAIR_GROUP_SCHED -#ifdef CONFIG_SMP -/* - * distribute shares of all task groups among their schedulable entities, - * to reflect load distribution across cpus. - */ -static int rebalance_shares(struct sched_domain *sd, int this_cpu) -{ - struct cfs_rq *cfs_rq; - struct rq *rq = cpu_rq(this_cpu); - cpumask_t sdspan = sd->span; - int balanced = 1; - - /* Walk thr' all the task groups that we have */ - for_each_leaf_cfs_rq(rq, cfs_rq) { - int i; - unsigned long total_load = 0, total_shares; - struct task_group *tg = cfs_rq->tg; - - /* Gather total task load of this group across cpus */ - for_each_cpu_mask(i, sdspan) - total_load += tg->cfs_rq[i]->load.weight; - - /* Nothing to do if this group has no load */ - if (!total_load) - continue; - - /* - * tg->shares represents the number of cpu shares the task group - * is eligible to hold on a single cpu. On N cpus, it is - * eligible to hold (N * tg->shares) number of cpu shares. - */ - total_shares = tg->shares * cpus_weight(sdspan); - - /* - * redistribute total_shares across cpus as per the task load - * distribution. - */ - for_each_cpu_mask(i, sdspan) { - unsigned long local_load, local_shares; - - local_load = tg->cfs_rq[i]->load.weight; - local_shares = (local_load * total_shares) / total_load; - if (!local_shares) - local_shares = MIN_GROUP_SHARES; - if (local_shares == tg->se[i]->load.weight) - continue; - - spin_lock_irq(&cpu_rq(i)->lock); - set_se_shares(tg->se[i], local_shares); - spin_unlock_irq(&cpu_rq(i)->lock); - balanced = 0; - } - } - - return balanced; -} - -/* - * How frequently should we rebalance_shares() across cpus? - * - * The more frequently we rebalance shares, the more accurate is the fairness - * of cpu bandwidth distribution between task groups. However higher frequency - * also implies increased scheduling overhead. - * - * sysctl_sched_min_bal_int_shares represents the minimum interval between - * consecutive calls to rebalance_shares() in the same sched domain. - * - * sysctl_sched_max_bal_int_shares represents the maximum interval between - * consecutive calls to rebalance_shares() in the same sched domain. - * - * These settings allows for the appropriate trade-off between accuracy of - * fairness and the associated overhead. - * - */ - -/* default: 8ms, units: milliseconds */ -const_debug unsigned int sysctl_sched_min_bal_int_shares = 8; - -/* default: 128ms, units: milliseconds */ -const_debug unsigned int sysctl_sched_max_bal_int_shares = 128; - -/* kernel thread that runs rebalance_shares() periodically */ -static int load_balance_monitor(void *unused) -{ - unsigned int timeout = sysctl_sched_min_bal_int_shares; - struct sched_param schedparm; - int ret; - - /* - * We don't want this thread's execution to be limited by the shares - * assigned to default group (init_task_group). Hence make it run - * as a SCHED_RR RT task at the lowest priority. - */ - schedparm.sched_priority = 1; - ret = sched_setscheduler(current, SCHED_RR, &schedparm); - if (ret) - printk(KERN_ERR "Couldn't set SCHED_RR policy for load balance" - " monitor thread (error = %d) \n", ret); - - while (!kthread_should_stop()) { - int i, cpu, balanced = 1; - - /* Prevent cpus going down or coming up */ - get_online_cpus(); - /* lockout changes to doms_cur[] array */ - lock_doms_cur(); - /* - * Enter a rcu read-side critical section to safely walk rq->sd - * chain on various cpus and to walk task group list - * (rq->leaf_cfs_rq_list) in rebalance_shares(). - */ - rcu_read_lock(); - - for (i = 0; i < ndoms_cur; i++) { - cpumask_t cpumap = doms_cur[i]; - struct sched_domain *sd = NULL, *sd_prev = NULL; - - cpu = first_cpu(cpumap); - - /* Find the highest domain at which to balance shares */ - for_each_domain(cpu, sd) { - if (!(sd->flags & SD_LOAD_BALANCE)) - continue; - sd_prev = sd; - } - - sd = sd_prev; - /* sd == NULL? No load balance reqd in this domain */ - if (!sd) - continue; - - balanced &= rebalance_shares(sd, cpu); - } - - rcu_read_unlock(); - - unlock_doms_cur(); - put_online_cpus(); - - if (!balanced) - timeout = sysctl_sched_min_bal_int_shares; - else if (timeout < sysctl_sched_max_bal_int_shares) - timeout *= 2; - - msleep_interruptible(timeout); - } - - return 0; -} -#endif /* CONFIG_SMP */ - -static void free_sched_group(struct task_group *tg) -{ - int i; - - for_each_possible_cpu(i) { - if (tg->cfs_rq) - kfree(tg->cfs_rq[i]); - if (tg->se) - kfree(tg->se[i]); - if (tg->rt_rq) - kfree(tg->rt_rq[i]); - if (tg->rt_se) - kfree(tg->rt_se[i]); - } - - kfree(tg->cfs_rq); - kfree(tg->se); - kfree(tg->rt_rq); - kfree(tg->rt_se); - kfree(tg); -} - /* allocate runqueue etc for a new task group */ struct task_group *sched_create_group(void) { struct task_group *tg; struct cfs_rq *cfs_rq; struct sched_entity *se; - struct rt_rq *rt_rq; - struct sched_rt_entity *rt_se; struct rq *rq; int i; @@ -7579,89 +6994,97 @@ struct task_group *sched_create_group(void) tg->se = kzalloc(sizeof(se) * NR_CPUS, GFP_KERNEL); if (!tg->se) goto err; - tg->rt_rq = kzalloc(sizeof(rt_rq) * NR_CPUS, GFP_KERNEL); - if (!tg->rt_rq) - goto err; - tg->rt_se = kzalloc(sizeof(rt_se) * NR_CPUS, GFP_KERNEL); - if (!tg->rt_se) - goto err; - - tg->shares = NICE_0_LOAD; - tg->rt_ratio = 0; /* XXX */ for_each_possible_cpu(i) { rq = cpu_rq(i); - cfs_rq = kmalloc_node(sizeof(struct cfs_rq), - GFP_KERNEL|__GFP_ZERO, cpu_to_node(i)); + cfs_rq = kmalloc_node(sizeof(struct cfs_rq), GFP_KERNEL, + cpu_to_node(i)); if (!cfs_rq) goto err; - se = kmalloc_node(sizeof(struct sched_entity), - GFP_KERNEL|__GFP_ZERO, cpu_to_node(i)); + se = kmalloc_node(sizeof(struct sched_entity), GFP_KERNEL, + cpu_to_node(i)); if (!se) goto err; - rt_rq = kmalloc_node(sizeof(struct rt_rq), - GFP_KERNEL|__GFP_ZERO, cpu_to_node(i)); - if (!rt_rq) - goto err; + memset(cfs_rq, 0, sizeof(struct cfs_rq)); + memset(se, 0, sizeof(struct sched_entity)); - rt_se = kmalloc_node(sizeof(struct sched_rt_entity), - GFP_KERNEL|__GFP_ZERO, cpu_to_node(i)); - if (!rt_se) - goto err; + tg->cfs_rq[i] = cfs_rq; + init_cfs_rq(cfs_rq, rq); + cfs_rq->tg = tg; - init_tg_cfs_entry(rq, tg, cfs_rq, se, i, 0); - init_tg_rt_entry(rq, tg, rt_rq, rt_se, i, 0); + tg->se[i] = se; + se->cfs_rq = &rq->cfs; + se->my_q = cfs_rq; + se->load.weight = NICE_0_LOAD; + se->load.inv_weight = div64_64(1ULL<<32, NICE_0_LOAD); + se->parent = NULL; } - lock_task_group_list(); for_each_possible_cpu(i) { rq = cpu_rq(i); cfs_rq = tg->cfs_rq[i]; list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list); - rt_rq = tg->rt_rq[i]; - list_add_rcu(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list); } - list_add_rcu(&tg->list, &task_groups); - unlock_task_group_list(); + + tg->shares = NICE_0_LOAD; + spin_lock_init(&tg->lock); return tg; err: - free_sched_group(tg); + for_each_possible_cpu(i) { + if (tg->cfs_rq) + kfree(tg->cfs_rq[i]); + if (tg->se) + kfree(tg->se[i]); + } + kfree(tg->cfs_rq); + kfree(tg->se); + kfree(tg); + return ERR_PTR(-ENOMEM); } /* rcu callback to free various structures associated with a task group */ -static void free_sched_group_rcu(struct rcu_head *rhp) +static void free_sched_group(struct rcu_head *rhp) { + struct task_group *tg = container_of(rhp, struct task_group, rcu); + struct cfs_rq *cfs_rq; + struct sched_entity *se; + int i; + /* now it should be safe to free those cfs_rqs */ - free_sched_group(container_of(rhp, struct task_group, rcu)); + for_each_possible_cpu(i) { + cfs_rq = tg->cfs_rq[i]; + kfree(cfs_rq); + + se = tg->se[i]; + kfree(se); + } + + kfree(tg->cfs_rq); + kfree(tg->se); + kfree(tg); } /* Destroy runqueue etc associated with a task group */ void sched_destroy_group(struct task_group *tg) { struct cfs_rq *cfs_rq = NULL; - struct rt_rq *rt_rq = NULL; int i; - lock_task_group_list(); for_each_possible_cpu(i) { cfs_rq = tg->cfs_rq[i]; list_del_rcu(&cfs_rq->leaf_cfs_rq_list); - rt_rq = tg->rt_rq[i]; - list_del_rcu(&rt_rq->leaf_rt_rq_list); } - list_del_rcu(&tg->list); - unlock_task_group_list(); BUG_ON(!cfs_rq); /* wait for possible concurrent references to cfs_rqs complete */ - call_rcu(&tg->rcu, free_sched_group_rcu); + call_rcu(&tg->rcu, free_sched_group); } /* change task's runqueue when it moves between groups. @@ -7677,6 +7100,11 @@ void sched_move_task(struct task_struct *tsk) rq = task_rq_lock(tsk, &flags); + if (tsk->sched_class != &fair_sched_class) { + set_task_cfs_rq(tsk, task_cpu(tsk)); + goto done; + } + update_rq_clock(rq); running = task_current(rq, tsk); @@ -7688,7 +7116,7 @@ void sched_move_task(struct task_struct *tsk) tsk->sched_class->put_prev_task(rq, tsk); } - set_task_rq(tsk, task_cpu(tsk)); + set_task_cfs_rq(tsk, task_cpu(tsk)); if (on_rq) { if (unlikely(running)) @@ -7696,82 +7124,53 @@ void sched_move_task(struct task_struct *tsk) enqueue_task(rq, tsk, 0); } +done: task_rq_unlock(rq, &flags); } -/* rq->lock to be locked by caller */ static void set_se_shares(struct sched_entity *se, unsigned long shares) { struct cfs_rq *cfs_rq = se->cfs_rq; struct rq *rq = cfs_rq->rq; int on_rq; - if (!shares) - shares = MIN_GROUP_SHARES; + spin_lock_irq(&rq->lock); on_rq = se->on_rq; - if (on_rq) { + if (on_rq) dequeue_entity(cfs_rq, se, 0); - dec_cpu_load(rq, se->load.weight); - } se->load.weight = shares; se->load.inv_weight = div64_64((1ULL<<32), shares); - if (on_rq) { + if (on_rq) enqueue_entity(cfs_rq, se, 0); - inc_cpu_load(rq, se->load.weight); - } + + spin_unlock_irq(&rq->lock); } int sched_group_set_shares(struct task_group *tg, unsigned long shares) { int i; - struct cfs_rq *cfs_rq; - struct rq *rq; - - lock_task_group_list(); - if (tg->shares == shares) - goto done; - - if (shares < MIN_GROUP_SHARES) - shares = MIN_GROUP_SHARES; /* - * Prevent any load balance activity (rebalance_shares, - * load_balance_fair) from referring to this group first, - * by taking it off the rq->leaf_cfs_rq_list on each cpu. + * A weight of 0 or 1 can cause arithmetics problems. + * (The default weight is 1024 - so there's no practical + * limitation from this.) */ - for_each_possible_cpu(i) { - cfs_rq = tg->cfs_rq[i]; - list_del_rcu(&cfs_rq->leaf_cfs_rq_list); - } + if (shares < 2) + shares = 2; - /* wait for any ongoing reference to this group to finish */ - synchronize_sched(); + spin_lock(&tg->lock); + if (tg->shares == shares) + goto done; - /* - * Now we are free to modify the group's share on each cpu - * w/o tripping rebalance_share or load_balance_fair. - */ tg->shares = shares; - for_each_possible_cpu(i) { - spin_lock_irq(&cpu_rq(i)->lock); + for_each_possible_cpu(i) set_se_shares(tg->se[i], shares); - spin_unlock_irq(&cpu_rq(i)->lock); - } - /* - * Enable load balance activity on this group, by inserting it back on - * each cpu's rq->leaf_cfs_rq_list. - */ - for_each_possible_cpu(i) { - rq = cpu_rq(i); - cfs_rq = tg->cfs_rq[i]; - list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list); - } done: - unlock_task_group_list(); + spin_unlock(&tg->lock); return 0; } @@ -7780,31 +7179,6 @@ unsigned long sched_group_shares(struct task_group *tg) return tg->shares; } -/* - * Ensure the total rt_ratio <= sysctl_sched_rt_ratio - */ -int sched_group_set_rt_ratio(struct task_group *tg, unsigned long rt_ratio) -{ - struct task_group *tgi; - unsigned long total = 0; - - rcu_read_lock(); - list_for_each_entry_rcu(tgi, &task_groups, list) - total += tgi->rt_ratio; - rcu_read_unlock(); - - if (total + rt_ratio - tg->rt_ratio > sysctl_sched_rt_ratio) - return -EINVAL; - - tg->rt_ratio = rt_ratio; - return 0; -} - -unsigned long sched_group_rt_ratio(struct task_group *tg) -{ - return tg->rt_ratio; -} - #endif /* CONFIG_FAIR_GROUP_SCHED */ #ifdef CONFIG_FAIR_CGROUP_SCHED @@ -7880,30 +7254,12 @@ static u64 cpu_shares_read_uint(struct cgroup *cgrp, struct cftype *cft) return (u64) tg->shares; } -static int cpu_rt_ratio_write_uint(struct cgroup *cgrp, struct cftype *cftype, - u64 rt_ratio_val) -{ - return sched_group_set_rt_ratio(cgroup_tg(cgrp), rt_ratio_val); -} - -static u64 cpu_rt_ratio_read_uint(struct cgroup *cgrp, struct cftype *cft) -{ - struct task_group *tg = cgroup_tg(cgrp); - - return (u64) tg->rt_ratio; -} - static struct cftype cpu_files[] = { { .name = "shares", .read_uint = cpu_shares_read_uint, .write_uint = cpu_shares_write_uint, }, - { - .name = "rt_ratio", - .read_uint = cpu_rt_ratio_read_uint, - .write_uint = cpu_rt_ratio_write_uint, - }, }; static int cpu_cgroup_populate(struct cgroup_subsys *ss, struct cgroup *cont) diff --git a/trunk/kernel/sched_debug.c b/trunk/kernel/sched_debug.c index 4b5e24cf2f4a..80fbbfc04290 100644 --- a/trunk/kernel/sched_debug.c +++ b/trunk/kernel/sched_debug.c @@ -179,7 +179,6 @@ static void print_cpu(struct seq_file *m, int cpu) PN(prev_clock_raw); P(clock_warps); P(clock_overflows); - P(clock_underflows); P(clock_deep_idle_events); PN(clock_max_delta); P(cpu_load[0]); @@ -300,8 +299,6 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m) PN(se.exec_max); PN(se.slice_max); PN(se.wait_max); - PN(se.wait_sum); - P(se.wait_count); P(sched_info.bkl_count); P(se.nr_migrations); P(se.nr_migrations_cold); @@ -369,8 +366,6 @@ void proc_sched_set_task(struct task_struct *p) { #ifdef CONFIG_SCHEDSTATS p->se.wait_max = 0; - p->se.wait_sum = 0; - p->se.wait_count = 0; p->se.sleep_max = 0; p->se.sum_sleep_runtime = 0; p->se.block_max = 0; diff --git a/trunk/kernel/sched_fair.c b/trunk/kernel/sched_fair.c index 72e25c7a3a18..da7c061e7206 100644 --- a/trunk/kernel/sched_fair.c +++ b/trunk/kernel/sched_fair.c @@ -20,8 +20,6 @@ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra */ -#include - /* * Targeted preemption latency for CPU-bound tasks: * (default: 20ms * (1 + ilog(ncpus)), units: nanoseconds) @@ -250,8 +248,8 @@ static u64 __sched_period(unsigned long nr_running) unsigned long nr_latency = sched_nr_latency; if (unlikely(nr_running > nr_latency)) { - period = sysctl_sched_min_granularity; period *= nr_running; + do_div(period, nr_latency); } return period; @@ -385,9 +383,6 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) { schedstat_set(se->wait_max, max(se->wait_max, rq_of(cfs_rq)->clock - se->wait_start)); - schedstat_set(se->wait_count, se->wait_count + 1); - schedstat_set(se->wait_sum, se->wait_sum + - rq_of(cfs_rq)->clock - se->wait_start); schedstat_set(se->wait_start, 0); } @@ -439,7 +434,6 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) #ifdef CONFIG_SCHEDSTATS if (se->sleep_start) { u64 delta = rq_of(cfs_rq)->clock - se->sleep_start; - struct task_struct *tsk = task_of(se); if ((s64)delta < 0) delta = 0; @@ -449,12 +443,9 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) se->sleep_start = 0; se->sum_sleep_runtime += delta; - - account_scheduler_latency(tsk, delta >> 10, 1); } if (se->block_start) { u64 delta = rq_of(cfs_rq)->clock - se->block_start; - struct task_struct *tsk = task_of(se); if ((s64)delta < 0) delta = 0; @@ -471,11 +462,11 @@ static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) * time that the task spent sleeping: */ if (unlikely(prof_on == SLEEP_PROFILING)) { + struct task_struct *tsk = task_of(se); profile_hits(SLEEP_PROFILING, (void *)get_wchan(tsk), delta >> 20); } - account_scheduler_latency(tsk, delta >> 10, 0); } #endif } @@ -651,29 +642,13 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev) cfs_rq->curr = NULL; } -static void -entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) +static void entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) { /* * Update run-time statistics of the 'current'. */ update_curr(cfs_rq); -#ifdef CONFIG_SCHED_HRTICK - /* - * queued ticks are scheduled to match the slice, so don't bother - * validating it and just reschedule. - */ - if (queued) - return resched_task(rq_of(cfs_rq)->curr); - /* - * don't let the period tick interfere with the hrtick preemption - */ - if (!sched_feat(DOUBLE_TICK) && - hrtimer_active(&rq_of(cfs_rq)->hrtick_timer)) - return; -#endif - if (cfs_rq->nr_running > 1 || !sched_feat(WAKEUP_PREEMPT)) check_preempt_tick(cfs_rq, curr); } @@ -715,7 +690,7 @@ static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu) /* Iterate thr' all leaf cfs_rq's on a runqueue */ #define for_each_leaf_cfs_rq(rq, cfs_rq) \ - list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list) + list_for_each_entry(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list) /* Do the two (enqueued) entities belong to the same group ? */ static inline int @@ -732,8 +707,6 @@ static inline struct sched_entity *parent_entity(struct sched_entity *se) return se->parent; } -#define GROUP_IMBALANCE_PCT 20 - #else /* CONFIG_FAIR_GROUP_SCHED */ #define for_each_sched_entity(se) \ @@ -779,43 +752,6 @@ static inline struct sched_entity *parent_entity(struct sched_entity *se) #endif /* CONFIG_FAIR_GROUP_SCHED */ -#ifdef CONFIG_SCHED_HRTICK -static void hrtick_start_fair(struct rq *rq, struct task_struct *p) -{ - int requeue = rq->curr == p; - struct sched_entity *se = &p->se; - struct cfs_rq *cfs_rq = cfs_rq_of(se); - - WARN_ON(task_rq(p) != rq); - - if (hrtick_enabled(rq) && cfs_rq->nr_running > 1) { - u64 slice = sched_slice(cfs_rq, se); - u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime; - s64 delta = slice - ran; - - if (delta < 0) { - if (rq->curr == p) - resched_task(p); - return; - } - - /* - * Don't schedule slices shorter than 10000ns, that just - * doesn't make sense. Rely on vruntime for fairness. - */ - if (!requeue) - delta = max(10000LL, delta); - - hrtick_start(rq, delta, requeue); - } -} -#else -static inline void -hrtick_start_fair(struct rq *rq, struct task_struct *p) -{ -} -#endif - /* * The enqueue_task method is called before nr_running is * increased. Here we update the fair scheduling stats and @@ -824,28 +760,15 @@ hrtick_start_fair(struct rq *rq, struct task_struct *p) static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup) { struct cfs_rq *cfs_rq; - struct sched_entity *se = &p->se, - *topse = NULL; /* Highest schedulable entity */ - int incload = 1; + struct sched_entity *se = &p->se; for_each_sched_entity(se) { - topse = se; - if (se->on_rq) { - incload = 0; + if (se->on_rq) break; - } cfs_rq = cfs_rq_of(se); enqueue_entity(cfs_rq, se, wakeup); wakeup = 1; } - /* Increment cpu load if we just enqueued the first task of a group on - * 'rq->cpu'. 'topse' represents the group to which task 'p' belongs - * at the highest grouping level. - */ - if (incload) - inc_cpu_load(rq, topse->load.weight); - - hrtick_start_fair(rq, rq->curr); } /* @@ -856,30 +779,16 @@ static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int wakeup) static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep) { struct cfs_rq *cfs_rq; - struct sched_entity *se = &p->se, - *topse = NULL; /* Highest schedulable entity */ - int decload = 1; + struct sched_entity *se = &p->se; for_each_sched_entity(se) { - topse = se; cfs_rq = cfs_rq_of(se); dequeue_entity(cfs_rq, se, sleep); /* Don't dequeue parent if it has other entities besides us */ - if (cfs_rq->load.weight) { - if (parent_entity(se)) - decload = 0; + if (cfs_rq->load.weight) break; - } sleep = 1; } - /* Decrement cpu load if we just dequeued the last task of a group on - * 'rq->cpu'. 'topse' represents the group to which task 'p' belongs - * at the highest grouping level. - */ - if (decload) - dec_cpu_load(rq, topse->load.weight); - - hrtick_start_fair(rq, rq->curr); } /* @@ -926,154 +835,6 @@ static void yield_task_fair(struct rq *rq) se->vruntime = rightmost->vruntime + 1; } -/* - * wake_idle() will wake a task on an idle cpu if task->cpu is - * not idle and an idle cpu is available. The span of cpus to - * search starts with cpus closest then further out as needed, - * so we always favor a closer, idle cpu. - * - * Returns the CPU we should wake onto. - */ -#if defined(ARCH_HAS_SCHED_WAKE_IDLE) -static int wake_idle(int cpu, struct task_struct *p) -{ - cpumask_t tmp; - struct sched_domain *sd; - int i; - - /* - * If it is idle, then it is the best cpu to run this task. - * - * This cpu is also the best, if it has more than one task already. - * Siblings must be also busy(in most cases) as they didn't already - * pickup the extra load from this cpu and hence we need not check - * sibling runqueue info. This will avoid the checks and cache miss - * penalities associated with that. - */ - if (idle_cpu(cpu) || cpu_rq(cpu)->nr_running > 1) - return cpu; - - for_each_domain(cpu, sd) { - if (sd->flags & SD_WAKE_IDLE) { - cpus_and(tmp, sd->span, p->cpus_allowed); - for_each_cpu_mask(i, tmp) { - if (idle_cpu(i)) { - if (i != task_cpu(p)) { - schedstat_inc(p, - se.nr_wakeups_idle); - } - return i; - } - } - } else { - break; - } - } - return cpu; -} -#else -static inline int wake_idle(int cpu, struct task_struct *p) -{ - return cpu; -} -#endif - -#ifdef CONFIG_SMP -static int select_task_rq_fair(struct task_struct *p, int sync) -{ - int cpu, this_cpu; - struct rq *rq; - struct sched_domain *sd, *this_sd = NULL; - int new_cpu; - - cpu = task_cpu(p); - rq = task_rq(p); - this_cpu = smp_processor_id(); - new_cpu = cpu; - - if (cpu == this_cpu) - goto out_set_cpu; - - for_each_domain(this_cpu, sd) { - if (cpu_isset(cpu, sd->span)) { - this_sd = sd; - break; - } - } - - if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed))) - goto out_set_cpu; - - /* - * Check for affine wakeup and passive balancing possibilities. - */ - if (this_sd) { - int idx = this_sd->wake_idx; - unsigned int imbalance; - unsigned long load, this_load; - - imbalance = 100 + (this_sd->imbalance_pct - 100) / 2; - - load = source_load(cpu, idx); - this_load = target_load(this_cpu, idx); - - new_cpu = this_cpu; /* Wake to this CPU if we can */ - - if (this_sd->flags & SD_WAKE_AFFINE) { - unsigned long tl = this_load; - unsigned long tl_per_task; - - /* - * Attract cache-cold tasks on sync wakeups: - */ - if (sync && !task_hot(p, rq->clock, this_sd)) - goto out_set_cpu; - - schedstat_inc(p, se.nr_wakeups_affine_attempts); - tl_per_task = cpu_avg_load_per_task(this_cpu); - - /* - * If sync wakeup then subtract the (maximum possible) - * effect of the currently running task from the load - * of the current CPU: - */ - if (sync) - tl -= current->se.load.weight; - - if ((tl <= load && - tl + target_load(cpu, idx) <= tl_per_task) || - 100*(tl + p->se.load.weight) <= imbalance*load) { - /* - * This domain has SD_WAKE_AFFINE and - * p is cache cold in this domain, and - * there is no bad imbalance. - */ - schedstat_inc(this_sd, ttwu_move_affine); - schedstat_inc(p, se.nr_wakeups_affine); - goto out_set_cpu; - } - } - - /* - * Start passive balancing when half the imbalance_pct - * limit is reached. - */ - if (this_sd->flags & SD_WAKE_BALANCE) { - if (imbalance*this_load <= 100*load) { - schedstat_inc(this_sd, ttwu_move_balance); - schedstat_inc(p, se.nr_wakeups_passive); - goto out_set_cpu; - } - } - } - - new_cpu = cpu; /* Could not wake to this_cpu. Wake to cpu instead */ -out_set_cpu: - return wake_idle(new_cpu, p); -} -#endif /* CONFIG_SMP */ - - /* * Preempt the current task with a newly woken task if needed: */ @@ -1115,7 +876,6 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p) static struct task_struct *pick_next_task_fair(struct rq *rq) { - struct task_struct *p; struct cfs_rq *cfs_rq = &rq->cfs; struct sched_entity *se; @@ -1127,10 +887,7 @@ static struct task_struct *pick_next_task_fair(struct rq *rq) cfs_rq = group_cfs_rq(se); } while (cfs_rq); - p = task_of(se); - hrtick_start_fair(rq, p); - - return p; + return task_of(se); } /* @@ -1187,6 +944,25 @@ static struct task_struct *load_balance_next_fair(void *arg) return __load_balance_iterator(cfs_rq, cfs_rq->rb_load_balance_curr); } +#ifdef CONFIG_FAIR_GROUP_SCHED +static int cfs_rq_best_prio(struct cfs_rq *cfs_rq) +{ + struct sched_entity *curr; + struct task_struct *p; + + if (!cfs_rq->nr_running) + return MAX_PRIO; + + curr = cfs_rq->curr; + if (!curr) + curr = __pick_next_entity(cfs_rq); + + p = task_of(curr); + + return p->prio; +} +#endif + static unsigned long load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, unsigned long max_load_move, @@ -1196,45 +972,28 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, struct cfs_rq *busy_cfs_rq; long rem_load_move = max_load_move; struct rq_iterator cfs_rq_iterator; - unsigned long load_moved; cfs_rq_iterator.start = load_balance_start_fair; cfs_rq_iterator.next = load_balance_next_fair; for_each_leaf_cfs_rq(busiest, busy_cfs_rq) { #ifdef CONFIG_FAIR_GROUP_SCHED - struct cfs_rq *this_cfs_rq = busy_cfs_rq->tg->cfs_rq[this_cpu]; - unsigned long maxload, task_load, group_weight; - unsigned long thisload, per_task_load; - struct sched_entity *se = busy_cfs_rq->tg->se[busiest->cpu]; - - task_load = busy_cfs_rq->load.weight; - group_weight = se->load.weight; + struct cfs_rq *this_cfs_rq; + long imbalance; + unsigned long maxload; - /* - * 'group_weight' is contributed by tasks of total weight - * 'task_load'. To move 'rem_load_move' worth of weight only, - * we need to move a maximum task load of: - * - * maxload = (remload / group_weight) * task_load; - */ - maxload = (rem_load_move * task_load) / group_weight; + this_cfs_rq = cpu_cfs_rq(busy_cfs_rq, this_cpu); - if (!maxload || !task_load) + imbalance = busy_cfs_rq->load.weight - this_cfs_rq->load.weight; + /* Don't pull if this_cfs_rq has more load than busy_cfs_rq */ + if (imbalance <= 0) continue; - per_task_load = task_load / busy_cfs_rq->nr_running; - /* - * balance_tasks will try to forcibly move atleast one task if - * possible (because of SCHED_LOAD_SCALE_FUZZ). Avoid that if - * maxload is less than GROUP_IMBALANCE_FUZZ% the per_task_load. - */ - if (100 * maxload < GROUP_IMBALANCE_PCT * per_task_load) - continue; + /* Don't pull more than imbalance/2 */ + imbalance /= 2; + maxload = min(rem_load_move, imbalance); - /* Disable priority-based load balance */ - *this_best_prio = 0; - thisload = this_cfs_rq->load.weight; + *this_best_prio = cfs_rq_best_prio(this_cfs_rq); #else # define maxload rem_load_move #endif @@ -1243,33 +1002,11 @@ load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, * load_balance_[start|next]_fair iterators */ cfs_rq_iterator.arg = busy_cfs_rq; - load_moved = balance_tasks(this_rq, this_cpu, busiest, + rem_load_move -= balance_tasks(this_rq, this_cpu, busiest, maxload, sd, idle, all_pinned, this_best_prio, &cfs_rq_iterator); -#ifdef CONFIG_FAIR_GROUP_SCHED - /* - * load_moved holds the task load that was moved. The - * effective (group) weight moved would be: - * load_moved_eff = load_moved/task_load * group_weight; - */ - load_moved = (group_weight * load_moved) / task_load; - - /* Adjust shares on both cpus to reflect load_moved */ - group_weight -= load_moved; - set_se_shares(se, group_weight); - - se = busy_cfs_rq->tg->se[this_cpu]; - if (!thisload) - group_weight = load_moved; - else - group_weight = se->load.weight + load_moved; - set_se_shares(se, group_weight); -#endif - - rem_load_move -= load_moved; - if (rem_load_move <= 0) break; } @@ -1305,14 +1042,14 @@ move_one_task_fair(struct rq *this_rq, int this_cpu, struct rq *busiest, /* * scheduler tick hitting a task of our scheduling class: */ -static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) +static void task_tick_fair(struct rq *rq, struct task_struct *curr) { struct cfs_rq *cfs_rq; struct sched_entity *se = &curr->se; for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); - entity_tick(cfs_rq, se, queued); + entity_tick(cfs_rq, se); } } @@ -1350,42 +1087,6 @@ static void task_new_fair(struct rq *rq, struct task_struct *p) resched_task(rq->curr); } -/* - * Priority of the task has changed. Check to see if we preempt - * the current task. - */ -static void prio_changed_fair(struct rq *rq, struct task_struct *p, - int oldprio, int running) -{ - /* - * Reschedule if we are currently running on this runqueue and - * our priority decreased, or if we are not currently running on - * this runqueue and our priority is higher than the current's - */ - if (running) { - if (p->prio > oldprio) - resched_task(rq->curr); - } else - check_preempt_curr(rq, p); -} - -/* - * We switched to the sched_fair class. - */ -static void switched_to_fair(struct rq *rq, struct task_struct *p, - int running) -{ - /* - * We were most likely switched from sched_rt, so - * kick off the schedule if running, otherwise just see - * if we can still preempt the current task. - */ - if (running) - resched_task(rq->curr); - else - check_preempt_curr(rq, p); -} - /* Account for a task changing its policy or group. * * This routine is mostly called to set cfs_rq->curr field when a task @@ -1407,9 +1108,6 @@ static const struct sched_class fair_sched_class = { .enqueue_task = enqueue_task_fair, .dequeue_task = dequeue_task_fair, .yield_task = yield_task_fair, -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_fair, -#endif /* CONFIG_SMP */ .check_preempt_curr = check_preempt_wakeup, @@ -1424,9 +1122,6 @@ static const struct sched_class fair_sched_class = { .set_curr_task = set_curr_task_fair, .task_tick = task_tick_fair, .task_new = task_new_fair, - - .prio_changed = prio_changed_fair, - .switched_to = switched_to_fair, }; #ifdef CONFIG_SCHED_DEBUG @@ -1437,9 +1132,7 @@ static void print_cfs_stats(struct seq_file *m, int cpu) #ifdef CONFIG_FAIR_GROUP_SCHED print_cfs_rq(m, cpu, &cpu_rq(cpu)->cfs); #endif - rcu_read_lock(); for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq) print_cfs_rq(m, cpu, cfs_rq); - rcu_read_unlock(); } #endif diff --git a/trunk/kernel/sched_idletask.c b/trunk/kernel/sched_idletask.c index 2bcafa375633..bf9c25c15b8b 100644 --- a/trunk/kernel/sched_idletask.c +++ b/trunk/kernel/sched_idletask.c @@ -5,12 +5,6 @@ * handled in sched_fair.c) */ -#ifdef CONFIG_SMP -static int select_task_rq_idle(struct task_struct *p, int sync) -{ - return task_cpu(p); /* IDLE tasks as never migrated */ -} -#endif /* CONFIG_SMP */ /* * Idle tasks are unconditionally rescheduled: */ @@ -61,7 +55,7 @@ move_one_task_idle(struct rq *this_rq, int this_cpu, struct rq *busiest, } #endif -static void task_tick_idle(struct rq *rq, struct task_struct *curr, int queued) +static void task_tick_idle(struct rq *rq, struct task_struct *curr) { } @@ -69,33 +63,6 @@ static void set_curr_task_idle(struct rq *rq) { } -static void switched_to_idle(struct rq *rq, struct task_struct *p, - int running) -{ - /* Can this actually happen?? */ - if (running) - resched_task(rq->curr); - else - check_preempt_curr(rq, p); -} - -static void prio_changed_idle(struct rq *rq, struct task_struct *p, - int oldprio, int running) -{ - /* This can happen for hot plug CPUS */ - - /* - * Reschedule if we are currently running on this runqueue and - * our priority decreased, or if we are not currently running on - * this runqueue and our priority is higher than the current's - */ - if (running) { - if (p->prio > oldprio) - resched_task(rq->curr); - } else - check_preempt_curr(rq, p); -} - /* * Simple, special scheduling class for the per-CPU idle tasks: */ @@ -105,9 +72,6 @@ const struct sched_class idle_sched_class = { /* dequeue is not valid, we print a debug message there: */ .dequeue_task = dequeue_task_idle, -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_idle, -#endif /* CONFIG_SMP */ .check_preempt_curr = check_preempt_curr_idle, @@ -121,9 +85,5 @@ const struct sched_class idle_sched_class = { .set_curr_task = set_curr_task_idle, .task_tick = task_tick_idle, - - .prio_changed = prio_changed_idle, - .switched_to = switched_to_idle, - /* no .task_new for idle tasks */ }; diff --git a/trunk/kernel/sched_rt.c b/trunk/kernel/sched_rt.c index 274b40d7bef2..9ba3daa03475 100644 --- a/trunk/kernel/sched_rt.c +++ b/trunk/kernel/sched_rt.c @@ -3,217 +3,6 @@ * policies) */ -#ifdef CONFIG_SMP - -static inline int rt_overloaded(struct rq *rq) -{ - return atomic_read(&rq->rd->rto_count); -} - -static inline void rt_set_overload(struct rq *rq) -{ - cpu_set(rq->cpu, rq->rd->rto_mask); - /* - * Make sure the mask is visible before we set - * the overload count. That is checked to determine - * if we should look at the mask. It would be a shame - * if we looked at the mask, but the mask was not - * updated yet. - */ - wmb(); - atomic_inc(&rq->rd->rto_count); -} - -static inline void rt_clear_overload(struct rq *rq) -{ - /* the order here really doesn't matter */ - atomic_dec(&rq->rd->rto_count); - cpu_clear(rq->cpu, rq->rd->rto_mask); -} - -static void update_rt_migration(struct rq *rq) -{ - if (rq->rt.rt_nr_migratory && (rq->rt.rt_nr_running > 1)) { - if (!rq->rt.overloaded) { - rt_set_overload(rq); - rq->rt.overloaded = 1; - } - } else if (rq->rt.overloaded) { - rt_clear_overload(rq); - rq->rt.overloaded = 0; - } -} -#endif /* CONFIG_SMP */ - -static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se) -{ - return container_of(rt_se, struct task_struct, rt); -} - -static inline int on_rt_rq(struct sched_rt_entity *rt_se) -{ - return !list_empty(&rt_se->run_list); -} - -#ifdef CONFIG_FAIR_GROUP_SCHED - -static inline unsigned int sched_rt_ratio(struct rt_rq *rt_rq) -{ - if (!rt_rq->tg) - return SCHED_RT_FRAC; - - return rt_rq->tg->rt_ratio; -} - -#define for_each_leaf_rt_rq(rt_rq, rq) \ - list_for_each_entry(rt_rq, &rq->leaf_rt_rq_list, leaf_rt_rq_list) - -static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq) -{ - return rt_rq->rq; -} - -static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) -{ - return rt_se->rt_rq; -} - -#define for_each_sched_rt_entity(rt_se) \ - for (; rt_se; rt_se = rt_se->parent) - -static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) -{ - return rt_se->my_q; -} - -static void enqueue_rt_entity(struct sched_rt_entity *rt_se); -static void dequeue_rt_entity(struct sched_rt_entity *rt_se); - -static void sched_rt_ratio_enqueue(struct rt_rq *rt_rq) -{ - struct sched_rt_entity *rt_se = rt_rq->rt_se; - - if (rt_se && !on_rt_rq(rt_se) && rt_rq->rt_nr_running) { - struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr; - - enqueue_rt_entity(rt_se); - if (rt_rq->highest_prio < curr->prio) - resched_task(curr); - } -} - -static void sched_rt_ratio_dequeue(struct rt_rq *rt_rq) -{ - struct sched_rt_entity *rt_se = rt_rq->rt_se; - - if (rt_se && on_rt_rq(rt_se)) - dequeue_rt_entity(rt_se); -} - -#else - -static inline unsigned int sched_rt_ratio(struct rt_rq *rt_rq) -{ - return sysctl_sched_rt_ratio; -} - -#define for_each_leaf_rt_rq(rt_rq, rq) \ - for (rt_rq = &rq->rt; rt_rq; rt_rq = NULL) - -static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq) -{ - return container_of(rt_rq, struct rq, rt); -} - -static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) -{ - struct task_struct *p = rt_task_of(rt_se); - struct rq *rq = task_rq(p); - - return &rq->rt; -} - -#define for_each_sched_rt_entity(rt_se) \ - for (; rt_se; rt_se = NULL) - -static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) -{ - return NULL; -} - -static inline void sched_rt_ratio_enqueue(struct rt_rq *rt_rq) -{ -} - -static inline void sched_rt_ratio_dequeue(struct rt_rq *rt_rq) -{ -} - -#endif - -static inline int rt_se_prio(struct sched_rt_entity *rt_se) -{ -#ifdef CONFIG_FAIR_GROUP_SCHED - struct rt_rq *rt_rq = group_rt_rq(rt_se); - - if (rt_rq) - return rt_rq->highest_prio; -#endif - - return rt_task_of(rt_se)->prio; -} - -static int sched_rt_ratio_exceeded(struct rt_rq *rt_rq) -{ - unsigned int rt_ratio = sched_rt_ratio(rt_rq); - u64 period, ratio; - - if (rt_ratio == SCHED_RT_FRAC) - return 0; - - if (rt_rq->rt_throttled) - return 1; - - period = (u64)sysctl_sched_rt_period * NSEC_PER_MSEC; - ratio = (period * rt_ratio) >> SCHED_RT_FRAC_SHIFT; - - if (rt_rq->rt_time > ratio) { - struct rq *rq = rq_of_rt_rq(rt_rq); - - rq->rt_throttled = 1; - rt_rq->rt_throttled = 1; - - sched_rt_ratio_dequeue(rt_rq); - return 1; - } - - return 0; -} - -static void update_sched_rt_period(struct rq *rq) -{ - struct rt_rq *rt_rq; - u64 period; - - while (rq->clock > rq->rt_period_expire) { - period = (u64)sysctl_sched_rt_period * NSEC_PER_MSEC; - rq->rt_period_expire += period; - - for_each_leaf_rt_rq(rt_rq, rq) { - unsigned long rt_ratio = sched_rt_ratio(rt_rq); - u64 ratio = (period * rt_ratio) >> SCHED_RT_FRAC_SHIFT; - - rt_rq->rt_time -= min(rt_rq->rt_time, ratio); - if (rt_rq->rt_throttled) { - rt_rq->rt_throttled = 0; - sched_rt_ratio_enqueue(rt_rq); - } - } - - rq->rt_throttled = 0; - } -} - /* * Update the current task's runtime statistics. Skip current tasks that * are not in our scheduling class. @@ -221,8 +10,6 @@ static void update_sched_rt_period(struct rq *rq) static void update_curr_rt(struct rq *rq) { struct task_struct *curr = rq->curr; - struct sched_rt_entity *rt_se = &curr->rt; - struct rt_rq *rt_rq = rt_rq_of_se(rt_se); u64 delta_exec; if (!task_has_rt_policy(curr)) @@ -237,228 +24,47 @@ static void update_curr_rt(struct rq *rq) curr->se.sum_exec_runtime += delta_exec; curr->se.exec_start = rq->clock; cpuacct_charge(curr, delta_exec); - - rt_rq->rt_time += delta_exec; - /* - * might make it a tad more accurate: - * - * update_sched_rt_period(rq); - */ - if (sched_rt_ratio_exceeded(rt_rq)) - resched_task(curr); -} - -static inline -void inc_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - WARN_ON(!rt_prio(rt_se_prio(rt_se))); - rt_rq->rt_nr_running++; -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED - if (rt_se_prio(rt_se) < rt_rq->highest_prio) - rt_rq->highest_prio = rt_se_prio(rt_se); -#endif -#ifdef CONFIG_SMP - if (rt_se->nr_cpus_allowed > 1) { - struct rq *rq = rq_of_rt_rq(rt_rq); - rq->rt.rt_nr_migratory++; - } - - update_rt_migration(rq_of_rt_rq(rt_rq)); -#endif } -static inline -void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - WARN_ON(!rt_prio(rt_se_prio(rt_se))); - WARN_ON(!rt_rq->rt_nr_running); - rt_rq->rt_nr_running--; -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED - if (rt_rq->rt_nr_running) { - struct rt_prio_array *array; - - WARN_ON(rt_se_prio(rt_se) < rt_rq->highest_prio); - if (rt_se_prio(rt_se) == rt_rq->highest_prio) { - /* recalculate */ - array = &rt_rq->active; - rt_rq->highest_prio = - sched_find_first_bit(array->bitmap); - } /* otherwise leave rq->highest prio alone */ - } else - rt_rq->highest_prio = MAX_RT_PRIO; -#endif -#ifdef CONFIG_SMP - if (rt_se->nr_cpus_allowed > 1) { - struct rq *rq = rq_of_rt_rq(rt_rq); - rq->rt.rt_nr_migratory--; - } - - update_rt_migration(rq_of_rt_rq(rt_rq)); -#endif /* CONFIG_SMP */ -} - -static void enqueue_rt_entity(struct sched_rt_entity *rt_se) -{ - struct rt_rq *rt_rq = rt_rq_of_se(rt_se); - struct rt_prio_array *array = &rt_rq->active; - struct rt_rq *group_rq = group_rt_rq(rt_se); - - if (group_rq && group_rq->rt_throttled) - return; - - list_add_tail(&rt_se->run_list, array->queue + rt_se_prio(rt_se)); - __set_bit(rt_se_prio(rt_se), array->bitmap); - - inc_rt_tasks(rt_se, rt_rq); -} - -static void dequeue_rt_entity(struct sched_rt_entity *rt_se) -{ - struct rt_rq *rt_rq = rt_rq_of_se(rt_se); - struct rt_prio_array *array = &rt_rq->active; - - list_del_init(&rt_se->run_list); - if (list_empty(array->queue + rt_se_prio(rt_se))) - __clear_bit(rt_se_prio(rt_se), array->bitmap); - - dec_rt_tasks(rt_se, rt_rq); -} - -/* - * Because the prio of an upper entry depends on the lower - * entries, we must remove entries top - down. - * - * XXX: O(1/2 h^2) because we can only walk up, not down the chain. - * doesn't matter much for now, as h=2 for GROUP_SCHED. - */ -static void dequeue_rt_stack(struct task_struct *p) +static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup) { - struct sched_rt_entity *rt_se, *top_se; + struct rt_prio_array *array = &rq->rt.active; - /* - * dequeue all, top - down. - */ - do { - rt_se = &p->rt; - top_se = NULL; - for_each_sched_rt_entity(rt_se) { - if (on_rt_rq(rt_se)) - top_se = rt_se; - } - if (top_se) - dequeue_rt_entity(top_se); - } while (top_se); + list_add_tail(&p->run_list, array->queue + p->prio); + __set_bit(p->prio, array->bitmap); } /* * Adding/removing a task to/from a priority array: */ -static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int wakeup) -{ - struct sched_rt_entity *rt_se = &p->rt; - - if (wakeup) - rt_se->timeout = 0; - - dequeue_rt_stack(p); - - /* - * enqueue everybody, bottom - up. - */ - for_each_sched_rt_entity(rt_se) - enqueue_rt_entity(rt_se); - - inc_cpu_load(rq, p->se.load.weight); -} - static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int sleep) { - struct sched_rt_entity *rt_se = &p->rt; - struct rt_rq *rt_rq; + struct rt_prio_array *array = &rq->rt.active; update_curr_rt(rq); - dequeue_rt_stack(p); - - /* - * re-enqueue all non-empty rt_rq entities. - */ - for_each_sched_rt_entity(rt_se) { - rt_rq = group_rt_rq(rt_se); - if (rt_rq && rt_rq->rt_nr_running) - enqueue_rt_entity(rt_se); - } - - dec_cpu_load(rq, p->se.load.weight); + list_del(&p->run_list); + if (list_empty(array->queue + p->prio)) + __clear_bit(p->prio, array->bitmap); } /* * Put task to the end of the run list without the overhead of dequeue * followed by enqueue. */ -static -void requeue_rt_entity(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se) -{ - struct rt_prio_array *array = &rt_rq->active; - - list_move_tail(&rt_se->run_list, array->queue + rt_se_prio(rt_se)); -} - static void requeue_task_rt(struct rq *rq, struct task_struct *p) { - struct sched_rt_entity *rt_se = &p->rt; - struct rt_rq *rt_rq; + struct rt_prio_array *array = &rq->rt.active; - for_each_sched_rt_entity(rt_se) { - rt_rq = rt_rq_of_se(rt_se); - requeue_rt_entity(rt_rq, rt_se); - } + list_move_tail(&p->run_list, array->queue + p->prio); } -static void yield_task_rt(struct rq *rq) +static void +yield_task_rt(struct rq *rq) { requeue_task_rt(rq, rq->curr); } -#ifdef CONFIG_SMP -static int find_lowest_rq(struct task_struct *task); - -static int select_task_rq_rt(struct task_struct *p, int sync) -{ - struct rq *rq = task_rq(p); - - /* - * If the current task is an RT task, then - * try to see if we can wake this RT task up on another - * runqueue. Otherwise simply start this RT task - * on its current runqueue. - * - * We want to avoid overloading runqueues. Even if - * the RT task is of higher priority than the current RT task. - * RT tasks behave differently than other tasks. If - * one gets preempted, we try to push it off to another queue. - * So trying to keep a preempting RT task on the same - * cache hot CPU will force the running RT task to - * a cold CPU. So we waste all the cache for the lower - * RT task in hopes of saving some of a RT task - * that is just being woken and probably will have - * cold cache anyway. - */ - if (unlikely(rt_task(rq->curr)) && - (p->rt.nr_cpus_allowed > 1)) { - int cpu = find_lowest_rq(p); - - return (cpu == -1) ? task_cpu(p) : cpu; - } - - /* - * Otherwise, just let it ride on the affined RQ and the - * post-schedule router will push the preempted task away - */ - return task_cpu(p); -} -#endif /* CONFIG_SMP */ - /* * Preempt the current task with a newly woken task if needed: */ @@ -468,46 +74,23 @@ static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p) resched_task(rq->curr); } -static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq, - struct rt_rq *rt_rq) +static struct task_struct *pick_next_task_rt(struct rq *rq) { - struct rt_prio_array *array = &rt_rq->active; - struct sched_rt_entity *next = NULL; + struct rt_prio_array *array = &rq->rt.active; + struct task_struct *next; struct list_head *queue; int idx; idx = sched_find_first_bit(array->bitmap); - BUG_ON(idx >= MAX_RT_PRIO); - - queue = array->queue + idx; - next = list_entry(queue->next, struct sched_rt_entity, run_list); - - return next; -} - -static struct task_struct *pick_next_task_rt(struct rq *rq) -{ - struct sched_rt_entity *rt_se; - struct task_struct *p; - struct rt_rq *rt_rq; - - rt_rq = &rq->rt; - - if (unlikely(!rt_rq->rt_nr_running)) + if (idx >= MAX_RT_PRIO) return NULL; - if (sched_rt_ratio_exceeded(rt_rq)) - return NULL; + queue = array->queue + idx; + next = list_entry(queue->next, struct task_struct, run_list); - do { - rt_se = pick_next_rt_entity(rq, rt_rq); - BUG_ON(!rt_se); - rt_rq = group_rt_rq(rt_se); - } while (rt_rq); + next->se.exec_start = rq->clock; - p = rt_task_of(rt_se); - p->se.exec_start = rq->clock; - return p; + return next; } static void put_prev_task_rt(struct rq *rq, struct task_struct *p) @@ -517,448 +100,76 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p) } #ifdef CONFIG_SMP - -/* Only try algorithms three times */ -#define RT_MAX_TRIES 3 - -static int double_lock_balance(struct rq *this_rq, struct rq *busiest); -static void deactivate_task(struct rq *rq, struct task_struct *p, int sleep); - -static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) -{ - if (!task_running(rq, p) && - (cpu < 0 || cpu_isset(cpu, p->cpus_allowed)) && - (p->rt.nr_cpus_allowed > 1)) - return 1; - return 0; -} - -/* Return the second highest RT task, NULL otherwise */ -static struct task_struct *pick_next_highest_task_rt(struct rq *rq, int cpu) +/* + * Load-balancing iterator. Note: while the runqueue stays locked + * during the whole iteration, the current task might be + * dequeued so the iterator has to be dequeue-safe. Here we + * achieve that by always pre-iterating before returning + * the current task: + */ +static struct task_struct *load_balance_start_rt(void *arg) { - struct task_struct *next = NULL; - struct sched_rt_entity *rt_se; - struct rt_prio_array *array; - struct rt_rq *rt_rq; + struct rq *rq = arg; + struct rt_prio_array *array = &rq->rt.active; + struct list_head *head, *curr; + struct task_struct *p; int idx; - for_each_leaf_rt_rq(rt_rq, rq) { - array = &rt_rq->active; - idx = sched_find_first_bit(array->bitmap); - next_idx: - if (idx >= MAX_RT_PRIO) - continue; - if (next && next->prio < idx) - continue; - list_for_each_entry(rt_se, array->queue + idx, run_list) { - struct task_struct *p = rt_task_of(rt_se); - if (pick_rt_task(rq, p, cpu)) { - next = p; - break; - } - } - if (!next) { - idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1); - goto next_idx; - } - } - - return next; -} - -static DEFINE_PER_CPU(cpumask_t, local_cpu_mask); - -static int find_lowest_cpus(struct task_struct *task, cpumask_t *lowest_mask) -{ - int lowest_prio = -1; - int lowest_cpu = -1; - int count = 0; - int cpu; - - cpus_and(*lowest_mask, task_rq(task)->rd->online, task->cpus_allowed); - - /* - * Scan each rq for the lowest prio. - */ - for_each_cpu_mask(cpu, *lowest_mask) { - struct rq *rq = cpu_rq(cpu); - - /* We look for lowest RT prio or non-rt CPU */ - if (rq->rt.highest_prio >= MAX_RT_PRIO) { - /* - * if we already found a low RT queue - * and now we found this non-rt queue - * clear the mask and set our bit. - * Otherwise just return the queue as is - * and the count==1 will cause the algorithm - * to use the first bit found. - */ - if (lowest_cpu != -1) { - cpus_clear(*lowest_mask); - cpu_set(rq->cpu, *lowest_mask); - } - return 1; - } - - /* no locking for now */ - if ((rq->rt.highest_prio > task->prio) - && (rq->rt.highest_prio >= lowest_prio)) { - if (rq->rt.highest_prio > lowest_prio) { - /* new low - clear old data */ - lowest_prio = rq->rt.highest_prio; - lowest_cpu = cpu; - count = 0; - } - count++; - } else - cpu_clear(cpu, *lowest_mask); - } - - /* - * Clear out all the set bits that represent - * runqueues that were of higher prio than - * the lowest_prio. - */ - if (lowest_cpu > 0) { - /* - * Perhaps we could add another cpumask op to - * zero out bits. Like cpu_zero_bits(cpumask, nrbits); - * Then that could be optimized to use memset and such. - */ - for_each_cpu_mask(cpu, *lowest_mask) { - if (cpu >= lowest_cpu) - break; - cpu_clear(cpu, *lowest_mask); - } - } - - return count; -} - -static inline int pick_optimal_cpu(int this_cpu, cpumask_t *mask) -{ - int first; - - /* "this_cpu" is cheaper to preempt than a remote processor */ - if ((this_cpu != -1) && cpu_isset(this_cpu, *mask)) - return this_cpu; - - first = first_cpu(*mask); - if (first != NR_CPUS) - return first; - - return -1; -} - -static int find_lowest_rq(struct task_struct *task) -{ - struct sched_domain *sd; - cpumask_t *lowest_mask = &__get_cpu_var(local_cpu_mask); - int this_cpu = smp_processor_id(); - int cpu = task_cpu(task); - int count = find_lowest_cpus(task, lowest_mask); - - if (!count) - return -1; /* No targets found */ - - /* - * There is no sense in performing an optimal search if only one - * target is found. - */ - if (count == 1) - return first_cpu(*lowest_mask); - - /* - * At this point we have built a mask of cpus representing the - * lowest priority tasks in the system. Now we want to elect - * the best one based on our affinity and topology. - * - * We prioritize the last cpu that the task executed on since - * it is most likely cache-hot in that location. - */ - if (cpu_isset(cpu, *lowest_mask)) - return cpu; - - /* - * Otherwise, we consult the sched_domains span maps to figure - * out which cpu is logically closest to our hot cache data. - */ - if (this_cpu == cpu) - this_cpu = -1; /* Skip this_cpu opt if the same */ - - for_each_domain(cpu, sd) { - if (sd->flags & SD_WAKE_AFFINE) { - cpumask_t domain_mask; - int best_cpu; - - cpus_and(domain_mask, sd->span, *lowest_mask); - - best_cpu = pick_optimal_cpu(this_cpu, - &domain_mask); - if (best_cpu != -1) - return best_cpu; - } - } - - /* - * And finally, if there were no matches within the domains - * just give the caller *something* to work with from the compatible - * locations. - */ - return pick_optimal_cpu(this_cpu, lowest_mask); -} - -/* Will lock the rq it finds */ -static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) -{ - struct rq *lowest_rq = NULL; - int tries; - int cpu; - - for (tries = 0; tries < RT_MAX_TRIES; tries++) { - cpu = find_lowest_rq(task); - - if ((cpu == -1) || (cpu == rq->cpu)) - break; + idx = sched_find_first_bit(array->bitmap); + if (idx >= MAX_RT_PRIO) + return NULL; - lowest_rq = cpu_rq(cpu); + head = array->queue + idx; + curr = head->prev; - /* if the prio of this runqueue changed, try again */ - if (double_lock_balance(rq, lowest_rq)) { - /* - * We had to unlock the run queue. In - * the mean time, task could have - * migrated already or had its affinity changed. - * Also make sure that it wasn't scheduled on its rq. - */ - if (unlikely(task_rq(task) != rq || - !cpu_isset(lowest_rq->cpu, - task->cpus_allowed) || - task_running(rq, task) || - !task->se.on_rq)) { + p = list_entry(curr, struct task_struct, run_list); - spin_unlock(&lowest_rq->lock); - lowest_rq = NULL; - break; - } - } + curr = curr->prev; - /* If this rq is still suitable use it. */ - if (lowest_rq->rt.highest_prio > task->prio) - break; + rq->rt.rt_load_balance_idx = idx; + rq->rt.rt_load_balance_head = head; + rq->rt.rt_load_balance_curr = curr; - /* try again */ - spin_unlock(&lowest_rq->lock); - lowest_rq = NULL; - } - - return lowest_rq; + return p; } -/* - * If the current CPU has more than one RT task, see if the non - * running task can migrate over to a CPU that is running a task - * of lesser priority. - */ -static int push_rt_task(struct rq *rq) +static struct task_struct *load_balance_next_rt(void *arg) { - struct task_struct *next_task; - struct rq *lowest_rq; - int ret = 0; - int paranoid = RT_MAX_TRIES; - - if (!rq->rt.overloaded) - return 0; + struct rq *rq = arg; + struct rt_prio_array *array = &rq->rt.active; + struct list_head *head, *curr; + struct task_struct *p; + int idx; - next_task = pick_next_highest_task_rt(rq, -1); - if (!next_task) - return 0; - - retry: - if (unlikely(next_task == rq->curr)) { - WARN_ON(1); - return 0; - } + idx = rq->rt.rt_load_balance_idx; + head = rq->rt.rt_load_balance_head; + curr = rq->rt.rt_load_balance_curr; /* - * It's possible that the next_task slipped in of - * higher priority than current. If that's the case - * just reschedule current. + * If we arrived back to the head again then + * iterate to the next queue (if any): */ - if (unlikely(next_task->prio < rq->curr->prio)) { - resched_task(rq->curr); - return 0; - } - - /* We might release rq lock */ - get_task_struct(next_task); - - /* find_lock_lowest_rq locks the rq if found */ - lowest_rq = find_lock_lowest_rq(next_task, rq); - if (!lowest_rq) { - struct task_struct *task; - /* - * find lock_lowest_rq releases rq->lock - * so it is possible that next_task has changed. - * If it has, then try again. - */ - task = pick_next_highest_task_rt(rq, -1); - if (unlikely(task != next_task) && task && paranoid--) { - put_task_struct(next_task); - next_task = task; - goto retry; - } - goto out; - } - - deactivate_task(rq, next_task, 0); - set_task_cpu(next_task, lowest_rq->cpu); - activate_task(lowest_rq, next_task, 0); + if (unlikely(head == curr)) { + int next_idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx+1); - resched_task(lowest_rq->curr); + if (next_idx >= MAX_RT_PRIO) + return NULL; - spin_unlock(&lowest_rq->lock); + idx = next_idx; + head = array->queue + idx; + curr = head->prev; - ret = 1; -out: - put_task_struct(next_task); - - return ret; -} - -/* - * TODO: Currently we just use the second highest prio task on - * the queue, and stop when it can't migrate (or there's - * no more RT tasks). There may be a case where a lower - * priority RT task has a different affinity than the - * higher RT task. In this case the lower RT task could - * possibly be able to migrate where as the higher priority - * RT task could not. We currently ignore this issue. - * Enhancements are welcome! - */ -static void push_rt_tasks(struct rq *rq) -{ - /* push_rt_task will return true if it moved an RT */ - while (push_rt_task(rq)) - ; -} - -static int pull_rt_task(struct rq *this_rq) -{ - int this_cpu = this_rq->cpu, ret = 0, cpu; - struct task_struct *p, *next; - struct rq *src_rq; - - if (likely(!rt_overloaded(this_rq))) - return 0; - - next = pick_next_task_rt(this_rq); - - for_each_cpu_mask(cpu, this_rq->rd->rto_mask) { - if (this_cpu == cpu) - continue; - - src_rq = cpu_rq(cpu); - /* - * We can potentially drop this_rq's lock in - * double_lock_balance, and another CPU could - * steal our next task - hence we must cause - * the caller to recalculate the next task - * in that case: - */ - if (double_lock_balance(this_rq, src_rq)) { - struct task_struct *old_next = next; - - next = pick_next_task_rt(this_rq); - if (next != old_next) - ret = 1; - } - - /* - * Are there still pullable RT tasks? - */ - if (src_rq->rt.rt_nr_running <= 1) - goto skip; - - p = pick_next_highest_task_rt(src_rq, this_cpu); - - /* - * Do we have an RT task that preempts - * the to-be-scheduled task? - */ - if (p && (!next || (p->prio < next->prio))) { - WARN_ON(p == src_rq->curr); - WARN_ON(!p->se.on_rq); - - /* - * There's a chance that p is higher in priority - * than what's currently running on its cpu. - * This is just that p is wakeing up and hasn't - * had a chance to schedule. We only pull - * p if it is lower in priority than the - * current task on the run queue or - * this_rq next task is lower in prio than - * the current task on that rq. - */ - if (p->prio < src_rq->curr->prio || - (next && next->prio < src_rq->curr->prio)) - goto skip; - - ret = 1; - - deactivate_task(src_rq, p, 0); - set_task_cpu(p, this_cpu); - activate_task(this_rq, p, 0); - /* - * We continue with the search, just in - * case there's an even higher prio task - * in another runqueue. (low likelyhood - * but possible) - * - * Update next so that we won't pick a task - * on another cpu with a priority lower (or equal) - * than the one we just picked. - */ - next = p; - - } - skip: - spin_unlock(&src_rq->lock); + rq->rt.rt_load_balance_idx = idx; + rq->rt.rt_load_balance_head = head; } - return ret; -} - -static void pre_schedule_rt(struct rq *rq, struct task_struct *prev) -{ - /* Try to pull RT tasks here if we lower this rq's prio */ - if (unlikely(rt_task(prev)) && rq->rt.highest_prio > prev->prio) - pull_rt_task(rq); -} + p = list_entry(curr, struct task_struct, run_list); -static void post_schedule_rt(struct rq *rq) -{ - /* - * If we have more than one rt_task queued, then - * see if we can push the other rt_tasks off to other CPUS. - * Note we may release the rq lock, and since - * the lock was owned by prev, we need to release it - * first via finish_lock_switch and then reaquire it here. - */ - if (unlikely(rq->rt.overloaded)) { - spin_lock_irq(&rq->lock); - push_rt_tasks(rq); - spin_unlock_irq(&rq->lock); - } -} + curr = curr->prev; + rq->rt.rt_load_balance_curr = curr; -static void task_wake_up_rt(struct rq *rq, struct task_struct *p) -{ - if (!task_running(rq, p) && - (p->prio >= rq->rt.highest_prio) && - rq->rt.overloaded) - push_rt_tasks(rq); + return p; } static unsigned long @@ -967,170 +178,38 @@ load_balance_rt(struct rq *this_rq, int this_cpu, struct rq *busiest, struct sched_domain *sd, enum cpu_idle_type idle, int *all_pinned, int *this_best_prio) { - /* don't touch RT tasks */ - return 0; -} - -static int -move_one_task_rt(struct rq *this_rq, int this_cpu, struct rq *busiest, - struct sched_domain *sd, enum cpu_idle_type idle) -{ - /* don't touch RT tasks */ - return 0; -} + struct rq_iterator rt_rq_iterator; -static void set_cpus_allowed_rt(struct task_struct *p, cpumask_t *new_mask) -{ - int weight = cpus_weight(*new_mask); - - BUG_ON(!rt_task(p)); - - /* - * Update the migration status of the RQ if we have an RT task - * which is running AND changing its weight value. + rt_rq_iterator.start = load_balance_start_rt; + rt_rq_iterator.next = load_balance_next_rt; + /* pass 'busiest' rq argument into + * load_balance_[start|next]_rt iterators */ - if (p->se.on_rq && (weight != p->rt.nr_cpus_allowed)) { - struct rq *rq = task_rq(p); - - if ((p->rt.nr_cpus_allowed <= 1) && (weight > 1)) { - rq->rt.rt_nr_migratory++; - } else if ((p->rt.nr_cpus_allowed > 1) && (weight <= 1)) { - BUG_ON(!rq->rt.rt_nr_migratory); - rq->rt.rt_nr_migratory--; - } + rt_rq_iterator.arg = busiest; - update_rt_migration(rq); - } - - p->cpus_allowed = *new_mask; - p->rt.nr_cpus_allowed = weight; -} - -/* Assumes rq->lock is held */ -static void join_domain_rt(struct rq *rq) -{ - if (rq->rt.overloaded) - rt_set_overload(rq); -} - -/* Assumes rq->lock is held */ -static void leave_domain_rt(struct rq *rq) -{ - if (rq->rt.overloaded) - rt_clear_overload(rq); -} - -/* - * When switch from the rt queue, we bring ourselves to a position - * that we might want to pull RT tasks from other runqueues. - */ -static void switched_from_rt(struct rq *rq, struct task_struct *p, - int running) -{ - /* - * If there are other RT tasks then we will reschedule - * and the scheduling of the other RT tasks will handle - * the balancing. But if we are the last RT task - * we may need to handle the pulling of RT tasks - * now. - */ - if (!rq->rt.rt_nr_running) - pull_rt_task(rq); + return balance_tasks(this_rq, this_cpu, busiest, max_load_move, sd, + idle, all_pinned, this_best_prio, &rt_rq_iterator); } -#endif /* CONFIG_SMP */ -/* - * When switching a task to RT, we may overload the runqueue - * with RT tasks. In this case we try to push them off to - * other runqueues. - */ -static void switched_to_rt(struct rq *rq, struct task_struct *p, - int running) -{ - int check_resched = 1; - - /* - * If we are already running, then there's nothing - * that needs to be done. But if we are not running - * we may need to preempt the current running task. - * If that current running task is also an RT task - * then see if we can move to another run queue. - */ - if (!running) { -#ifdef CONFIG_SMP - if (rq->rt.overloaded && push_rt_task(rq) && - /* Don't resched if we changed runqueues */ - rq != task_rq(p)) - check_resched = 0; -#endif /* CONFIG_SMP */ - if (check_resched && p->prio < rq->curr->prio) - resched_task(rq->curr); - } -} - -/* - * Priority of the task has changed. This may cause - * us to initiate a push or pull. - */ -static void prio_changed_rt(struct rq *rq, struct task_struct *p, - int oldprio, int running) -{ - if (running) { -#ifdef CONFIG_SMP - /* - * If our priority decreases while running, we - * may need to pull tasks to this runqueue. - */ - if (oldprio < p->prio) - pull_rt_task(rq); - /* - * If there's a higher priority task waiting to run - * then reschedule. - */ - if (p->prio > rq->rt.highest_prio) - resched_task(p); -#else - /* For UP simply resched on drop of prio */ - if (oldprio < p->prio) - resched_task(p); -#endif /* CONFIG_SMP */ - } else { - /* - * This task is not running, but if it is - * greater than the current running task - * then reschedule. - */ - if (p->prio < rq->curr->prio) - resched_task(rq->curr); - } -} - -static void watchdog(struct rq *rq, struct task_struct *p) +static int +move_one_task_rt(struct rq *this_rq, int this_cpu, struct rq *busiest, + struct sched_domain *sd, enum cpu_idle_type idle) { - unsigned long soft, hard; - - if (!p->signal) - return; - - soft = p->signal->rlim[RLIMIT_RTTIME].rlim_cur; - hard = p->signal->rlim[RLIMIT_RTTIME].rlim_max; + struct rq_iterator rt_rq_iterator; - if (soft != RLIM_INFINITY) { - unsigned long next; + rt_rq_iterator.start = load_balance_start_rt; + rt_rq_iterator.next = load_balance_next_rt; + rt_rq_iterator.arg = busiest; - p->rt.timeout++; - next = DIV_ROUND_UP(min(soft, hard), USEC_PER_SEC/HZ); - if (p->rt.timeout > next) - p->it_sched_expires = p->se.sum_exec_runtime; - } + return iter_move_one_task(this_rq, this_cpu, busiest, sd, idle, + &rt_rq_iterator); } +#endif -static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) +static void task_tick_rt(struct rq *rq, struct task_struct *p) { update_curr_rt(rq); - watchdog(rq, p); - /* * RR tasks need a special form of timeslice management. * FIFO tasks have no timeslices. @@ -1138,16 +217,16 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) if (p->policy != SCHED_RR) return; - if (--p->rt.time_slice) + if (--p->time_slice) return; - p->rt.time_slice = DEF_TIMESLICE; + p->time_slice = DEF_TIMESLICE; /* * Requeue to the end of queue if we are not the only element * on the queue: */ - if (p->rt.run_list.prev != p->rt.run_list.next) { + if (p->run_list.prev != p->run_list.next) { requeue_task_rt(rq, p); set_tsk_need_resched(p); } @@ -1165,9 +244,6 @@ const struct sched_class rt_sched_class = { .enqueue_task = enqueue_task_rt, .dequeue_task = dequeue_task_rt, .yield_task = yield_task_rt, -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_rt, -#endif /* CONFIG_SMP */ .check_preempt_curr = check_preempt_curr_rt, @@ -1177,18 +253,8 @@ const struct sched_class rt_sched_class = { #ifdef CONFIG_SMP .load_balance = load_balance_rt, .move_one_task = move_one_task_rt, - .set_cpus_allowed = set_cpus_allowed_rt, - .join_domain = join_domain_rt, - .leave_domain = leave_domain_rt, - .pre_schedule = pre_schedule_rt, - .post_schedule = post_schedule_rt, - .task_wake_up = task_wake_up_rt, - .switched_from = switched_from_rt, #endif .set_curr_task = set_curr_task_rt, .task_tick = task_tick_rt, - - .prio_changed = prio_changed_rt, - .switched_to = switched_to_rt, }; diff --git a/trunk/kernel/softlockup.c b/trunk/kernel/softlockup.c index c1d76552446e..11df812263c8 100644 --- a/trunk/kernel/softlockup.c +++ b/trunk/kernel/softlockup.c @@ -8,7 +8,6 @@ */ #include #include -#include #include #include #include @@ -24,8 +23,8 @@ static DEFINE_PER_CPU(unsigned long, touch_timestamp); static DEFINE_PER_CPU(unsigned long, print_timestamp); static DEFINE_PER_CPU(struct task_struct *, watchdog_task); -static int __read_mostly did_panic; -unsigned long __read_mostly softlockup_thresh = 60; +static int did_panic; +int softlockup_thresh = 10; static int softlock_panic(struct notifier_block *this, unsigned long event, void *ptr) @@ -46,7 +45,7 @@ static struct notifier_block panic_block = { */ static unsigned long get_timestamp(int this_cpu) { - return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */ + return cpu_clock(this_cpu) >> 30; /* 2^30 ~= 10^9 */ } void touch_softlockup_watchdog(void) @@ -101,7 +100,11 @@ void softlockup_tick(void) now = get_timestamp(this_cpu); - /* Warn about unreasonable delays: */ + /* Wake up the high-prio watchdog task every second: */ + if (now > (touch_timestamp + 1)) + wake_up_process(per_cpu(watchdog_task, this_cpu)); + + /* Warn about unreasonable 10+ seconds delays: */ if (now <= (touch_timestamp + softlockup_thresh)) return; @@ -118,94 +121,12 @@ void softlockup_tick(void) spin_unlock(&print_lock); } -/* - * Have a reasonable limit on the number of tasks checked: - */ -unsigned long __read_mostly sysctl_hung_task_check_count = 1024; - -/* - * Zero means infinite timeout - no checking done: - */ -unsigned long __read_mostly sysctl_hung_task_timeout_secs = 120; - -unsigned long __read_mostly sysctl_hung_task_warnings = 10; - -/* - * Only do the hung-tasks check on one CPU: - */ -static int check_cpu __read_mostly = -1; - -static void check_hung_task(struct task_struct *t, unsigned long now) -{ - unsigned long switch_count = t->nvcsw + t->nivcsw; - - if (t->flags & PF_FROZEN) - return; - - if (switch_count != t->last_switch_count || !t->last_switch_timestamp) { - t->last_switch_count = switch_count; - t->last_switch_timestamp = now; - return; - } - if ((long)(now - t->last_switch_timestamp) < - sysctl_hung_task_timeout_secs) - return; - if (sysctl_hung_task_warnings < 0) - return; - sysctl_hung_task_warnings--; - - /* - * Ok, the task did not get scheduled for more than 2 minutes, - * complain: - */ - printk(KERN_ERR "INFO: task %s:%d blocked for more than " - "%ld seconds.\n", t->comm, t->pid, - sysctl_hung_task_timeout_secs); - printk(KERN_ERR "\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\"" - " disables this message.\n"); - sched_show_task(t); - __debug_show_held_locks(t); - - t->last_switch_timestamp = now; - touch_nmi_watchdog(); -} - -/* - * Check whether a TASK_UNINTERRUPTIBLE does not get woken up for - * a really long time (120 seconds). If that happens, print out - * a warning. - */ -static void check_hung_uninterruptible_tasks(int this_cpu) -{ - int max_count = sysctl_hung_task_check_count; - unsigned long now = get_timestamp(this_cpu); - struct task_struct *g, *t; - - /* - * If the system crashed already then all bets are off, - * do not report extra hung tasks: - */ - if ((tainted & TAINT_DIE) || did_panic) - return; - - read_lock(&tasklist_lock); - do_each_thread(g, t) { - if (!--max_count) - break; - if (t->state & TASK_UNINTERRUPTIBLE) - check_hung_task(t, now); - } while_each_thread(g, t); - - read_unlock(&tasklist_lock); -} - /* * The watchdog thread - runs every second and touches the timestamp. */ static int watchdog(void *__bind_cpu) { struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; - int this_cpu = (long)__bind_cpu; sched_setscheduler(current, SCHED_FIFO, ¶m); @@ -214,18 +135,13 @@ static int watchdog(void *__bind_cpu) /* * Run briefly once per second to reset the softlockup timestamp. - * If this gets delayed for more than 60 seconds then the + * If this gets delayed for more than 10 seconds then the * debug-printout triggers in softlockup_tick(). */ while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); touch_softlockup_watchdog(); - msleep_interruptible(10000); - - if (this_cpu != check_cpu) - continue; - - if (sysctl_hung_task_timeout_secs) - check_hung_uninterruptible_tasks(this_cpu); + schedule(); } return 0; @@ -255,7 +171,6 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) break; case CPU_ONLINE: case CPU_ONLINE_FROZEN: - check_cpu = any_online_cpu(cpu_online_map); wake_up_process(per_cpu(watchdog_task, hotcpu)); break; #ifdef CONFIG_HOTPLUG_CPU @@ -266,15 +181,6 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) /* Unbind so it can run. Fall thru. */ kthread_bind(per_cpu(watchdog_task, hotcpu), any_online_cpu(cpu_online_map)); - case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: - if (hotcpu == check_cpu) { - cpumask_t temp_cpu_online_map = cpu_online_map; - - cpu_clear(hotcpu, temp_cpu_online_map); - check_cpu = any_online_cpu(temp_cpu_online_map); - } - break; case CPU_DEAD: case CPU_DEAD_FROZEN: p = per_cpu(watchdog_task, hotcpu); diff --git a/trunk/kernel/stop_machine.c b/trunk/kernel/stop_machine.c index 51b5ee53571a..319821ef78af 100644 --- a/trunk/kernel/stop_machine.c +++ b/trunk/kernel/stop_machine.c @@ -203,13 +203,13 @@ int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) int ret; /* No CPUs can come up or down during this. */ - get_online_cpus(); + lock_cpu_hotplug(); p = __stop_machine_run(fn, data, cpu); if (!IS_ERR(p)) ret = kthread_stop(p); else ret = PTR_ERR(p); - put_online_cpus(); + unlock_cpu_hotplug(); return ret; } diff --git a/trunk/kernel/sysctl.c b/trunk/kernel/sysctl.c index 8e96558cb8f3..c68f68dcc605 100644 --- a/trunk/kernel/sysctl.c +++ b/trunk/kernel/sysctl.c @@ -81,7 +81,6 @@ extern int compat_log; extern int maps_protect; extern int sysctl_stat_interval; extern int audit_argv_kb; -extern int latencytop_enabled; /* Constants used for minimum and maximum */ #ifdef CONFIG_DETECT_SOFTLOCKUP @@ -307,43 +306,9 @@ static struct ctl_table kern_table[] = { .procname = "sched_nr_migrate", .data = &sysctl_sched_nr_migrate, .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "sched_rt_period_ms", - .data = &sysctl_sched_rt_period, - .maxlen = sizeof(unsigned int), - .mode = 0644, + .mode = 644, .proc_handler = &proc_dointvec, }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "sched_rt_ratio", - .data = &sysctl_sched_rt_ratio, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, -#if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP) - { - .ctl_name = CTL_UNNUMBERED, - .procname = "sched_min_bal_int_shares", - .data = &sysctl_sched_min_bal_int_shares, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "sched_max_bal_int_shares", - .data = &sysctl_sched_max_bal_int_shares, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, -#endif #endif { .ctl_name = CTL_UNNUMBERED, @@ -417,15 +382,6 @@ static struct ctl_table kern_table[] = { .proc_handler = &proc_dointvec_taint, }, #endif -#ifdef CONFIG_LATENCYTOP - { - .procname = "latencytop", - .data = &latencytop_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, -#endif #ifdef CONFIG_SECURITY_CAPABILITIES { .procname = "cap-bound", @@ -772,40 +728,13 @@ static struct ctl_table kern_table[] = { .ctl_name = CTL_UNNUMBERED, .procname = "softlockup_thresh", .data = &softlockup_thresh, - .maxlen = sizeof(unsigned long), + .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_doulongvec_minmax, + .proc_handler = &proc_dointvec_minmax, .strategy = &sysctl_intvec, .extra1 = &one, .extra2 = &sixty, }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "hung_task_check_count", - .data = &sysctl_hung_task_check_count, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = &proc_doulongvec_minmax, - .strategy = &sysctl_intvec, - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "hung_task_timeout_secs", - .data = &sysctl_hung_task_timeout_secs, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = &proc_doulongvec_minmax, - .strategy = &sysctl_intvec, - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "hung_task_warnings", - .data = &sysctl_hung_task_warnings, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = &proc_doulongvec_minmax, - .strategy = &sysctl_intvec, - }, #endif #ifdef CONFIG_COMPAT { diff --git a/trunk/kernel/time/tick-sched.c b/trunk/kernel/time/tick-sched.c index 1a21b6fdb674..cb89fa8db110 100644 --- a/trunk/kernel/time/tick-sched.c +++ b/trunk/kernel/time/tick-sched.c @@ -153,7 +153,6 @@ void tick_nohz_update_jiffies(void) void tick_nohz_stop_sched_tick(void) { unsigned long seq, last_jiffies, next_jiffies, delta_jiffies, flags; - unsigned long rt_jiffies; struct tick_sched *ts; ktime_t last_update, expires, now, delta; struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev; @@ -217,10 +216,6 @@ void tick_nohz_stop_sched_tick(void) next_jiffies = get_next_timer_interrupt(last_jiffies); delta_jiffies = next_jiffies - last_jiffies; - rt_jiffies = rt_needs_cpu(cpu); - if (rt_jiffies && rt_jiffies < delta_jiffies) - delta_jiffies = rt_jiffies; - if (rcu_needs_cpu(cpu)) delta_jiffies = 1; /* @@ -514,6 +509,7 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) { struct tick_sched *ts = container_of(timer, struct tick_sched, sched_timer); + struct hrtimer_cpu_base *base = timer->base->cpu_base; struct pt_regs *regs = get_irq_regs(); ktime_t now = ktime_get(); int cpu = smp_processor_id(); @@ -551,8 +547,15 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) touch_softlockup_watchdog(); ts->idle_jiffies++; } + /* + * update_process_times() might take tasklist_lock, hence + * drop the base lock. sched-tick hrtimers are per-CPU and + * never accessible by userspace APIs, so this is safe to do. + */ + spin_unlock(&base->lock); update_process_times(user_mode(regs)); profile_tick(CPU_PROFILING); + spin_lock(&base->lock); } /* Do not restart, when we are in the idle loop */ diff --git a/trunk/kernel/timer.c b/trunk/kernel/timer.c index f739dfb539ce..2a00c22203f3 100644 --- a/trunk/kernel/timer.c +++ b/trunk/kernel/timer.c @@ -896,7 +896,7 @@ static void run_timer_softirq(struct softirq_action *h) { tvec_base_t *base = __get_cpu_var(tvec_bases); - hrtimer_run_pending(); + hrtimer_run_queues(); if (time_after_eq(jiffies, base->timer_jiffies)) __run_timers(base); @@ -907,7 +907,6 @@ static void run_timer_softirq(struct softirq_action *h) */ void run_local_timers(void) { - hrtimer_run_queues(); raise_softirq(TIMER_SOFTIRQ); softlockup_tick(); } diff --git a/trunk/kernel/user.c b/trunk/kernel/user.c index bc1c48d35cb3..ab4fd706993b 100644 --- a/trunk/kernel/user.c +++ b/trunk/kernel/user.c @@ -319,7 +319,7 @@ void free_uid(struct user_struct *up) struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) { struct hlist_head *hashent = uidhashentry(ns, uid); - struct user_struct *up, *new; + struct user_struct *up; /* Make uid_hash_find() + uids_user_create() + uid_hash_insert() * atomic. @@ -331,9 +331,13 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) spin_unlock_irq(&uidhash_lock); if (!up) { + struct user_struct *new; + new = kmem_cache_alloc(uid_cachep, GFP_KERNEL); - if (!new) - goto out_unlock; + if (!new) { + uids_mutex_unlock(); + return NULL; + } new->uid = uid; atomic_set(&new->__count, 1); @@ -349,14 +353,28 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) #endif new->locked_shm = 0; - if (alloc_uid_keyring(new, current) < 0) - goto out_free_user; + if (alloc_uid_keyring(new, current) < 0) { + kmem_cache_free(uid_cachep, new); + uids_mutex_unlock(); + return NULL; + } - if (sched_create_user(new) < 0) - goto out_put_keys; + if (sched_create_user(new) < 0) { + key_put(new->uid_keyring); + key_put(new->session_keyring); + kmem_cache_free(uid_cachep, new); + uids_mutex_unlock(); + return NULL; + } - if (uids_user_create(new)) - goto out_destoy_sched; + if (uids_user_create(new)) { + sched_destroy_user(new); + key_put(new->uid_keyring); + key_put(new->session_keyring); + kmem_cache_free(uid_cachep, new); + uids_mutex_unlock(); + return NULL; + } /* * Before adding this, check whether we raced @@ -384,17 +402,6 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) uids_mutex_unlock(); return up; - -out_destoy_sched: - sched_destroy_user(new); -out_put_keys: - key_put(new->uid_keyring); - key_put(new->session_keyring); -out_free_user: - kmem_cache_free(uid_cachep, new); -out_unlock: - uids_mutex_unlock(); - return NULL; } void switch_uid(struct user_struct *new_user) diff --git a/trunk/kernel/workqueue.c b/trunk/kernel/workqueue.c index 52db48e7f6e7..8db0b597509e 100644 --- a/trunk/kernel/workqueue.c +++ b/trunk/kernel/workqueue.c @@ -67,8 +67,9 @@ struct workqueue_struct { #endif }; -/* Serializes the accesses to the list of workqueues. */ -static DEFINE_SPINLOCK(workqueue_lock); +/* All the per-cpu workqueues on the system, for hotplug cpu to add/remove + threads to each one as cpus come/go. */ +static DEFINE_MUTEX(workqueue_mutex); static LIST_HEAD(workqueues); static int singlethread_cpu __read_mostly; @@ -591,6 +592,8 @@ EXPORT_SYMBOL(schedule_delayed_work_on); * Returns zero on success. * Returns -ve errno on failure. * + * Appears to be racy against CPU hotplug. + * * schedule_on_each_cpu() is very slow. */ int schedule_on_each_cpu(work_func_t func) @@ -602,7 +605,7 @@ int schedule_on_each_cpu(work_func_t func) if (!works) return -ENOMEM; - get_online_cpus(); + preempt_disable(); /* CPU hotplug */ for_each_online_cpu(cpu) { struct work_struct *work = per_cpu_ptr(works, cpu); @@ -610,8 +613,8 @@ int schedule_on_each_cpu(work_func_t func) set_bit(WORK_STRUCT_PENDING, work_data_bits(work)); __queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), work); } + preempt_enable(); flush_workqueue(keventd_wq); - put_online_cpus(); free_percpu(works); return 0; } @@ -747,10 +750,8 @@ struct workqueue_struct *__create_workqueue_key(const char *name, err = create_workqueue_thread(cwq, singlethread_cpu); start_workqueue_thread(cwq, -1); } else { - get_online_cpus(); - spin_lock(&workqueue_lock); + mutex_lock(&workqueue_mutex); list_add(&wq->list, &workqueues); - spin_unlock(&workqueue_lock); for_each_possible_cpu(cpu) { cwq = init_cpu_workqueue(wq, cpu); @@ -759,7 +760,7 @@ struct workqueue_struct *__create_workqueue_key(const char *name, err = create_workqueue_thread(cwq, cpu); start_workqueue_thread(cwq, cpu); } - put_online_cpus(); + mutex_unlock(&workqueue_mutex); } if (err) { @@ -774,7 +775,7 @@ static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) { /* * Our caller is either destroy_workqueue() or CPU_DEAD, - * get_online_cpus() protects cwq->thread. + * workqueue_mutex protects cwq->thread */ if (cwq->thread == NULL) return; @@ -809,11 +810,9 @@ void destroy_workqueue(struct workqueue_struct *wq) struct cpu_workqueue_struct *cwq; int cpu; - get_online_cpus(); - spin_lock(&workqueue_lock); + mutex_lock(&workqueue_mutex); list_del(&wq->list); - spin_unlock(&workqueue_lock); - put_online_cpus(); + mutex_unlock(&workqueue_mutex); for_each_cpu_mask(cpu, *cpu_map) { cwq = per_cpu_ptr(wq->cpu_wq, cpu); @@ -836,6 +835,13 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb, action &= ~CPU_TASKS_FROZEN; switch (action) { + case CPU_LOCK_ACQUIRE: + mutex_lock(&workqueue_mutex); + return NOTIFY_OK; + + case CPU_LOCK_RELEASE: + mutex_unlock(&workqueue_mutex); + return NOTIFY_OK; case CPU_UP_PREPARE: cpu_set(cpu, cpu_populated_map); @@ -848,8 +854,7 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb, case CPU_UP_PREPARE: if (!create_workqueue_thread(cwq, cpu)) break; - printk(KERN_ERR "workqueue [%s] for %i failed\n", - wq->name, cpu); + printk(KERN_ERR "workqueue for %i failed\n", cpu); return NOTIFY_BAD; case CPU_ONLINE: diff --git a/trunk/lib/Kconfig.debug b/trunk/lib/Kconfig.debug index 14fb355e3caa..a60109307d32 100644 --- a/trunk/lib/Kconfig.debug +++ b/trunk/lib/Kconfig.debug @@ -517,18 +517,4 @@ config FAULT_INJECTION_STACKTRACE_FILTER help Provide stacktrace filter for fault-injection capabilities -config LATENCYTOP - bool "Latency measuring infrastructure" - select FRAME_POINTER if !MIPS - select KALLSYMS - select KALLSYMS_ALL - select STACKTRACE - select SCHEDSTATS - select SCHED_DEBUG - depends on X86 || X86_64 - help - Enable this option if you want to use the LatencyTOP tool - to find out which userspace is blocking on what kernel operations. - - source "samples/Kconfig" diff --git a/trunk/lib/kernel_lock.c b/trunk/lib/kernel_lock.c index 812dbf00844b..f73e2f8c308f 100644 --- a/trunk/lib/kernel_lock.c +++ b/trunk/lib/kernel_lock.c @@ -9,6 +9,7 @@ #include #include +#ifdef CONFIG_PREEMPT_BKL /* * The 'big kernel semaphore' * @@ -85,6 +86,128 @@ void __lockfunc unlock_kernel(void) up(&kernel_sem); } +#else + +/* + * The 'big kernel lock' + * + * This spinlock is taken and released recursively by lock_kernel() + * and unlock_kernel(). It is transparently dropped and reacquired + * over schedule(). It is used to protect legacy code that hasn't + * been migrated to a proper locking design yet. + * + * Don't use in new code. + */ +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(kernel_flag); + + +/* + * Acquire/release the underlying lock from the scheduler. + * + * This is called with preemption disabled, and should + * return an error value if it cannot get the lock and + * TIF_NEED_RESCHED gets set. + * + * If it successfully gets the lock, it should increment + * the preemption count like any spinlock does. + * + * (This works on UP too - _raw_spin_trylock will never + * return false in that case) + */ +int __lockfunc __reacquire_kernel_lock(void) +{ + while (!_raw_spin_trylock(&kernel_flag)) { + if (test_thread_flag(TIF_NEED_RESCHED)) + return -EAGAIN; + cpu_relax(); + } + preempt_disable(); + return 0; +} + +void __lockfunc __release_kernel_lock(void) +{ + _raw_spin_unlock(&kernel_flag); + preempt_enable_no_resched(); +} + +/* + * These are the BKL spinlocks - we try to be polite about preemption. + * If SMP is not on (ie UP preemption), this all goes away because the + * _raw_spin_trylock() will always succeed. + */ +#ifdef CONFIG_PREEMPT +static inline void __lock_kernel(void) +{ + preempt_disable(); + if (unlikely(!_raw_spin_trylock(&kernel_flag))) { + /* + * If preemption was disabled even before this + * was called, there's nothing we can be polite + * about - just spin. + */ + if (preempt_count() > 1) { + _raw_spin_lock(&kernel_flag); + return; + } + + /* + * Otherwise, let's wait for the kernel lock + * with preemption enabled.. + */ + do { + preempt_enable(); + while (spin_is_locked(&kernel_flag)) + cpu_relax(); + preempt_disable(); + } while (!_raw_spin_trylock(&kernel_flag)); + } +} + +#else + +/* + * Non-preemption case - just get the spinlock + */ +static inline void __lock_kernel(void) +{ + _raw_spin_lock(&kernel_flag); +} +#endif + +static inline void __unlock_kernel(void) +{ + /* + * the BKL is not covered by lockdep, so we open-code the + * unlocking sequence (and thus avoid the dep-chain ops): + */ + _raw_spin_unlock(&kernel_flag); + preempt_enable(); +} + +/* + * Getting the big kernel lock. + * + * This cannot happen asynchronously, so we only need to + * worry about other CPU's. + */ +void __lockfunc lock_kernel(void) +{ + int depth = current->lock_depth+1; + if (likely(!depth)) + __lock_kernel(); + current->lock_depth = depth; +} + +void __lockfunc unlock_kernel(void) +{ + BUG_ON(current->lock_depth < 0); + if (likely(--current->lock_depth < 0)) + __unlock_kernel(); +} + +#endif + EXPORT_SYMBOL(lock_kernel); EXPORT_SYMBOL(unlock_kernel); diff --git a/trunk/mm/oom_kill.c b/trunk/mm/oom_kill.c index 96473b482099..91a081a82f55 100644 --- a/trunk/mm/oom_kill.c +++ b/trunk/mm/oom_kill.c @@ -286,7 +286,7 @@ static void __oom_kill_task(struct task_struct *p, int verbose) * all the memory it needs. That way it should be able to * exit() and clear out its resources quickly... */ - p->rt.time_slice = HZ; + p->time_slice = HZ; set_tsk_thread_flag(p, TIF_MEMDIE); force_sig(SIGKILL, p); diff --git a/trunk/mm/slab.c b/trunk/mm/slab.c index 40c00dacbe4b..ff31261fd24f 100644 --- a/trunk/mm/slab.c +++ b/trunk/mm/slab.c @@ -730,7 +730,8 @@ static inline void init_lock_keys(void) #endif /* - * Guard access to the cache-chain. + * 1. Guard access to the cache-chain. + * 2. Protect sanity of cpu_online_map against cpu hotplug events */ static DEFINE_MUTEX(cache_chain_mutex); static struct list_head cache_chain; @@ -1330,11 +1331,12 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb, int err = 0; switch (action) { + case CPU_LOCK_ACQUIRE: + mutex_lock(&cache_chain_mutex); + break; case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - mutex_lock(&cache_chain_mutex); err = cpuup_prepare(cpu); - mutex_unlock(&cache_chain_mutex); break; case CPU_ONLINE: case CPU_ONLINE_FROZEN: @@ -1371,8 +1373,9 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb, #endif case CPU_UP_CANCELED: case CPU_UP_CANCELED_FROZEN: - mutex_lock(&cache_chain_mutex); cpuup_canceled(cpu); + break; + case CPU_LOCK_RELEASE: mutex_unlock(&cache_chain_mutex); break; } @@ -2167,7 +2170,6 @@ kmem_cache_create (const char *name, size_t size, size_t align, * We use cache_chain_mutex to ensure a consistent view of * cpu_online_map as well. Please see cpuup_callback */ - get_online_cpus(); mutex_lock(&cache_chain_mutex); list_for_each_entry(pc, &cache_chain, next) { @@ -2394,7 +2396,6 @@ kmem_cache_create (const char *name, size_t size, size_t align, panic("kmem_cache_create(): failed to create slab `%s'\n", name); mutex_unlock(&cache_chain_mutex); - put_online_cpus(); return cachep; } EXPORT_SYMBOL(kmem_cache_create); @@ -2546,11 +2547,9 @@ int kmem_cache_shrink(struct kmem_cache *cachep) int ret; BUG_ON(!cachep || in_interrupt()); - get_online_cpus(); mutex_lock(&cache_chain_mutex); ret = __cache_shrink(cachep); mutex_unlock(&cache_chain_mutex); - put_online_cpus(); return ret; } EXPORT_SYMBOL(kmem_cache_shrink); @@ -2576,7 +2575,6 @@ void kmem_cache_destroy(struct kmem_cache *cachep) BUG_ON(!cachep || in_interrupt()); /* Find the cache in the chain of caches. */ - get_online_cpus(); mutex_lock(&cache_chain_mutex); /* * the chain is never empty, cache_cache is never destroyed @@ -2586,7 +2584,6 @@ void kmem_cache_destroy(struct kmem_cache *cachep) slab_error(cachep, "Can't free all objects"); list_add(&cachep->next, &cache_chain); mutex_unlock(&cache_chain_mutex); - put_online_cpus(); return; } @@ -2595,7 +2592,6 @@ void kmem_cache_destroy(struct kmem_cache *cachep) __kmem_cache_destroy(cachep); mutex_unlock(&cache_chain_mutex); - put_online_cpus(); } EXPORT_SYMBOL(kmem_cache_destroy); diff --git a/trunk/net/core/flow.c b/trunk/net/core/flow.c index 6489f4e24ecf..3ed2b4b1d6d4 100644 --- a/trunk/net/core/flow.c +++ b/trunk/net/core/flow.c @@ -293,7 +293,7 @@ void flow_cache_flush(void) static DEFINE_MUTEX(flow_flush_sem); /* Don't want cpus going down or up during this. */ - get_online_cpus(); + lock_cpu_hotplug(); mutex_lock(&flow_flush_sem); atomic_set(&info.cpuleft, num_online_cpus()); init_completion(&info.completion); @@ -305,7 +305,7 @@ void flow_cache_flush(void) wait_for_completion(&info.completion); mutex_unlock(&flow_flush_sem); - put_online_cpus(); + unlock_cpu_hotplug(); } static void __devinit flow_cache_cpu_prepare(int cpu) diff --git a/trunk/net/ipv4/arp.c b/trunk/net/ipv4/arp.c index 54a76b8b803a..08174a2aa878 100644 --- a/trunk/net/ipv4/arp.c +++ b/trunk/net/ipv4/arp.c @@ -211,7 +211,7 @@ int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) ip_tr_mc_map(addr, haddr); return 0; case ARPHRD_INFINIBAND: - ip_ib_mc_map(addr, dev->broadcast, haddr); + ip_ib_mc_map(addr, haddr); return 0; default: if (dir) { diff --git a/trunk/net/ipv6/ndisc.c b/trunk/net/ipv6/ndisc.c index 85947eae5bf7..777ed733b2d7 100644 --- a/trunk/net/ipv6/ndisc.c +++ b/trunk/net/ipv6/ndisc.c @@ -337,7 +337,7 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d ipv6_arcnet_mc_map(addr, buf); return 0; case ARPHRD_INFINIBAND: - ipv6_ib_mc_map(addr, dev->broadcast, buf); + ipv6_ib_mc_map(addr, buf); return 0; default: if (dir) {