http://linux.bkbits.net/linux-2.5 bunk@stusta.de[torvalds]|ChangeSet|20041212203112|64625 bunk # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/12/12 12:31:12-08:00 bunk@stusta.de # [PATCH] fm801_gp_probe: fix use after free # # The patch below by "Petri T. Koistinen" in # Rusty's trivial patches is IMHO a candidate for 2.6.10 . # # # Signed-off-by: Adrian Bunk # Signed-off-by: Linus Torvalds # # drivers/input/gameport/fm801-gp.c # 2004/12/04 16:06:01-08:00 bunk@stusta.de +1 -1 # fm801_gp_probe: fix use after free # # ChangeSet # 2004/12/12 10:38:02-08:00 torvalds@ppc970.osdl.org # x86 sysenter: clear %ebp on exit. # # It contains the thread info pointer. That's not something that # user mode can really use for anything interesting, but it's also # not something that user mode should ever really see. # # Pointed out by Brad Spender as being in PaX. # # arch/i386/kernel/entry.S # 2004/12/12 10:37:55-08:00 torvalds@ppc970.osdl.org +1 -0 # x86 sysenter: clear %ebp on exit. # # It contains the thread info pointer. That's not something that # user mode can really use for anything interesting, but it's also # not something that user mode should ever really see. # # ChangeSet # 2004/12/10 09:57:53-08:00 torvalds@ppc970.osdl.org # Clean up open_exec()/kmalloc() error case handling. # # It's a purely theoretical bug, since the kmalloc() failure that # might "leak" file descriptors cannot actually happen (we do not # ever fail small GFP_KERNEL allocations), but it's good to do # things properly. # # Noted by Brad Spender. # # fs/exec.c # 2004/12/10 09:57:46-08:00 torvalds@ppc970.osdl.org +10 -8 # Clean up open_exec()/kmalloc() error case handling. # # fs/compat.c # 2004/12/10 09:57:46-08:00 torvalds@ppc970.osdl.org +10 -8 # Clean up open_exec()/kmalloc() error case handling. # # ChangeSet # 2004/12/10 09:52:42-08:00 torvalds@ppc970.osdl.org # Make sure VC resizing fits in s16. # # Noted by Georgi Guninski # # drivers/char/vt.c # 2004/12/10 09:52:35-08:00 torvalds@ppc970.osdl.org +5 -0 # Make sure VC resizing fits in s16. # # ChangeSet # 2004/12/09 20:08:11-08:00 torvalds@ppc970.osdl.org # Merge bk://linux-scsi.bkbits.net/scsi-for-linus-2.6 # into ppc970.osdl.org:/home/torvalds/v2.6/linux # # drivers/block/cciss.c # 2004/12/09 20:08:07-08:00 torvalds@ppc970.osdl.org +0 -1 # Auto merged # # ChangeSet # 2004/12/09 13:49:32-08:00 greg@kroah.com # USB: fix another sparse warning in the USB core # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/inode.c # 2004/12/09 13:49:17-08:00 greg@kroah.com +1 -1 # USB: fix another sparse warning in the USB core # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/12/09 13:47:47-08:00 nacc@us.ibm.com # [PATCH] USB: add wake-up for waitqueues in usbfs_remove_file() to fix bug 387 # # Description: Bug 387 (http://bugzilla.kernel.org/show_bug.cgi?id=387) # is fixed by the attached patch, which sends waitqueue wake-ups to all # the appropriate wait-queue entries when a device is removed from # the system. # # Signed-off-by: Nishanth Aravamudan # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/core/inode.c # 2004/12/08 11:57:52-08:00 nacc@us.ibm.com +1 -0 # USB: add wake-up for waitqueues in usbfs_remove_file() to fix bug 387 # # ChangeSet # 2004/12/09 12:41:33-08:00 greg@kroah.com # USB: fix obvious build error in hc_chrisv10.c driver # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/hc_crisv10.c # 2004/12/09 12:41:24-08:00 greg@kroah.com +1 -1 # USB: fix obvious build error in hc_chrisv10.c driver # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/12/09 12:41:17-08:00 greg@kroah.com # USB: removed unused hc_sl811 driver from the tree # # Signed-off-by: Greg Kroah-Hartman # # BitKeeper/deleted/.del-hc_sl811_rh.c~a7c17b7413ce1779 # 2004/12/09 12:41:10-08:00 greg@kroah.com +0 -0 # Delete: drivers/usb/host/hc_sl811_rh.c # # BitKeeper/deleted/.del-hc_sl811.h~c807419e3e9283d5 # 2004/12/09 12:41:10-08:00 greg@kroah.com +0 -0 # Delete: drivers/usb/host/hc_sl811.h # # BitKeeper/deleted/.del-hc_sl811.c~8aecb583af6cedcf # 2004/12/09 12:41:10-08:00 greg@kroah.com +0 -0 # Delete: drivers/usb/host/hc_sl811.c # # BitKeeper/deleted/.del-hc_simple.h~3270f6c2fc8ba2d4 # 2004/12/09 12:41:10-08:00 greg@kroah.com +0 -0 # Delete: drivers/usb/host/hc_simple.h # # BitKeeper/deleted/.del-hc_simple.c~6574984ab71fcc15 # 2004/12/09 12:41:10-08:00 greg@kroah.com +0 -0 # Delete: drivers/usb/host/hc_simple.c # # ChangeSet # 2004/12/09 12:41:01-08:00 greg@kroah.com # USB: fix sparse warning in ehci-hcd driver. # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/ehci-hub.c # 2004/12/09 12:40:53-08:00 greg@kroah.com +1 -1 # USB: fix sparse warning in ehci-hcd driver. # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/12/09 12:40:44-08:00 greg@kroah.com # USB: fix sparse warnings in sl811-hcd driver. # # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/sl811-hcd.c # 2004/12/09 12:40:35-08:00 greg@kroah.com +2 -2 # USB: fix sparse warnings in sl811-hcd driver. # # Signed-off-by: Greg Kroah-Hartman # # ChangeSet # 2004/12/09 12:35:50-08:00 david-b@pacbell.net # [PATCH] USB: sl811-hcd driver, replaces hc_sl811 # # This patch provides a new "sl811-hcd" driver, which should replace the older # one from Cypress (which has been broken for ages, even on SA-1100). # # Key features of this new driver: # # - Small, relatively tight code; # - Uses the 2.6 platform_device and usbcore HCD infrastructures; # - Compiles (x86, ARM) and works (ARM/PXA255); # - Passed a day's worth of "usbtest" stress testing (on 2.6.9). # # I've enumerated over a dozen different devices with it, and actually tested # mice, hubs, keyboards, and usb-storage. There's a hardware erratum that # prevents this chip from working with certain external hubs. There's scope # yet for some performance work here; and some IRQ quirks linger. # # This PIO-only driver should serve as a model for some other non-DMA USB host # controllers (like isp1161, isp1362, td243) used in embedded Linuxes ... in # particular, showing how to maintain async and periodic schedules without # pointless emulation of OHCI DMA queues and/or registers. # # The driver should handle ISO, but since it doesn't implement the special # urb->iso_frame_desc[] "pseudo-queue" model (and since Linux can't guarantee # low enough IRQ latencies!), ISO is disabled. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # include/linux/usb_sl811.h # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +26 -0 # USB: sl811-hcd driver, replaces hc_sl811 # # drivers/usb/host/sl811.h # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +270 -0 # USB: sl811-hcd driver, replaces hc_sl811 # # include/linux/usb_sl811.h # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/include/linux/usb_sl811.h # # drivers/usb/host/sl811.h # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/host/sl811.h # # drivers/usb/host/sl811-hcd.c # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +1905 -0 # USB: sl811-hcd driver, replaces hc_sl811 # # drivers/usb/host/Makefile # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +1 -2 # USB: sl811-hcd driver, replaces hc_sl811 # # drivers/usb/host/Kconfig # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +9 -7 # USB: sl811-hcd driver, replaces hc_sl811 # # drivers/usb/host/sl811-hcd.c # 2004/12/06 10:45:04-08:00 david-b@pacbell.net +0 -0 # BitKeeper file /home/greg/linux/BK/usb-2.6/drivers/usb/host/sl811-hcd.c # # ChangeSet # 2004/12/09 12:23:36-08:00 david-b@pacbell.net # [PATCH] USB: OHCI "resume"/smp fix # # I noticed an SMP deadlock when connecting devices to # an autosuspended root hub. # # This fix just makes the OHCI hub status reporting logic (used # exclusively by khubd) be a NOP until after the worker task # (keventd) finishes resuming the port, so they can't deadlock. # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/ohci-hub.c # 2004/12/07 07:53:43-08:00 david-b@pacbell.net +14 -4 # USB: OHCI "resume"/smp fix # # ChangeSet # 2004/12/09 12:23:20-08:00 bunk@stusta.de # [PATCH] USB uhci-debug.c: remove an unused function (fwd) # # The patch below removes an unused function from # drivers/usb/host/uhci-debug.c # # # Signed-off-by: Adrian Bunk # Acked-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/uhci-debug.c # 2004/10/28 14:30:49-07:00 bunk@stusta.de +0 -11 # USB uhci-debug.c: remove an unused function (fwd) # # ChangeSet # 2004/12/09 12:23:06-08:00 david-b@pacbell.net # [PATCH] USB: EHCI qh update race fix # # This makes the EHCI driver stop trying to update a live QH ... it's # not like OHCI, that can't be done safely because of a hardware race. # The fix: # # - Unlinks the QH before updating it; only the tail can safely be # updated "live", not the queue head. The async schedule (all # control/bulk QHs) and periodic schedule (interrupt QH) work a # bit differently ... high bandwidth transfers will hiccup. # # - Moves "update QH" and "clear toggle" logic into one new # qh_refresh() routine, used in several places. # # The race shows readily enough under load with the right hardware. # The controller silicon might be relatively slow, or maybe it's the # bus that's slow/busy: # # Host Controller # --- ---------- # reads two TD pointers # update two TD pointers # wmb() # activate QH # reads rest of QH # # Net result is that the HC treated old TD pointers as valid, and things # started misbehaving. Busy controllers would misbehave worse; some systems # wouldn't notice more than a slowdown, especially with light USB loads. # # This affects behavior in two cases. The uncommon one is when an endpoint # gets an error and halts. The more common one happens when the controller # runs off the end of its queue and overlays an inactive "dummy" TD into # the QH ... something the spec says shouldn't happen, but which more # silicon seems to be doing. (Presumably to reduce DMA chatter.) # # Signed-off-by: David Brownell # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/ehci-sched.c # 2004/12/07 13:04:36-08:00 david-b@pacbell.net +3 -2 # USB: EHCI qh update race fix # # drivers/usb/host/ehci-q.c # 2004/12/07 13:04:36-08:00 david-b@pacbell.net +75 -58 # USB: EHCI qh update race fix # # ChangeSet # 2004/12/09 12:22:49-08:00 stern@rowland.harvard.edu # [PATCH] USB UHCI: minor bugfix for port resume # # This patch fixes two small problems in the port suspend/resume handling # for the UHCI driver. There were a couple of spots where I neglected to # store I/O addresses in unsigned _long_ variables (required for 64-bit # architectures). And it turns out the host controller will continue to # indicate a resume is in progress for a few microseconds after it has been # turned off, so an extra delay is needed. # # # Signed-off-by: Alan Stern # Signed-off-by: Greg Kroah-Hartman # # drivers/usb/host/uhci-hub.c # 2004/12/01 14:06:25-08:00 stern@rowland.harvard.edu +8 -2 # USB UHCI: minor bugfix for port resume # # ChangeSet # 2004/12/09 12:22:35-08:00 rddunlap@osdl.org # [PATCH] PCI/x86-64: build with PCI=n # # Fix (most of) x64-64 kernel build for CONFIG_PCI=n. Fixes these 2 errors: # # 1. arch/x86_64/kernel/built-in.o(.text+0x8186): In function `quirk_intel_irqbalance': # : undefined reference to `raw_pci_ops' # # Kconfig change: # 2. arch/x86_64/kernel/pci-gart.c:194: error: `pci_bus_type' undeclared (first use in this function) # # Still does not fix this one: # drivers/built-in.o(.text+0x3dcd8): In function `pnpacpi_allocated_resource': # : undefined reference to `pcibios_penalize_isa_irq' # # Signed-off-by: Randy Dunlap # Signed-off-by: Greg Kroah-Hartman # # arch/x86_64/Kconfig # 2004/11/16 10:50:01-08:00 rddunlap@osdl.org +1 -0 # PCI/x86-64: build with PCI=n # # arch/i386/kernel/quirks.c # 2004/11/16 11:24:25-08:00 rddunlap@osdl.org +2 -1 # PCI/x86-64: build with PCI=n # # ChangeSet # 2004/12/09 08:19:26-08:00 pisa@cmp.felk.cvut.cz # [PATCH] VM86 interrupt emulation fix # # Fixes faulty IRQ_NONE value returning by VM86 irq_handler(). # # The IRQ source is blocked as well until userspace confirms processing. # This should enable to use VM86 code even for level triggered interrupt # sources. # # Signed-off-by: Pavel Pisa # Signed-off-by: Linus Torvalds # # arch/i386/kernel/vm86.c # 2004/12/09 08:14:48-08:00 pisa@cmp.felk.cvut.cz +8 -1 # VM86 interrupt emulation fix # # ChangeSet # 2004/12/08 23:22:06-08:00 eradicator@gentoo.org # [SPARC]: Make some asm headers more userland friendly. # # Signed-off-by: David S. Miller # # include/asm-sparc/signal.h # 2004/12/08 23:21:27-08:00 eradicator@gentoo.org +5 -3 # [SPARC]: Make some asm headers more userland friendly. # # include/asm-sparc/sigcontext.h # 2004/12/08 23:21:27-08:00 eradicator@gentoo.org +2 -1 # [SPARC]: Make some asm headers more userland friendly. # # include/asm-sparc/processor.h # 2004/12/08 23:21:27-08:00 eradicator@gentoo.org +2 -0 # [SPARC]: Make some asm headers more userland friendly. # # ChangeSet # 2004/12/08 23:02:03-08:00 davem@nuts.davemloft.net # [SPARC]: Adjust 32-bit ELF_ET_DYN_BASE. # # We were using 0x08000000 instead of TASK_UNMAPPED_BASE # so that running something like "/lib/ld-linux.so.2 emacs" # would work. # # The issue there was that wherever /lib/ld-linux.so.2 gets # mapped (controlled by ELF_ET_DYN_BASE), that is where the # BSS start for the process ends up. Now, emacs allocates # dynamic memory for LISP objects from the BSS, and needs # the top 4 bits of the virtual address to be clear so that # it can encode LISP type and GC marking information there. # # But making this obscure emacs case work breaks lots of other # stuff. For example, programs with a reasonably large data # section fail to load via direct ld.so interpreter execution # because the data section is large enough to begin overlapping # with the ELF_ET_DYN_BASE area. # # The /lib/ld-linux.so.2 emacs case does not work on a lot of # platforms due to this issue, including i386, so it is not # worth making work on sparc either. It is indeed useful # sometimes when debugging a new experimental build of glibc # for example, but people doing that can hack the value of # ELF_ET_DYN_BASE in their kernels. Perhaps at some point # we will make a sysctl controllable value. # # Signed-off-by: David S. Miller # # include/asm-sparc/elf.h # 2004/12/08 22:56:54-08:00 davem@nuts.davemloft.net +1 -1 # [SPARC]: Adjust 32-bit ELF_ET_DYN_BASE. # # arch/sparc64/kernel/binfmt_elf32.c # 2004/12/08 22:56:54-08:00 davem@nuts.davemloft.net +1 -1 # [SPARC]: Adjust 32-bit ELF_ET_DYN_BASE. # # ChangeSet # 2004/12/08 22:55:27-08:00 wensong@linux-vs.org # [IPVS] add a sysctl variable to expire quiescent template # # The patch is from Horms # # Signed-off-by: Horms # Signed-off-by: David S. Miller # # net/ipv4/ipvs/ip_vs_ctl.c # 2004/12/08 22:54:47-08:00 wensong@linux-vs.org +20 -11 # [IPVS] add a sysctl variable to expire quiescent template # # The patch is from Horms # # Signed-off-by: Horms # Signed-off-by: David S. Miller # # net/ipv4/ipvs/ip_vs_conn.c # 2004/12/08 22:54:47-08:00 wensong@linux-vs.org +3 -1 # [IPVS] add a sysctl variable to expire quiescent template # # The patch is from Horms # # Signed-off-by: Horms # Signed-off-by: David S. Miller # # include/net/ip_vs.h # 2004/12/08 22:54:47-08:00 wensong@linux-vs.org +2 -0 # [IPVS] add a sysctl variable to expire quiescent template # # The patch is from Horms # # Signed-off-by: Horms # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 22:00:32-08:00 davem@nuts.davemloft.net # [IPV6]: Do not use udp_poll for RAW sockets. # # Signed-off-by: David S. Miller # # net/ipv6/af_inet6.c # 2004/12/08 21:59:56-08:00 davem@nuts.davemloft.net +23 -1 # [IPV6]: Do not use udp_poll for RAW sockets. # # ChangeSet # 2004/12/08 21:37:13-08:00 solar@openwall.com # [TCP]: Missing KERN_INFO in remotely triggerable printk. # # Signed-off-by: David S. Miller # # net/ipv4/tcp_input.c # 2004/12/08 21:36:20-08:00 solar@openwall.com +1 -1 # [TCP]: Missing KERN_INFO in remotely triggerable printk. # # ChangeSet # 2004/12/08 21:32:16-08:00 jurij@woodyd.org # [SUNSAB]: Fix serial break handling. # # We forget to check the BRK condition in # the interrupt status register when deciding # to call receive_chars() or not, which is where # BRK handling occurs. # # Signed-off-by: David S. Miller # # drivers/serial/sunsab.c # 2004/12/08 21:31:16-08:00 jurij@woodyd.org +12 -6 # [SUNSAB]: Fix serial break handling. # # ChangeSet # 2004/12/08 21:15:08-08:00 davem@nuts.davemloft.net # [SPARC64]: Update defconfig. # # Signed-off-by: David S. Miller # # arch/sparc64/defconfig # 2004/12/08 21:14:39-08:00 davem@nuts.davemloft.net +54 -36 # [SPARC64]: Update defconfig. # # ChangeSet # 2004/12/08 20:35:33-08:00 shemminger@osdl.org # [PKT_SCHED]: netem forgets to restart device after inserting packets # # The version of netem in 2.6.10 moves packets from the delayed queue # to the qdisc in a timer interrupt. But it forgot to force the device to # pick them up. # # Signed-off-by: Stephen Hemminger # Signed-off-by: David S. Miller # # net/sched/sch_netem.c # 2004/12/08 20:35:14-08:00 shemminger@osdl.org +4 -2 # [PKT_SCHED]: netem forgets to restart device after inserting packets # # The version of netem in 2.6.10 moves packets from the delayed queue # to the qdisc in a timer interrupt. But it forgot to force the device to # pick them up. # # Signed-off-by: Stephen Hemminger # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 20:33:03-08:00 kaber@trash.net # [PKT_SCHED]: Fix oops in ipt action error path. # # This patch fixes an oops when the ipt action is used with a # non-existant iptables target. It tries to log # t->u.kernel.target->name, u.kernel.target is part of a union # and as long as the target wasn't successfully loaded contains # the name of the target, using it as a pointer results in a # crash. # # Signed-off-by: Patrick McHardy # Signed-off-by: David S. Miller # # net/sched/ipt.c # 2004/12/08 20:32:45-08:00 kaber@trash.net +1 -2 # [PKT_SCHED]: Fix oops in ipt action error path. # # This patch fixes an oops when the ipt action is used with a # non-existant iptables target. It tries to log # t->u.kernel.target->name, u.kernel.target is part of a union # and as long as the target wasn't successfully loaded contains # the name of the target, using it as a pointer results in a # crash. # # Signed-off-by: Patrick McHardy # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 20:31:35-08:00 jt@hpl.hp.com # [IRDA]: Use kill_urb() in irda-usb # # * change comment about Sigmatel now that there is a driver # * convert to new module_param # * places where urb is unlinked synchronously, use usb_kill_urb # because that is now a runtime warning. # # Original patch from Stephen Hemminger # # Signed-off-by: Stephen Hemminger # Signed-off-by: Jean Tourrilhes # Signed-off-by: David S. Miller # # drivers/net/irda/irda-usb.c # 2004/12/08 20:31:16-08:00 jt@hpl.hp.com +10 -10 # [IRDA]: Use kill_urb() in irda-usb # # * change comment about Sigmatel now that there is a driver # * convert to new module_param # * places where urb is unlinked synchronously, use usb_kill_urb # because that is now a runtime warning. # # Original patch from Stephen Hemminger # # Signed-off-by: Stephen Hemminger # Signed-off-by: Jean Tourrilhes # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 20:29:41-08:00 jt@hpl.hp.com # [IRDA]: Use kill_urb() in stir4200 # # USB changed behaviour of unlink_urb so that it gives warning and backtrace when # being used synchronously. The correct current behaviour is to us kill_urb # in that case. # # Original patch from Stephen Hemminger # # Signed-off-by: Stephen Hemminger # Signed-off-by: Jean Tourrilhes # Signed-off-by: David S. Miller # # drivers/net/irda/stir4200.c # 2004/12/08 20:29:22-08:00 jt@hpl.hp.com +2 -2 # [IRDA]: Use kill_urb() in stir4200 # # USB changed behaviour of unlink_urb so that it gives warning and backtrace when # being used synchronously. The correct current behaviour is to us kill_urb # in that case. # # Original patch from Stephen Hemminger # # Signed-off-by: Stephen Hemminger # Signed-off-by: Jean Tourrilhes # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 20:28:20-08:00 jt@hpl.hp.com # [IRDA]: Try to fix the worst abuse of the pci init code in via_ircc # # Bugfix suggested by Arkadiusz Miskiewicz. # # Signed-off-by: Jean Tourrilhes # Signed-off-by: David S. Miller # # drivers/net/irda/via-ircc.c # 2004/12/08 20:28:01-08:00 jt@hpl.hp.com +20 -3 # [IRDA]: Try to fix the worst abuse of the pci init code in via_ircc # # Bugfix suggested by Arkadiusz Miskiewicz. # # Signed-off-by: Jean Tourrilhes # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 20:22:28-08:00 davem@nuts.davemloft.net # [SPARC]: asm/mostek.h needs asm/io.h # # Noticed by Bob Breuer. # # Signed-off-by: David S. Miller # # include/asm-sparc/mostek.h # 2004/12/08 20:21:53-08:00 davem@nuts.davemloft.net +1 -0 # [SPARC]: asm/mostek.h needs asm/io.h # # ChangeSet # 2004/12/08 13:37:53-08:00 kaber@trash.net # [NETFILTER]: Fix memory leak in ip_conntrack_ftp # # Signed-off-by: Patrick McHardy # Signed-off-by: David S. Miller # # net/ipv4/netfilter/ip_conntrack_ftp.c # 2004/12/08 13:37:32-08:00 kaber@trash.net +1 -0 # [NETFILTER]: Fix memory leak in ip_conntrack_ftp # # Signed-off-by: Patrick McHardy # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 13:03:03-08:00 davem@nuts.davemloft.net # [NET]: CMSG compat code needs signedness fixes too. # # Signed-off-by: David S. Miller # # net/compat.c # 2004/12/08 13:02:32-08:00 davem@nuts.davemloft.net +7 -5 # [NET]: CMSG compat code needs signedness fixes too. # # ChangeSet # 2004/12/08 12:49:21-08:00 herbert@gondor.apana.org.au # [NET]: Fix CMSG validation checks wrt. signedness. # # Noticed by Georgi Guninski. # # Signed-off-by: Herbert Xu # Signed-off-by: David S. Miller # # net/sctp/socket.c # 2004/12/08 12:48:29-08:00 herbert@gondor.apana.org.au +1 -5 # [NET]: Fix CMSG validation checks wrt. signedness. # # net/ipv6/datagram.c # 2004/12/08 12:48:28-08:00 herbert@gondor.apana.org.au +1 -3 # [NET]: Fix CMSG validation checks wrt. signedness. # # net/ipv4/ip_sockglue.c # 2004/12/08 12:48:28-08:00 herbert@gondor.apana.org.au +1 -4 # [NET]: Fix CMSG validation checks wrt. signedness. # # net/core/scm.c # 2004/12/08 12:48:28-08:00 herbert@gondor.apana.org.au +1 -3 # [NET]: Fix CMSG validation checks wrt. signedness. # # include/linux/socket.h # 2004/12/08 12:48:28-08:00 herbert@gondor.apana.org.au +4 -0 # [NET]: Fix CMSG validation checks wrt. signedness. # # ChangeSet # 2004/12/08 12:39:15-08:00 davem@nuts.davemloft.net # [IPV4]: Do not leak IP options. # # If the user makes ip_cmsg_send call ip_options_get # multiple times, we leak kmalloced IP options data. # # Noticed by Georgi Guninski. # # Signed-off-by: David S. Miller # # net/ipv4/ip_options.c # 2004/12/08 12:38:09-08:00 davem@nuts.davemloft.net +2 -0 # [IPV4]: Do not leak IP options. # # ChangeSet # 2004/12/08 12:30:12-08:00 yoshfuji@linux-ipv6.org # [IPV6]: Fix check if we're a router. # # Signed-off-by: Hideaki YOSHIFUJI # Signed-off-by: David S. Miller # # net/ipv6/ndisc.c # 2004/12/08 12:29:53-08:00 yoshfuji@linux-ipv6.org +1 -1 # [IPV6]: Fix check if we're a router. # # Signed-off-by: Hideaki YOSHIFUJI # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/08 07:41:46-08:00 piggin@cyberone.com.au # [PATCH] Fix broken domain debugging (aka "isolcpus option broken") # # Fix an oops in sched_domain_debug when using the isolcpus= option. # # Also move a debug check for validating groups into the "for-each-group" # loop, where it should be. # # Signed-off-by: Nick Piggin # Signed-off-by: Linus Torvalds # # kernel/sched.c # 2004/12/08 00:53:23-08:00 piggin@cyberone.com.au +4 -2 # Fix broken domain debugging (aka "isolcpus option broken") # # ChangeSet # 2004/12/08 07:38:59-08:00 torvalds@ppc970.osdl.org # Revert isolcpus option fix, pending better fix from Nick. # # The real bug was in the debugging code, not the actual domain data # structure setup. # # Cset exclude: sivanich@sgi.com[torvalds]|ChangeSet|20041207160443|30564 # # kernel/sched.c # 2004/12/08 07:38:57-08:00 torvalds@ppc970.osdl.org +0 -0 # Revert isolcpus option fix, pending better fix from Nick. # # arch/ia64/kernel/domain.c # 2004/12/08 07:38:57-08:00 torvalds@ppc970.osdl.org +0 -0 # Revert isolcpus option fix, pending better fix from Nick. # # ChangeSet # 2004/12/07 21:05:37-08:00 kaber@trash.net # [PKT_SCHED]: Fix hard freeze with QoS in 2.6.10-rc3 # # The problem is in tcf_action_copy_stats, it assumes a->priv has # the same layout as struct tcf_act_hdr, which is not true for # struct tcf_police. This patch rearranges struct tcf_police to # match tcf_act_hdr. # # Signed-off-by: Patrick McHardy # Signed-off-by: David S. Miller # # include/net/act_api.h # 2004/12/07 21:05:18-08:00 kaber@trash.net +15 -26 # [PKT_SCHED]: Fix hard freeze with QoS in 2.6.10-rc3 # # The problem is in tcf_action_copy_stats, it assumes a->priv has # the same layout as struct tcf_act_hdr, which is not true for # struct tcf_police. This patch rearranges struct tcf_police to # match tcf_act_hdr. # # Signed-off-by: Patrick McHardy # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/07 21:03:48-08:00 mitch@sfgoth.com # [IPV4]: Do not use udp_poll for RAW sockets. # # Signed-off-by: Mitchell Blank Jr # Signed-off-by: David S. Miller # # net/ipv4/af_inet.c # 2004/12/07 21:03:28-08:00 mitch@sfgoth.com +26 -1 # [IPV4]: Do not use udp_poll for RAW sockets. # # Signed-off-by: Mitchell Blank Jr # Signed-off-by: David S. Miller # # ChangeSet # 2004/12/07 18:35:14-08:00 torvalds@ppc970.osdl.org # Revert recent ext3_dx_readdir changes # # They turn out to be buggy, and result in the same filename being # reported twice when htree directory indexing is enabled. # # Thanks for Kris Karas for helping chase it down. Also reported # by Holger Kiehl. # # Cset exclude: akpm@osdl.org[torvalds]|ChangeSet|20041108040801|49372 # # fs/ext3/dir.c # 2004/12/07 18:35:12-08:00 torvalds@ppc970.osdl.org +0 -0 # Revert recent ext3_dx_readdir changes # # ChangeSet # 2004/12/07 19:23:59-05:00 dougg@torque.net # [PATCH] off-by-1 libata-scsi INQUIRY VPD pages 0x80 and 0x83 # # I have some code (in sginfo) that requests the first 4 bytes # of SCSI INQUIRY VPD pages to get their length then asks for # that exact length in a follow up request to fetch the payload. # Just like I saw with 36 byte standard INQUIRYs (no fixed) # I get a buffer full or zeroes. # # BTW SCSI standards dictate that in situations where the allocation # length (in the cdb) is less than what is needed that what can be # sent shall be sent (i.e. truncated and without any error indication # or modification to the part of the response returned). # In other words it is up the the application client to take remedial # action. # # Changelog: # - fix off-by-1 allocation length issue with SCSI # INQUIRY VPD pages 0x80 and 0x83 # # Signed-off-by: Jeff Garzik # # drivers/scsi/libata-scsi.c # 2004/11/26 04:13:03-05:00 dougg@torque.net +2 -2 # off-by-1 libata-scsi INQUIRY VPD pages 0x80 and 0x83 # # ChangeSet # 2004/12/07 16:23:27-08:00 kraxel@bytesex.org # [PATCH] msp3400 quick fix # # The new "simpler" opmode added by the recent merge from ivtv breaks msp3400 # support for other tv cards. Not figured yet why. # # This patch disables the "simpler" mode by default (can still be enabled by # insmod option) as quick fix for 2.6.10. # # Signed-off-by: Gerd Knorr # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/media/video/msp3400.c # 2004/12/07 06:25:35-08:00 kraxel@bytesex.org +4 -1 # msp3400 quick fix # # ChangeSet # 2004/12/07 16:23:12-08:00 hunold@linuxtv.org # [PATCH] dvb: follow changes in dvb-ttpci and budget drivers # # - [DVB] dvb-ttpci, budget: updated to fix problems with some CAMs on KNC1 # cards # # - [DVB] dvb-ttpci, budget: make needlessly global code static, whitespace # and newline cleanups, thanks to Adrian Bunk # # - [DVB] dvb-ttpci, budget: follow frontend changes in driver # # - [DVB] dvb-ttpci, budget: fix drivers to use new # wait_for_debi_done(...,nobusywait) routine. # # Signed-off-by: Michael Hunold # Signed-off-by: Adrian Bunk # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +1 -1 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/budget.h # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +17 -6 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/budget.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +333 -62 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/budget-patch.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +225 -23 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/budget-core.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +93 -46 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/budget-ci.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +493 -108 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/budget-av.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +665 -44 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/av7110_v4l.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +5 -5 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/av7110_hw.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +23 -7 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/av7110_ca.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +4 -4 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/av7110_av.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +2 -2 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/av7110.h # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +18 -0 # dvb: follow changes in dvb-ttpci and budget drivers # # drivers/media/dvb/ttpci/av7110.c # 2004/12/07 06:25:35-08:00 hunold@linuxtv.org +579 -112 # dvb: follow changes in dvb-ttpci and budget drivers # # ChangeSet # 2004/12/07 16:22:59-08:00 hunold@linuxtv.org # [PATCH] dvb: remove dead files # # - [DVB] remove obsolete grundig_29504-401, grundig_29504-491, alps_tdlb7 and # alps_tdmb7 frontend drivers # # - [DVB] remove sp887x firmware file, it's unused thanks to firmware_class # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # BitKeeper/deleted/.del-sp887x_firm.h~458e089f33a5ef45 # 2004/12/07 16:22:52-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/frontends/sp887x_firm.h # # BitKeeper/deleted/.del-grundig_29504-491.c~3cd6cf69802be994 # 2004/12/07 16:22:52-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/frontends/grundig_29504-491.c # # BitKeeper/deleted/.del-grundig_29504-401.c~a5893812564d3643 # 2004/12/07 16:22:52-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/frontends/grundig_29504-401.c # # BitKeeper/deleted/.del-alps_tdmb7.c~3e02fe25d79f6a8a # 2004/12/07 16:22:51-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/frontends/alps_tdmb7.c # # BitKeeper/deleted/.del-alps_tdlb7.c~27de420074c35d6e # 2004/12/07 16:22:51-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/frontends/alps_tdlb7.c # # ChangeSet # 2004/12/07 16:22:44-08:00 hunold@linuxtv.org # [PATCH] dvb: core changes # # - [DVB] dvb-core: follow Linux coding style, kill dvb_ksyms.c and move the # EXPORT_SYMBOLs to the files where the functions are, thanks to Adrian Bunk # # # - [DVB] dvb-core: #if 0'ing unused code, make needlessly global code static, # whitespace and newline cleanups, thanks to Adrian Bunk # # - [DVB] dvb_ca_en50221.c: support for KNC1/Cinergy CI modules, fix # segfaults, enhanced poll_slot_status to support non-IRQ interfaces, Fix # module usage count problem # # - [DVB] dvb-frontend.c: core changes to support the refactorized frontend # drivers # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # include/linux/dvb/frontend.h # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +1 -1 # dvb: core changes # # drivers/media/dvb/dvb-core/dvbdev.h # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +1 -0 # dvb: core changes # # drivers/media/dvb/dvb-core/dvbdev.c # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +7 -0 # dvb: core changes # # drivers/media/dvb/dvb-core/dvb_net.c # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +7 -1 # dvb: core changes # # drivers/media/dvb/dvb-core/dvb_frontend.h # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +49 -80 # dvb: core changes # # drivers/media/dvb/dvb-core/dvb_frontend.c # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +159 -367 # dvb: core changes # # drivers/media/dvb/dvb-core/dvb_filter.c # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +9 -5 # dvb: core changes # # drivers/media/dvb/dvb-core/dvb_demux.c # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +9 -1 # dvb: core changes # # drivers/media/dvb/dvb-core/dvb_ca_en50221.h # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +4 -1 # dvb: core changes # # drivers/media/dvb/dvb-core/dvb_ca_en50221.c # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +269 -119 # dvb: core changes # # drivers/media/dvb/dvb-core/dmxdev.c # 2004/12/07 06:25:34-08:00 hunold@linuxtv.org +4 -9 # dvb: core changes # # BitKeeper/deleted/.del-dvb_ksyms.c~9282b8b83492594c # 2004/12/07 16:22:37-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/dvb-core/dvb_ksyms.c # # ChangeSet # 2004/12/07 16:22:31-08:00 hunold@linuxtv.org # [PATCH] dvb: dibusb driver update # # - [DVB] dibusb: added remote control event handling, thanks to David # Matthews. # # - [DVB] dibusb: added support for special Artec devices (with AN2235 usb # controller) # # - [DVB] dibusb: enable several new devices (even the broken Artec T1) # # - [DVB] dibusb: #if 0'ing unused code # # - [DVB] dibusb: follow frontend changes # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/media/dvb/dibusb/dvb-dibusb.h # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +224 -124 # dvb: dibusb driver update # # drivers/media/dvb/dibusb/dvb-dibusb.c # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +379 -199 # dvb: dibusb driver update # # ChangeSet # 2004/12/07 16:22:17-08:00 hunold@linuxtv.org # [PATCH] dvb: Cinergy T2 update # # - [DVB] cinergyT2: update driver to exploit hardware capabilities # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/media/dvb/cinergyT2/cinergyT2.c # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +320 -189 # dvb: Cinergy T2 update # # drivers/media/dvb/cinergyT2/Kconfig # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +28 -2 # dvb: Cinergy T2 update # # ChangeSet # 2004/12/07 16:22:05-08:00 hunold@linuxtv.org # [PATCH] dvb: follow frontend changes in drivers # # - [DVB] dvb-ttusb-dec, dvb-ttusb-budget, skystar2, bt878 + dvb-bt8xx: follow # frontend changes in driver # # - [DVB] DST isn't a real frontend, it's an interface to a frontend # microcontroller, so move the hardware dependend stuff to the right place # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/media/dvb/ttusb-dec/ttusbdecfe.h # 2004/12/07 16:21:57-08:00 hunold@linuxtv.org +38 -0 # # drivers/media/dvb/ttusb-dec/ttusbdecfe.c # 2004/12/07 16:21:57-08:00 hunold@linuxtv.org +255 -0 # # drivers/media/dvb/ttusb-dec/ttusbdecfe.h # 2004/12/07 16:21:57-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.h # # drivers/media/dvb/ttusb-dec/ttusbdecfe.c # 2004/12/07 16:21:57-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/ttusb-dec/ttusbdecfe.c # # drivers/media/dvb/ttusb-dec/ttusb_dec.c # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +42 -307 # dvb: follow frontend changes in drivers # # drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +1 -1 # dvb: follow frontend changes in drivers # # drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c # 2004/12/07 07:33:13-08:00 hunold@linuxtv.org +181 -49 # dvb: follow frontend changes in drivers # # drivers/media/dvb/bt8xx/dvb-bt8xx.h # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +5 -0 # dvb: follow frontend changes in drivers # # drivers/media/dvb/bt8xx/dvb-bt8xx.c # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +290 -22 # dvb: follow frontend changes in drivers # # drivers/media/dvb/bt8xx/dst_priv.h # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +1 -1 # dvb: follow frontend changes in drivers # # drivers/media/dvb/bt8xx/dst.h # 2004/12/07 16:21:56-08:00 hunold@linuxtv.org +40 -0 # # drivers/media/dvb/bt8xx/dst.c # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +447 -614 # dvb: follow frontend changes in drivers # # drivers/media/dvb/bt8xx/bt878.c # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +5 -18 # dvb: follow frontend changes in drivers # # drivers/media/dvb/b2c2/skystar2.c # 2004/12/07 06:25:32-08:00 hunold@linuxtv.org +220 -69 # dvb: follow frontend changes in drivers # # drivers/media/dvb/bt8xx/dst.h # 2004/12/07 16:21:56-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/bt8xx/dst.h # # ChangeSet # 2004/12/07 16:20:46-08:00 hunold@linuxtv.org # [PATCH] dvb: saa7146 changes # # - [DVB] saa7146_core.c, saa7146_video.c: MODULE_PARM -> module_param, added # non-busy waiting option for saa7146_wait_for_debi_done(), make needlessly # global code static and remove unused code (thanks to Adrian Bunk # ) # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # include/media/saa7146_vv.h # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +0 -2 # dvb: saa7146 changes # # include/media/saa7146.h # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: saa7146 changes # # drivers/media/common/saa7146_video.c # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: saa7146 changes # # drivers/media/common/saa7146_vbi.c # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: saa7146 changes # # drivers/media/common/saa7146_i2c.c # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: saa7146 changes # # drivers/media/common/saa7146_hlp.c # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +2 -19 # dvb: saa7146 changes # # drivers/media/common/saa7146_fops.c # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -11 # dvb: saa7146 changes # # drivers/media/common/saa7146_core.c # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +95 -82 # dvb: saa7146 changes # # ChangeSet # 2004/12/07 16:20:33-08:00 hunold@linuxtv.org # [PATCH] dvb: frontend driver refactoring # # - [DVB] reafactor or add the following frontend drivers: at76c651, cx22700, # ves1x93, ves1820, tda80xx, tda8083, cx22702, tda1004x, tda10021, cx24110, # dvb_dummy_fe, l64781, mt312, mt352, stv0299, sp887x, stv0297, nxt6000, # sp8870 # # - [DVB] remove dib3000mb from frontends, it's handled by the hw dependent # driver now # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/media/dvb/frontends/ves1x93.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +50 -0 # # drivers/media/dvb/frontends/ves1820.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +52 -0 # # drivers/media/dvb/frontends/tda80xx.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +51 -0 # # drivers/media/dvb/frontends/tda80xx.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +749 -0 # # drivers/media/dvb/frontends/tda8083.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +45 -0 # # drivers/media/dvb/frontends/tda8083.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +490 -0 # # drivers/media/dvb/frontends/tda1004x.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +53 -0 # # drivers/media/dvb/frontends/tda10021.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +43 -0 # # drivers/media/dvb/frontends/tda10021.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +483 -0 # # drivers/media/dvb/frontends/stv0299.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +104 -0 # # drivers/media/dvb/frontends/stv0297.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +41 -0 # # drivers/media/dvb/frontends/stv0297.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +774 -0 # # drivers/media/dvb/frontends/sp887x.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +29 -0 # # drivers/media/dvb/frontends/sp8870.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +45 -0 # # drivers/media/dvb/frontends/sp8870.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +613 -0 # # drivers/media/dvb/frontends/nxt6000_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +265 -0 # # drivers/media/dvb/frontends/mt352_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +127 -0 # # drivers/media/dvb/frontends/mt312_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +162 -0 # # drivers/media/dvb/frontends/l64781.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +43 -0 # # drivers/media/dvb/frontends/l64781.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +607 -0 # # drivers/media/dvb/frontends/dvb_dummy_fe.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +32 -0 # # drivers/media/dvb/frontends/dib3000mb_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +467 -0 # # drivers/media/dvb/frontends/dib3000.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +53 -0 # # drivers/media/dvb/frontends/dib3000-common.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +104 -0 # # drivers/media/dvb/frontends/cx24110.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +45 -0 # # drivers/media/dvb/frontends/cx22702.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +46 -0 # # drivers/media/dvb/frontends/cx22700.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +41 -0 # # drivers/media/dvb/frontends/cx22700.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +445 -0 # # drivers/media/dvb/frontends/ves1x93.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/ves1x93.h # # drivers/media/dvb/frontends/ves1x93.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +242 -415 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/ves1820.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/ves1820.h # # drivers/media/dvb/frontends/ves1820.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +216 -391 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/tda80xx.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/tda80xx.h # # drivers/media/dvb/frontends/tda80xx.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/tda80xx.c # # drivers/media/dvb/frontends/tda8083.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/tda8083.h # # drivers/media/dvb/frontends/tda8083.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/tda8083.c # # drivers/media/dvb/frontends/tda1004x.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/tda1004x.h # # drivers/media/dvb/frontends/tda1004x.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +415 -758 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/tda10021.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/tda10021.h # # drivers/media/dvb/frontends/tda10021.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/tda10021.c # # drivers/media/dvb/frontends/stv0299.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/stv0299.h # # drivers/media/dvb/frontends/stv0299.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +337 -1094 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/stv0297.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/stv0297.h # # drivers/media/dvb/frontends/stv0297.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/stv0297.c # # drivers/media/dvb/frontends/sp887x.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/sp887x.h # # drivers/media/dvb/frontends/sp887x.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +229 -310 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/sp8870.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/sp8870.h # # drivers/media/dvb/frontends/sp8870.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/sp8870.c # # drivers/media/dvb/frontends/nxt6000_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/nxt6000_priv.h # # drivers/media/dvb/frontends/nxt6000.h # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +40 -263 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/nxt6000.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +163 -469 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/mt352_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/mt352_priv.h # # drivers/media/dvb/frontends/mt352.h # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +20 -136 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/mt352.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +167 -643 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/mt312_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/mt312_priv.h # # drivers/media/dvb/frontends/mt312.h # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +19 -137 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/mt312.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +273 -449 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/l64781.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/l64781.h # # drivers/media/dvb/frontends/l64781.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/l64781.c # # drivers/media/dvb/frontends/dvb_dummy_fe.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/dvb_dummy_fe.h # # drivers/media/dvb/frontends/dvb_dummy_fe.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +189 -175 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/dib3000mb_priv.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/dib3000mb_priv.h # # drivers/media/dvb/frontends/dib3000mb.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +405 -443 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/dib3000.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/dib3000.h # # drivers/media/dvb/frontends/dib3000-common.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/dib3000-common.h # # drivers/media/dvb/frontends/cx24110.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/cx24110.h # # drivers/media/dvb/frontends/cx24110.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +288 -411 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/cx22702.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/cx22702.h # # drivers/media/dvb/frontends/cx22702.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +213 -581 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/cx22700.h # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/cx22700.h # # drivers/media/dvb/frontends/cx22700.c # 2004/12/07 16:20:26-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/cx22700.c # # drivers/media/dvb/frontends/at76c651.h # 2004/12/07 16:20:25-08:00 hunold@linuxtv.org +47 -0 # # drivers/media/dvb/frontends/at76c651.c # 2004/12/07 06:25:31-08:00 hunold@linuxtv.org +179 -289 # dvb: frontend driver refactoring # # drivers/media/dvb/frontends/at76c651.h # 2004/12/07 16:20:25-08:00 hunold@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/at76c651.h # # BitKeeper/deleted/.del-dib3000mb.h~419063f58394e051 # 2004/12/07 16:20:25-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/frontends/dib3000mb.h # # ChangeSet # 2004/12/07 16:19:51-08:00 hunold@linuxtv.org # [PATCH] dvb: collateral frontend changes # # - [DVB] get_dvb_firmware: rework to reflect new frontend design, added # additional firmware location # # - [DVB] Kconfig and Makefile changes all over the place, remove Makefile.lib # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/media/dvb/ttusb-dec/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: collateral frontend changes # # drivers/media/dvb/ttusb-budget/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: collateral frontend changes # # drivers/media/dvb/ttusb-budget/Kconfig # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +2 -0 # dvb: collateral frontend changes # # drivers/media/dvb/ttpci/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: collateral frontend changes # # drivers/media/dvb/ttpci/Kconfig # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +18 -0 # dvb: collateral frontend changes # # drivers/media/dvb/frontends/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +7 -6 # dvb: collateral frontend changes # # drivers/media/dvb/frontends/Kconfig # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +31 -90 # dvb: collateral frontend changes # # drivers/media/dvb/dvb-core/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: collateral frontend changes # # drivers/media/dvb/dibusb/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: collateral frontend changes # # drivers/media/dvb/dibusb/Kconfig # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +25 -8 # dvb: collateral frontend changes # # drivers/media/dvb/bt8xx/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: collateral frontend changes # # drivers/media/dvb/bt8xx/Kconfig # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +2 -0 # dvb: collateral frontend changes # # drivers/media/dvb/b2c2/Makefile # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +1 -1 # dvb: collateral frontend changes # # drivers/media/dvb/b2c2/Kconfig # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +2 -0 # dvb: collateral frontend changes # # drivers/media/dvb/Kconfig # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +4 -3 # dvb: collateral frontend changes # # Documentation/dvb/get_dvb_firmware # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +4 -4 # dvb: collateral frontend changes # # BitKeeper/deleted/.del-Makefile.lib~7e5fa08df14fec32 # 2004/12/07 16:19:41-08:00 hunold@linuxtv.org +0 -0 # Delete: drivers/media/dvb/dvb-core/Makefile.lib # # ChangeSet # 2004/12/07 16:19:34-08:00 hunold@linuxtv.org # [PATCH] dvb: documentation update # # Start of a big DVB update. # # # The reasons for revamping the DVB frontend architecture: # # Just as analog TV cards, DVB cards need some sort of tuner to tune to the # desired frequency of the digital transponder. Tuning alone doesn't give you a # digital DVB datastream, however, you need a demodulator as well. The # combination of tuner and demodulator is called frontend in the DVB world. # Tuner and demodulator are both accessed via the serial i2c bus on all DVB # cards out there. So, technically a frontend consists of two i2c helper # chipsets. # # In former times when there was only a handful of different DVB cards, the # frontend was encapsulated in one tin box. Some people had the idea that there # should be one "frontend driver" instead of dedicated tuner and demodulator # drivers. A bad idea. # # As time went on, different manufacturers used the same tuner and demodulator # combination, but used a different wiring for the tuner or did other technical # changes. The only possibility to support different cards with one combined # frontend driver was to add hardware dependent tuner code inside the generic # i2c frontend drivers. Yuck. # # So there was a need for communication between the i2c frontend driver and the # hardware depenedent driver, for example to exchange initialization code for # the tuner. Unfortunately, the i2c infrastructure is one way, from the i2c # client to the i2c adapter using a non-typesafe ioctl() like interface, which # is ugly by itself. Greg K-H and others refused the idea to add an iotctl() # like interface from the i2c adapter to the i2c client and instead proposed to # use a typesafe interface instead. We all agreed with that. # # The existing i2c infrastructure heavily depends on the probing facility, ie. # clients probe for their existence on i2c busses. This is dumb for most i2c # busses out there that sit on dedicated hardware. A DVB card is uniquely # identified with pci or usb subvendor and subsystem ids, so on that particular # bus we exactly *know* which kinds of i2c helper chipsets sit on there. # # Up to now this wasn't a problem, because we could fix all conflicts manually # until half a year ago. By that date, we found two different DVB designs which # used different demodulators that unfortunately use the same i2c address and # which cannot be distinguished by hardware tricks (ie. different number of # registers, some fixed hw dependent register,...) # # Getting a usable DVB card depended on the load order of the modules, because # the i2c core probed the demodulator drivers one after another and the first # one won the race. Compiling all drivers statically into the kernel resulted # in non-working cards. # # Our solution is as follows: we agreed to keep the basic underlying kernel i2c # infrastructure, but we decided not to register our bussed and chipsets to the # kernel i2c "probing" infrastructure. Instead, we killed the tuner parts of # the frontend drivers and put them into the dedicated hardware drivers (this is # were they technically belong, they are highly hardware dependent) and we # changed the frontend drivers to pure demodulator drivers (which are hardware # independend). There is now a type-safe functional dependency between the # drivers and the demodulator drivers, the drivers explicitely ask the # demodulator drivers to attach to their i2c bus. The only negative aspect of # that approach is that for some hardware there are now more dependencies to # demodulator drivers than needed, ie. a small amount of memory is wasted. # # This patch: # # - [DVB] cards.txt: added the USB devices to the card-list # - [DVB] README.dibusb: follow changes in dibusb-driver # # Signed-off-by: Michael Hunold # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # Documentation/dvb/cards.txt # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +12 -2 # dvb: documentation update # # Documentation/dvb/README.dibusb # 2004/12/07 06:25:30-08:00 hunold@linuxtv.org +77 -29 # dvb: documentation update # # ChangeSet # 2004/12/07 16:08:40-08:00 torvalds@ppc970.osdl.org # Revert double patch application. # # Heh. usually these come through Andrew, but this time it was all me. # # Noted by BenH. # # Cset exclude: paulus@samba.org[torvalds]|ChangeSet|20041207181541|44524 # # arch/ppc64/kernel/prom_init.c # 2004/12/07 16:08:38-08:00 torvalds@ppc970.osdl.org +0 -0 # Revert double patch application. # # ChangeSet # 2004/12/07 18:54:34-05:00 jgarzik@pobox.com # [libata] only DMA map data for DMA commands (fix >=4GB bug) # # libata made the assumption that (for PIO commands in this case) # it could modify DMA memory at the kernel-virtual address, after # mapping this. This is incorrect, and fails on e.g. platforms that # copy DMA memory back and forth (swiotlb on Intel EM64T and IA64). # # Remove this assumption by ensuring that we only call the DMA mapping # routines if we really are going to use DMA for data xfer. # # Also: remove a bogus WARN_ON() in ata_sg_init_one() which caused # bug reports (but no problems). # # include/linux/libata.h # 2004/12/07 18:54:23-05:00 jgarzik@pobox.com +1 -0 # [libata] only DMA map data for DMA commands (fix >=4GB bug) # # libata made the assumption that (for PIO commands in this case) # it could modify DMA memory at the kernel-virtual address, after # mapping this. This is incorrect, and fails on e.g. platforms that # copy DMA memory back and forth (swiotlb on Intel EM64T and IA64). # # Remove this assumption by ensuring that we only call the DMA mapping # routines if we really are going to use DMA for data xfer. # # Also: remove a bogus WARN_ON() in ata_sg_init_one() which caused # bug reports (but no problems). # # drivers/scsi/libata-core.c # 2004/12/07 18:54:23-05:00 jgarzik@pobox.com +34 -8 # [libata] only DMA map data for DMA commands (fix >=4GB bug) # # libata made the assumption that (for PIO commands in this case) # it could modify DMA memory at the kernel-virtual address, after # mapping this. This is incorrect, and fails on e.g. platforms that # copy DMA memory back and forth (swiotlb on Intel EM64T and IA64). # # Remove this assumption by ensuring that we only call the DMA mapping # routines if we really are going to use DMA for data xfer. # # Also: remove a bogus WARN_ON() in ata_sg_init_one() which caused # bug reports (but no problems). # # drivers/scsi/ahci.c # 2004/12/07 18:54:23-05:00 jgarzik@pobox.com +2 -1 # [libata] only DMA map data for DMA commands (fix >=4GB bug) # # libata made the assumption that (for PIO commands in this case) # it could modify DMA memory at the kernel-virtual address, after # mapping this. This is incorrect, and fails on e.g. platforms that # copy DMA memory back and forth (swiotlb on Intel EM64T and IA64). # # Remove this assumption by ensuring that we only call the DMA mapping # routines if we really are going to use DMA for data xfer. # # Also: remove a bogus WARN_ON() in ata_sg_init_one() which caused # bug reports (but no problems). # # ChangeSet # 2004/12/07 10:16:09-08:00 Andries.Brouwer@cwi.nl # [PATCH] restore BLKRRPART semantics # # In 2.6.8 the code for the BLKRRPART ioctl was changed # to return EIO when no partitions were found, such as # on an empty disk. This breaks some partitioning programs # and is also confusing: "Input/Output error" while in fact # nothing was wrong with this brand new all blank disk. # # This restores old behaviour. # # fs/partitions/check.c # 2004/12/07 03:26:28-08:00 Andries.Brouwer@cwi.nl +1 -1 # restore BLKRRPART semantics # # ChangeSet # 2004/12/07 10:15:54-08:00 alan@lxorguk.ukuu.org.uk # [PATCH] Intel/Cyrix typo # # Self explanatory.. Based on a report on l/k # # Signed-off-by: Alan Cox # Signed-off-by: Linus Torvalds # # arch/i386/Kconfig # 2004/11/25 15:06:10-08:00 alan@lxorguk.ukuu.org.uk +1 -1 # Intel/Cyrix typo # # ChangeSet # 2004/12/07 10:45:13-06:00 matthew@wil.cx # [PATCH] Blacklist devices that falsely claim an echo buffer # # A particular type of DVD is wrongly claiming to have an echo buffer # (but only if a DVD is inserted). This confuses domain validation, so # only look for an echo buffer if the device supports ppr (this is all # SCSI3 and above devices plus LVD SCSI2 devices). # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_transport_spi.c # 2004/12/06 14:51:40-06:00 matthew@wil.cx +5 -1 # Blacklist devices that falsely claim an echo buffer # # ChangeSet # 2004/12/07 08:07:09-08:00 kernel-stuff@comcast.net # [PATCH] ohci1394.c - Correct kmalloc usage in interrupt # # alloc_dma_rcv_ctx is called in interrupt and Kernel Spinlock debugging code # cribs about it via "Debug: sleeping function called in interrupt context". # See sample stack traces below. # # The patch below corrects ohci1394.c to use GFP_ATOMIC instead of # GFP_KERNEL. Tested to work fine with 2 different Camcorder devices for # fairly long periods and connect/disconnects. # # Signed-off-by: Parag Warudkar # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/ieee1394/ohci1394.c # 2004/12/07 01:01:17-08:00 kernel-stuff@comcast.net +5 -5 # ohci1394.c - Correct kmalloc usage in interrupt # # ChangeSet # 2004/12/07 08:06:56-08:00 tiwai@suse.de # [PATCH] alsa: fix iomem mmap # # The patch adds the definition vm_private_data again to # snd_pcm_lib_mmap_iomem(). It got lost during the rewrite of the mmap # stuff. # # Signed-off-by: Martin Langer # Signed-off-by: Takashi Iwai # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # sound/core/pcm_native.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +1 -0 # alsa: fix iomem mmap # # ChangeSet # 2004/12/07 08:06:43-08:00 tiwai@suse.de # [PATCH] alsa: add pci_disable_device() to removal and error paths # # pci_disable_device() is called properly in the removal and error paths. # Also, the pci_set_master() is added to the resume callbacks if missing # (just to be sure). # # Signed-off-by: Takashi Iwai # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # sound/pci/ymfpci/ymfpci_main.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +5 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/vx222/vx222.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +4 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/via82xx.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +5 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/trident/trident_main.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +7 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/sonicvibes.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/rme9652/rme9652.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +1 -0 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/rme9652/hdsp.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +1 -0 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/rme96.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +1 -0 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/rme32.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +1 -0 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/nm256/nm256.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +8 -4 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/mixart/mixart.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/maestro3.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +9 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/korg1212/korg1212.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +20 -4 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/intel8x0m.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/intel8x0.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/ice1712/ice1724.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +5 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/ice1712/ice1712.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/fm801.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +5 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/es1968.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +8 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/es1938.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +7 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/ens1370.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +5 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/emu10k1/emu10k1_main.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/cs46xx/cs46xx_lib.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/cs4281.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +7 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/cmipci.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +5 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/bt87x.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +5 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/azt3328.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/atiixp_modem.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/atiixp.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/als4000.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # sound/pci/ali5451/ali5451.c # 2004/12/07 01:01:17-08:00 tiwai@suse.de +6 -1 # alsa: add pci_disable_device() to removal and error paths # # ChangeSet # 2004/12/07 08:06:26-08:00 tiwai@suse.de # [PATCH] alsa: fix sleep in atomic during prepare callback # # Fixed the sleep in spinlock during prepare callback. This happened only on # Nforce chips. # # Signed-off-by: Takashi Iwai # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # sound/pci/intel8x0.c # 2004/12/07 02:01:42-08:00 tiwai@suse.de +2 -0 # alsa: fix sleep in atomic during prepare callback # # ChangeSet # 2004/12/07 08:06:13-08:00 trini@kernel.crashing.org # [PATCH] ppc32: fix Motorola PReP (PowerstackII Utah) PCI IRQ map # # The PCI IRQ map for the old Motorola PowerStackII (Utah) boards was # incorrect, but this breakage wasn't exposed until 2.5, and finally fixed # until recently by Sebastian Heutling . # # Signed-off-by: Christian Kujau # Signed-off-by: Tom Rini # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # arch/ppc/platforms/prep_pci.c # 2004/12/07 01:01:16-08:00 trini@kernel.crashing.org +3 -3 # ppc32: fix Motorola PReP (PowerstackII Utah) PCI IRQ map # # ChangeSet # 2004/12/07 08:06:01-08:00 mike.miller@hp.com # [PATCH] cciss: cciss_ioctl return code fix # # This patches fixes the return code from cciss_ioctl. Without this some # block layer (BLK*) ioctls do not work. # # Thanks to Jens Axboe for pointing this out. # # Signed-off-by: Mike Miller # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/block/cciss.c # 2004/12/07 01:01:16-08:00 mike.miller@hp.com +1 -1 # cciss: cciss_ioctl return code fix # # ChangeSet # 2004/12/07 08:05:47-08:00 paulus@samba.org # [PATCH] PPC64: close firmware stdin # # We recently found a problem that was causing memory corruption during boot # on IBM POWER5 machines. The problem was that the if you have a USB # keyboard and it is set to the input device for the firmware, it will still # be active when the kernel is started. That means that the OHCI controller # has pointers to various memory areas that it polls for transfers to do. # When we start using that same memory in the kernel, bad things can happen. # (This isn't a problem on powermacs because the Apple OF implements a # "quiesce" call which turns off all the devices it is using.) # # This patch fixes the problem by calling the Open Firmware "close" method # for the input device. Stephen Rothwell and I have verified that doing this # fixes the problem on the POWER5 machine where we observed it. I verified # that this patch doesn't cause any problems on powermacs. # # I think this patch should go into 2.6.10 since it fixes a nasty memory # corruption bug that can cause rather subtle and hard-to-diagnose problems # during boot. (The symptom on the POWER5 machine with the particular kernel # that we were using was that reading /proc/net/tcp would oops, due to one of # the pointers in tcp_ehash being corrupted.) # # Signed-off-by: Paul Mackerras # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # arch/ppc64/kernel/prom_init.c # 2004/12/07 01:01:16-08:00 paulus@samba.org +13 -0 # PPC64: close firmware stdin # # ChangeSet # 2004/12/07 08:05:35-08:00 shaohua.li@intel.com # [PATCH] eepro100 resume failure # # Fix eepro100 driver suspend/resume issue. # # Signed-off-by: Li Shaohua # Cc: Jeff Garzik # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/net/eepro100.c # 2004/12/07 01:00:14-08:00 shaohua.li@intel.com +5 -0 # eepro100 resume failure # # ChangeSet # 2004/12/07 08:05:21-08:00 axboe@suse.de # [PATCH] cfq-iosched: bad accounting on non-fs requests # # Current cfq can cause hangs with non-fs requests, because the accounting # goes bad. This fixes it. # # Signed-off-by: Jens Axboe # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/block/cfq-iosched.c # 2004/12/07 01:00:14-08:00 axboe@suse.de +6 -0 # cfq-iosched: bad accounting on non-fs requests # # ChangeSet # 2004/12/07 08:05:08-08:00 geert@linux-m68k.org # [PATCH] M68k: Update defconfigs for 2.6.10-rc3 # # M68k: Update defconfigs for 2.6.10-rc3 # # Signed-off-by: Geert Uytterhoeven # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # arch/m68k/defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +7 -2 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/sun3x_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +8 -3 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/sun3_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +8 -3 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/q40_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +8 -3 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/mvme16x_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +8 -3 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/mvme147_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +7 -2 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/mac_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +7 -2 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/hp300_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +7 -2 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/bvme6000_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +7 -2 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/atari_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +8 -3 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/apollo_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +7 -2 # M68k: Update defconfigs for 2.6.10-rc3 # # arch/m68k/configs/amiga_defconfig # 2004/12/07 01:00:13-08:00 geert@linux-m68k.org +8 -3 # M68k: Update defconfigs for 2.6.10-rc3 # # ChangeSet # 2004/12/07 08:04:56-08:00 romieu@fr.zoreil.com # [PATCH] r8169: new PCI id # # The D-Link DGE-528T gigabit adapter is based on the 8169 chipset (reported # by Andreas Tauscher , checked in the sources of a # driver for this adapter). # # Signed-off-by: Francois Romieu # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/net/r8169.c # 2004/12/07 01:00:13-08:00 romieu@fr.zoreil.com +1 -0 # r8169: new PCI id # # ChangeSet # 2004/12/07 08:04:30-08:00 benh@kernel.crashing.org # [PATCH] remove some PowerMac cruft from USB # # The PowerMac specific sleep code in the OHCI USB driver used to call # disable/enable irq, which is no longer necessary and actually clashes with # the calls to free/request_irq that the common OHCI code now does, thus # causing WARN_ON's to trigger each time a PowerBook is woken up from sleep. # # Signed-off-by: Benjamin Herrenschmidt # Cc: David Brownell # Cc: Greg KH # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/usb/host/ohci-pci.c # 2004/12/07 00:59:48-08:00 benh@kernel.crashing.org +4 -13 # remove some PowerMac cruft from USB # # ChangeSet # 2004/12/07 08:04:18-08:00 fenghua.yu@intel.com # [PATCH] Add cpu_relax in idle spin loop for no-hlt kernel option # # If given no-hlt kernel option, ia32 idle loop turns out to be a spin loop. # Add cpu_relax() in this spin loop because IA32 SDM recommends that a PAUSE # instruction be put in all spin loops. # # Signed-off-by: Fenghua Yu # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # arch/i386/kernel/process.c # 2004/12/07 00:59:46-08:00 fenghua.yu@intel.com +2 -0 # Add cpu_relax in idle spin loop for no-hlt kernel option # # ChangeSet # 2004/12/07 08:04:05-08:00 santil@us.ibm.com # [PATCH] fix buffer starvation race in ibmveth # # There's a chance that the receive buffers are being consumed at the same # rate as they are being replenished in ibmveth_replenish_task()... # Meanwhile, the calls to schedule_replenishing() from ibmveth_poll() won't # schedule another replenishing cycle (because the not_replenishing flag is # zero), starving the buffers and making the adapter unable to receive # packets unless the module is reloaded... Here's a small patch that will # fix it by scheduling another replenishing task after toggling the # not_replenishing flag. # # Signed-Off-By: Santiago Leon # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # drivers/net/ibmveth.c # 2004/12/07 00:59:45-08:00 santil@us.ibm.com +4 -1 # fix buffer starvation race in ibmveth # # ChangeSet # 2004/12/07 08:03:52-08:00 herbert@13thfloor.at # [PATCH] normalise wall_to_monotonic for i386 and m32r # # Fix the non-normalized wall_to_monotonic for i386 and m32r (The other archs # seem to get it right) # # Signed-off-by: Herbert Poetzl # Signed-off-by: George Anzinger # Signed-off-by: Andrew Morton # Signed-off-by: Linus Torvalds # # arch/m32r/kernel/time.c # 2004/12/07 00:58:56-08:00 herbert@13thfloor.at +2 -2 # normalise wall_to_monotonic for i386 and m32r # # arch/i386/kernel/time.c # 2004/12/07 00:58:56-08:00 herbert@13thfloor.at +4 -4 # normalise wall_to_monotonic for i386 and m32r # # ChangeSet # 2004/12/07 09:15:15-06:00 aherrman@de.ibm.com # [PATCH] zfcp: act enhancements corrections # # - corrects errors introduced in open_unit_handler # with last patch submission for act enhancements, # - changes formatting and some log-messages in act # enhancments code, # - removes junk lines # - corrected Kconfig dependency for zfcp # - do not wait for SBALs when creating ELS requests # # Signed-off-by: Andreas Herrmann # Signed-off-by: James Bottomley # # drivers/scsi/Kconfig # 2004/12/07 04:19:06-06:00 aherrman@de.ibm.com +1 -1 # zfcp: act enhancements corrections # # drivers/s390/scsi/zfcp_scsi.c # 2004/12/07 04:19:06-06:00 aherrman@de.ibm.com +1 -2 # zfcp: act enhancements corrections # # drivers/s390/scsi/zfcp_fsf.c # 2004/12/07 04:19:06-06:00 aherrman@de.ibm.com +4 -49 # zfcp: act enhancements corrections # # drivers/s390/scsi/zfcp_ext.h # 2004/12/07 04:19:06-06:00 aherrman@de.ibm.com +2 -2 # zfcp: act enhancements corrections # # drivers/s390/scsi/zfcp_erp.c # 2004/12/07 04:19:06-06:00 aherrman@de.ibm.com +18 -20 # zfcp: act enhancements corrections # # drivers/s390/scsi/zfcp_def.h # 2004/12/07 04:19:06-06:00 aherrman@de.ibm.com +2 -2 # zfcp: act enhancements corrections # # ChangeSet # 2004/12/06 11:49:45-06:00 mike.miller@hp.com # [PATCH] cciss: cciss_ioctl return code fix # # This patches fixes the return code from cciss_ioctl. Without this some # block layer (BLK*) ioctls do not work. Please consider this for inclusion. # # Thanks to Jens Axboe for pointing this out. # # Signed-off-by: Mike Miller # Signed-off-by: James Bottomley # # drivers/block/cciss.c # 2004/12/06 09:39:18-06:00 mike.miller@hp.com +1 -1 # cciss: cciss_ioctl return code fix # # ChangeSet # 2004/12/06 11:45:38-06:00 jejb@mulgrave.(none) # SCSI: spi_transport set_signalling is buggy # # From: Matthew Wilcox # # Looks like you got the test backwards. It would only call set_signalling # if type was SPI_SIGNAL_UNKNOWN. # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_transport_spi.c # 2004/12/06 11:44:16-06:00 jejb@mulgrave.(none) +1 -2 # SCSI: spi_transport set_signalling is buggy # # ChangeSet # 2004/12/06 10:24:45-06:00 dougg@torque.net # [PATCH] extracting resid from struct scsi_cmnd # # - during successful command completion place resid from SCSI # LLDs into request::data_len so that block SG_IO ioctl reports # resid # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_lib.c # 2004/11/28 06:12:22-06:00 dougg@torque.net +1 -1 # extracting resid from struct scsi_cmnd # # ChangeSet # 2004/12/06 15:55:27+00:00 dvrabel@com.rmk.(none) # [ARM PATCH] 2298/1: Fix minor typo in ixp4xx_wdt # # Patch from David Vrabel # # Fix a minor typo in the MODULE_AUTHOR string in ixp4xx_wdt. # # Signed-off-by: David Vrabel # Signed-off-by: Russell King # # drivers/char/watchdog/ixp4xx_wdt.c # 2004/12/03 17:09:54+00:00 dvrabel@com.rmk.(none) +1 -1 # [PATCH] 2298/1: Fix minor typo in ixp4xx_wdt # # ChangeSet # 2004/12/06 09:38:48-06:00 jejb@mulgrave.(none) # aic7xxx: fix compiler warning from dma mask assignement # # Promote all the mask quantites to being u64 so that # they never cause truncation warnings. # # Signed-off-by: James Bottomley # # drivers/scsi/aic7xxx/aic7xxx_osm_pci.c # 2004/12/06 09:38:05-06:00 jejb@mulgrave.(none) +3 -4 # aic7xxx: fix compiler warning from dma mask assignement # # drivers/scsi/aic7xxx/aic7xxx_osm.h # 2004/12/06 09:38:05-06:00 jejb@mulgrave.(none) +1 -1 # aic7xxx: fix compiler warning from dma mask assignement # # drivers/scsi/aic7xxx/aic79xx_osm_pci.c # 2004/12/06 09:38:05-06:00 jejb@mulgrave.(none) +6 -8 # aic7xxx: fix compiler warning from dma mask assignement # # drivers/scsi/aic7xxx/aic79xx_osm.h # 2004/12/06 09:38:05-06:00 jejb@mulgrave.(none) +1 -1 # aic7xxx: fix compiler warning from dma mask assignement # # ChangeSet # 2004/12/06 10:48:06+01:00 marcel@holtmann.org # [Bluetooth] Use module parameter for ISOC alternate setting # # The module parameter for the ISOC transfers now chooses the value # of the alternate setting. # # Signed-off-by: Marcel Holtmann # # drivers/bluetooth/hci_usb.c # 2004/12/06 10:45:28+01:00 marcel@holtmann.org +3 -3 # Use module parameter for ISOC alternate setting # # ChangeSet # 2004/12/06 10:39:53+01:00 marcel@holtmann.org # [Bluetooth] Track the class of device value # # The class of device is only available from an inquiry response or # from the connection request. In the case of an incoming connection # the value can be taken from the request and stored in the hci_conn # structure. For an outgoing connection the value from the inquiry # cache is used or it is set to zero. # # Signed-off-by: Marcel Holtmann # # net/bluetooth/hci_event.c # 2004/12/06 10:36:25+01:00 marcel@holtmann.org +1 -0 # Track the class of device value # # net/bluetooth/hci_conn.c # 2004/12/06 10:36:21+01:00 marcel@holtmann.org +1 -0 # Track the class of device value # # include/net/bluetooth/hci_core.h # 2004/12/06 10:36:13+01:00 marcel@holtmann.org +1 -0 # Track the class of device value # # ChangeSet # 2004/12/06 09:18:04+01:00 marcel@holtmann.org # [Bluetooth] Use separate inquiry data structure # # The inquiry results can return different fields and so create one # data structure that has place for every of these. Missing fields # are filled with default values. # # Signed-off-by: Marcel Holtmann # # net/bluetooth/hci_sysfs.c # 2004/12/06 09:16:21+01:00 marcel@holtmann.org +6 -6 # Use separate inquiry data structure # # net/bluetooth/hci_event.c # 2004/12/06 09:16:20+01:00 marcel@holtmann.org +21 -10 # Use separate inquiry data structure # # net/bluetooth/hci_conn.c # 2004/12/06 09:16:18+01:00 marcel@holtmann.org +3 -3 # Use separate inquiry data structure # # net/bluetooth/hci_core.c # 2004/12/06 09:16:16+01:00 marcel@holtmann.org +15 -7 # Use separate inquiry data structure # # include/net/bluetooth/hci_core.h # 2004/12/06 09:15:52+01:00 marcel@holtmann.org +12 -2 # Use separate inquiry data structure # # ChangeSet # 2004/12/05 21:20:56-08:00 davem@nuts.davemloft.net # [SPARC]: Fix syscall return value errno comparison. # # This was hosing all restart block handling. # # Noticed by Richard Mortimer. # # Signed-off-by: David S. Miller # # arch/sparc64/solaris/entry64.S # 2004/12/05 21:19:35-08:00 davem@nuts.davemloft.net +1 -1 # [SPARC]: Fix syscall return value errno comparison. # # arch/sparc64/kernel/entry.S # 2004/12/05 21:19:35-08:00 davem@nuts.davemloft.net +1 -1 # [SPARC]: Fix syscall return value errno comparison. # # arch/sparc/kernel/entry.S # 2004/12/05 21:19:35-08:00 davem@nuts.davemloft.net +3 -3 # [SPARC]: Fix syscall return value errno comparison. # # ChangeSet # 2004/12/05 23:11:34+00:00 elf@com.rmk.(none) # [ARM PATCH] 2297/1: SMC91x patch (#2) for LPD7a40x CardEngines # # Patch from Marc Singer # # Add support for the LPD7a40x implementation of the SMC91x ethernet # controller. This patch exists to work around a mismatch between the # way the LH7a40x CPUs handle chip selects and what the ethernet # controller expects. # # This patch has been revised to eliminate masking of interrupts. The # concessions are that # # a) the ISR must perform an IOBARRIER before the first access to the # chip, just in case the interrupt occurred while the driver was # writing to the chip # b) other drivers that use the same chip select region as the SMC # chip must perform a similar IOBARRIER at the top of their ISRs. # # Signed-off-by: Marc Singer # Signed-off-by: Russell King # # drivers/net/smc91x.h # 2004/12/05 22:25:52+00:00 elf@com.rmk.(none) +50 -0 # [PATCH] 2297/1: SMC91x patch (#2) for LPD7a40x CardEngines # # drivers/net/smc91x.c # 2004/12/05 22:25:52+00:00 elf@com.rmk.(none) +5 -0 # [PATCH] 2297/1: SMC91x patch (#2) for LPD7a40x CardEngines # # Documentation/arm/Sharp-LH/IOBarrier # 2004/12/05 22:25:52+00:00 elf@com.rmk.(none) +23 -10 # [PATCH] 2297/1: SMC91x patch (#2) for LPD7a40x CardEngines # # ChangeSet # 2004/12/05 16:36:40+00:00 elf@com.rmk.(none) # [ARM PATCH] 2296/1: Corrections to build for LPD7a404 # # Patch from Marc Singer # # A missing exten prevented the 2.6.10-rc2 kernel from building for the # LPD7A404. This patch adds it. # # Signed-off-by: Marc Singer # Signed-off-by: Russell King # # arch/arm/mach-lh7a40x/common.h # 2004/12/05 07:10:02+00:00 elf@com.rmk.(none) +9 -4 # [PATCH] 2296/1: Corrections to build for LPD7a404 # # ChangeSet # 2004/12/05 08:32:07-08:00 gandalf@wlug.westbo.se # [PATCH] Fix ALSA resume # # Some time ago, a patch was merged that removed pci_save_state() and # pci_restore_state() from various ALSA drivers. That patch also added # pci_restore_state() to sound/core/init.c but didn't add pci_save_state() # anywhere. This is needed since the core pci handling doesn't do this for # us anymore. # # My laptop doesn't resume (gets what I assume is an ACPI timeout and # hangs solid) without this small obvious patch. # # Signed-off-by: Martin Josefsson # Fixed-by: Takashi Iwai # Signed-off-by: Linus Torvalds # # sound/core/init.c # 2004/11/12 05:56:32-08:00 gandalf@wlug.westbo.se +4 -1 # Fix ALSA resume # # ChangeSet # 2004/12/05 16:31:17+00:00 zecke@org.rmk.(none) # [ARM PATCH] 2294/1: SA1100 ide.h change superseed 2282/1 # # Patch from Holger Hans Peter Freyther # # As proposed in 2282 asm-arm/arch-sa1100/ide.h is not included anymore from asm-arm/ide.h. # If arch-sa1100/ide.h is included we abort with #error. # If lart.c is compiled we kindly warn that ide needs fixing for this board. # # # Signed-off-by: Holger Hans Peter Freyther # Signed-off-by: Russell King # # include/asm-arm/ide.h # 2004/12/04 23:18:07+00:00 zecke@org.rmk.(none) +0 -4 # [PATCH] 2294/1: SA1100 ide.h change superseed 2282/1 # # include/asm-arm/arch-sa1100/ide.h # 2004/12/04 23:18:07+00:00 zecke@org.rmk.(none) +2 -0 # [PATCH] 2294/1: SA1100 ide.h change superseed 2282/1 # # arch/arm/mach-sa1100/lart.c # 2004/12/04 23:18:07+00:00 zecke@org.rmk.(none) +2 -0 # [PATCH] 2294/1: SA1100 ide.h change superseed 2282/1 # # ChangeSet # 2004/12/05 16:25:39+00:00 elf@com.rmk.(none) # [ARM PATCH] 2293/1: Corrections to build for LPD7a400 # # Patch from Marc Singer # # Some typos prevent the 2.6.10-rc2 kernel from building for the # LPD7A400. This patch fixes them. It also removes CONFIG_FIQ which # shouldn't be necessary and doesn't compile. # # Signed-off-by: Marc Singer # Signed-off-by: Russell King # # arch/arm/mach-lh7a40x/time.c # 2004/12/04 21:01:02+00:00 elf@com.rmk.(none) +1 -1 # [PATCH] 2293/1: Corrections to build for LPD7a400 # # arch/arm/mach-lh7a40x/arch-lpd7a40x.c # 2004/12/04 21:01:02+00:00 elf@com.rmk.(none) +2 -2 # [PATCH] 2293/1: Corrections to build for LPD7a400 # # arch/arm/Kconfig # 2004/12/04 21:01:02+00:00 elf@com.rmk.(none) +1 -1 # [PATCH] 2293/1: Corrections to build for LPD7a400 # # ChangeSet # 2004/12/04 19:34:20-08:00 davem@nuts.davemloft.net # [SPARC64]: Fix SMP cpu bringup bug when bigkernel. # # We have to load the bigkernel second TLB entry on # secondary processors before we move over the use # the kernel trap table. Otherwise we can take a # TLB miss somewhere in the post-4MB area and the # TLB handler is not prepared to service that. # # The case that usually occurs is the prom_set_trap_table # call made by trampoline.S, since p1275buf usually sits # very near the end of the kernel image. It worked by # luck most of the time as long as p1275buf sits within # a single page since earlier code running in trampoline.S # forced that TLB entry to be loaded by the OBP TLB miss # handler. # # This was not fun to figure out. # # Signed-off-by: David S. Miller # # arch/sparc64/kernel/trampoline.S # 2004/12/04 19:33:42-08:00 davem@nuts.davemloft.net +84 -1 # [SPARC64]: Fix SMP cpu bringup bug when bigkernel. # # arch/sparc64/kernel/smp.c # 2004/12/04 19:33:42-08:00 davem@nuts.davemloft.net +0 -9 # [SPARC64]: Fix SMP cpu bringup bug when bigkernel. # # ChangeSet # 2004/12/04 21:09:09+00:00 rmk@flint.arm.linux.org.uk # [SERIAL] Ensure correct units for close_delay and closing_wait. # # Use milliseconds internally for these delays, and convert them # to centiseconds at the interface boundary to the ioctl # configuration controls. # # include/linux/serial_core.h # 2004/12/04 21:06:05+00:00 rmk@flint.arm.linux.org.uk +3 -3 # closing_wait and close_delay are in milliseconds. # # drivers/serial/serial_core.c # 2004/12/04 21:06:04+00:00 rmk@flint.arm.linux.org.uk +18 -14 # Ensure correct units for close_delay and closing_wait. # # ChangeSet # 2004/12/03 22:32:50+00:00 rmk@flint.arm.linux.org.uk # [ARM] Add per_cpu data area to linker script. # # arch/arm/kernel/vmlinux.lds.S # 2004/12/03 22:29:38+00:00 rmk@flint.arm.linux.org.uk +4 -0 # Add per_cpu data area. # # ChangeSet # 2004/12/03 22:22:04+00:00 rmk@flint.arm.linux.org.uk # [ARM] Ensure user ops pass 64-bit constants in even,odd registers. # # Always pass values to get_user and put_user in an even numbered # register, and optionally the next odd numbered register. This # ensures that we are compatible with compiler enhancements. # # include/asm-arm/uaccess.h # 2004/12/03 22:18:49+00:00 rmk@flint.arm.linux.org.uk +17 -17 # Pass/retrieve values in r2,r3 not r1,r2 # # arch/arm/lib/putuser.S # 2004/12/03 22:18:48+00:00 rmk@flint.arm.linux.org.uk +8 -8 # Pass values in r2,r3 not r1,r2 # # arch/arm/lib/getuser.S # 2004/12/03 22:18:48+00:00 rmk@flint.arm.linux.org.uk +11 -11 # Return values in r2,r3 not r1,r2 # # ChangeSet # 2004/12/03 16:38:42+00:00 ben-linux@org.rmk.(none) # [ARM PATCH] 2290/1: S3C2410 - timer usec fixes # # Patch from Ben Dooks # # A simple divide is not enough for the s3c2410 default # timer code, due to most clocks not being a nice multiple # of usecs. # # This update changes the calculation of the usec to use # multipliers and shifts to effect a fast divide by a non-integer # number. # # Original patch by Dimitry Andric, updated by Ben Dooks # # Signed-off-by: Dimitry Andric # # Signed-off-by: Ben Dooks # Signed-off-by: Russell King # # arch/arm/mach-s3c2410/time.c # 2004/12/02 18:20:17+00:00 ben-linux@org.rmk.(none) +69 -20 # [PATCH] 2290/1: S3C2410 - timer usec fixes # # ChangeSet # 2004/11/29 13:44:23+00:00 rmk@flint.arm.linux.org.uk # [SERIAL] Add missing definition for PORT_IMX. # # include/linux/serial_core.h # 2004/11/29 13:41:34+00:00 rmk@flint.arm.linux.org.uk +5 -2 # Add definition for PORT_IMX. # # ChangeSet # 2004/11/26 11:56:57-06:00 jejb@mulgrave.(none) # support for 3PAR sparse SCSI LUNs # # From: Castor Fu # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_devinfo.c # 2004/11/26 11:56:27-06:00 jejb@mulgrave.(none) +1 -0 # support for 3PAR sparse SCSI LUNs # # ChangeSet # 2004/11/25 15:01:22-06:00 jejb@mulgrave.(none) # mptfusion: kill fusion init called # # From: Moore, Eric Dean # # The scsi early init problem is long gone, # so no need to work around it anymore. # This patch previously submitted by hch@. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # drivers/message/fusion/mptbase.h # 2004/11/25 15:00:43-06:00 jejb@mulgrave.(none) +2 -2 # mptfusion: kill fusion init called # # drivers/message/fusion/mptbase.c # 2004/11/25 15:00:43-06:00 jejb@mulgrave.(none) +0 -22 # mptfusion: kill fusion init called # # ChangeSet # 2004/11/25 14:58:06-06:00 jejb@mulgrave.(none) # mptfusion: resid cleanup # # From: Moore, Eric Dean # # This cleanup returns residual for all completed # scsi io. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # drivers/message/fusion/mptscsih.c # 2004/11/25 14:56:15-06:00 jejb@mulgrave.(none) +9 -15 # mptfusion: resid cleanup # # ChangeSet # 2004/11/25 14:50:32-06:00 jejb@mulgrave.(none) # mptfusion: command line parameters # # This cleans up the command line parameters # with individual parameters and descriptions. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # drivers/message/fusion/mptscsih.h # 2004/11/25 14:50:08-06:00 jejb@mulgrave.(none) +1 -10 # mptfusion: command line parameters # # drivers/message/fusion/mptscsih.c # 2004/11/25 14:50:08-06:00 jejb@mulgrave.(none) +30 -118 # mptfusion: command line parameters # # ChangeSet # 2004/11/25 14:47:00-06:00 jejb@mulgrave.(none) # mptfusion: replace chip_type # # From: Moore, Eric Dean # # This replaces chip_type with bus_type. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # drivers/message/fusion/mptscsih.c # 2004/11/25 14:46:31-06:00 jejb@mulgrave.(none) +16 -19 # mptfusion: replace chip_type # # drivers/message/fusion/mptctl.c # 2004/11/25 14:46:31-06:00 jejb@mulgrave.(none) +4 -4 # mptfusion: replace chip_type # # drivers/message/fusion/mptbase.h # 2004/11/25 14:46:31-06:00 jejb@mulgrave.(none) +7 -19 # mptfusion: replace chip_type # # drivers/message/fusion/mptbase.c # 2004/11/25 14:46:31-06:00 jejb@mulgrave.(none) +22 -39 # mptfusion: replace chip_type # # ChangeSet # 2004/11/25 14:44:57-06:00 jejb@mulgrave.(none) # mptfusion: streamline queuecommand # # From: Moore, Eric Dean # # This cleans up mptscsih_qcmd function. # This patch previously submitted by hch@. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # drivers/message/fusion/mptscsih.c # 2004/11/25 14:44:07-06:00 jejb@mulgrave.(none) +45 -55 # mptfusion: streamline queuecommand # # ChangeSet # 2004/11/25 14:42:16-06:00 jejb@mulgrave.(none) # mptfusion: streamline slave_alloc # # From: Moore, Eric Dean # # This cleans up slave_xxx functions. # This patch previously submitted by hch@. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # drivers/message/fusion/mptscsih.c # 2004/11/25 14:41:34-06:00 jejb@mulgrave.(none) +66 -92 # mptfusion: streamline slave_alloc # # ChangeSet # 2004/11/25 11:53:00-06:00 jejb@mulgrave.(none) # mptfusion: delete MPTSCSIH_DBG_TIMEOUT # # From: Moore, Eric Dean # # This removes MPTSCSIH_DBG_TIMEOUT associated # code in the driver. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # drivers/message/fusion/mptscsih.c # 2004/11/25 11:49:11-06:00 jejb@mulgrave.(none) +4 -180 # mptfusion: delete MPTSCSIH_DBG_TIMEOUT # # drivers/message/fusion/mptbase.h # 2004/11/25 11:49:11-06:00 jejb@mulgrave.(none) +0 -6 # mptfusion: delete MPTSCSIH_DBG_TIMEOUT # # ChangeSet # 2004/11/25 11:45:09-06:00 markh@osdl.org # [PATCH] 2.6.9 aacraid: Support ROMB RAID/SCSI mode - Resend - # # Another patch from Mark Salyzyn's driver. Supports correct operation of # ROMB (RAID on motherboard) SCSI/RAID. Applies to the scsi-misc bk tree. # # Signed-off-by: Mark Haverkamp # Signed-off-by: James Bottomley # # drivers/scsi/aacraid/aacraid.h # 2004/10/20 15:35:27-05:00 markh@osdl.org +3 -0 # 2.6.9 aacraid: Support ROMB RAID/SCSI mode - Resend - # # drivers/scsi/aacraid/aachba.c # 2004/10/21 11:53:08-05:00 markh@osdl.org +43 -3 # 2.6.9 aacraid: Support ROMB RAID/SCSI mode - Resend - # diff -Nru a/Documentation/arm/Sharp-LH/IOBarrier b/Documentation/arm/Sharp-LH/IOBarrier --- a/Documentation/arm/Sharp-LH/IOBarrier 2004-12-12 17:40:52 -08:00 +++ b/Documentation/arm/Sharp-LH/IOBarrier 2004-12-12 17:40:52 -08:00 @@ -5,7 +5,7 @@ the signals that control access to some peripherals, most notably the SMC91C9111 ethernet controller, are not properly handled. -The symptom is that back to back IO with the peripheral returns +The symptom is that some back to back IO with the peripheral returns unreliable data. With the SMC chip, you'll see errors about the bank register being 'screwed'. @@ -13,20 +13,33 @@ for every memory access. It is driven through the CPLD from the CS7 line of the CPU's static memory controller which is optimized to eliminate unnecessary transitions. Yet, the SMC requires a transition -for every access. The Sharp website has more information on the -effect of this power conservation feature on peripheral interfacing. +for every write access. The Sharp website has more information about +the effect this power-conserving feature has on peripheral +interfacing. -The solution is to follow every access to the SMC chip with an access -to another memory region that will force the CPU to release the chip -select line. Note that it is important to guarantee that the access -will force the CPU off-chip. We map a page of SDRAM as if it were an -uncacheable IO device and read from it after every SMC IO operation. +The solution is to follow every write access to the SMC chip with an +access to another memory region that will force the CPU to release the +chip select line. It is important to guarantee that this access +forces the CPU off-chip. We map a page of SDRAM as if it were an +uncacheable IO device and read from it after every SMC IO write +operation. SMC IO BARRIER IO -You might be tempted to believe that we must access another device +Only this sequence is important. It does not matter that there is no +BARRIER IO before the access to the SMC chip because the AEN latch +only needs occurs after the SMC IO write cycle. The routines that +implement this work-around make an additional concession which is to +disable interrupts during the IO sequence. Other hardware devices +(the LogicPD CPLD) have registers in the same the physical memory +region as the SMC chip. An interrupt might allow an access to one of +those registers while SMC IO is being performed. + +You might be tempted to think that we have to access another device attached to the static memory controller, but the empirical evidence indicates that this is not so. Mapping 0x00000000 (flash) and 0xc0000000 (SDRAM) appear to have the same effect. Using SDRAM seems -to be faster. +to be faster. Choosing to access an undecoded memory region is not +desirable as there is no way to know how that chip select will be used +in the future. diff -Nru a/Documentation/dvb/README.dibusb b/Documentation/dvb/README.dibusb --- a/Documentation/dvb/README.dibusb 2004-12-12 17:40:52 -08:00 +++ b/Documentation/dvb/README.dibusb 2004-12-12 17:40:52 -08:00 @@ -1,43 +1,82 @@ +Documentation for dib3000mb frontend driver and dibusb device driver +==================================================================== +Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de), -Documentation for dib3000mb frontend driver and dibusb device driver +dibusb and dib3000mb/mc drivers based on GPL code, which has -The drivers should work with +Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) -- Twinhan VisionPlus VisionDTV USB-Ter DVB-T Device (VP7041) - http://www.twinhan.com/ +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. -- CTS Portable (Chinese Television System) - http://www.2cts.tv/ctsportable/ -- KWorld V-Stream XPERT DTV - DVB-T USB - http://www.kworld.com.tw/asp/pindex.asp?id=4&pid=13 +Supported devices USB1.1 +======================== + +Produced and reselled by Twinhan: +--------------------------------- +- TwinhanDTV USB-Ter DVB-T Device (VP7041) + http://www.twinhan.com/product_terrestrial_3.asp + +- TwinhanDTV Magic Box (VP7041e) + http://www.twinhan.com/product_terrestrial_4.asp - HAMA DVB-T USB device http://www.hama.de/portal/articleId*110620/action*2598 -- DiBcom USB DVB-T reference device +- CTS Portable (Chinese Television System) + http://www.2cts.tv/ctsportable/ + +- Unknown USB DVB-T device with vendor ID Hyper-Paltek + + +Produced and reselled by KWorld: +-------------------------------- +- KWorld V-Stream XPERT DTV DVB-T USB + http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html -- Ultima Electronic/Artec T1 USB TVBOX +- JetWay DTV DVB-T USB + http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm + +- ADSTech Instant TV DVB-T USB + http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333 + + +Others: +------- +- Ultima Electronic/Artec T1 USB TVBOX (AN2135 and AN2235) http://www.arteceuro.com/products-tvbox.html - Compro Videomate DVB-U2000 - DVB-T USB http://www.comprousa.com/products/vmu2000.htm -- Unknown USB DVB-T device with vendor ID Hyper-Paltek +- Grandtec USB DVB-T + http://www.grand.com.tw/ -Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de), +- Avermedia AverTV DVBT USB + http://www.avermedia.com/ -both drivers based on GPL code, which has +- DiBcom USB DVB-T reference device (non-public) -Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) -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. +Supported devices USB2.0 +======================== +- Yakumo DVB-T mobile + http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T + +- DiBcom USB2.0 DVB-T reference device (non-public) -NEWS: + +0. NEWS: + 2004-11-07 - added remote control support. Thanks to David Matthews. + 2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec) + - merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD + - moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems + better settled there (added xfer_ops-struct) + - created a common files for frontends (mc/p/mb) 2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek) 2004-09-20 - added support for a new device (Compro DVB-U2000), thanks to Amaury Demol for reporting @@ -49,7 +88,7 @@ (old news for vp7041.c) 2004-07-15 - found out, by accident, that the device has a TUA6010XS for - frequency generator + PLL 2004-07-12 - figured out, that the driver should also work with the CTS Portable (Chinese Television System) 2004-07-08 - firmware-extraction-2.422-problem solved, driver is now working @@ -67,7 +106,7 @@ 1. How to use? NOTE: This driver was developed using Linux 2.6.6., -it is working with 2.6.7, 2.6.8.1. +it is working with 2.6.7, 2.6.8.1, 2.6.9 . Linux 2.4.x support is not planned, but patches are very welcome. @@ -81,8 +120,15 @@ You can either use "get_dvb_firmware dibusb" to download the firmware or you can get it directly via +for USB1.1 (AN2135) http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-5.0.0.11.fw?rev=1.1&content-type=text/plain +for USB1.1 (AN2235) (a few Artec T1 devices) +http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-an2235-1.fw?rev=1.1&content-type=text/plain + +for USB2.0 (FX2) +http://linuxtv.org/cgi-bin/cvsweb.cgi/dvb-kernel/firmware/dvb-dibusb-6.0.0.5.fw?rev=1.1&content-type=text/plain + 1.2. Compiling Since the driver is in the linux kernel, activating the driver in @@ -94,15 +140,16 @@ Hotplug is able to load the driver, when it is needed (because you plugged in the device). -If you want to enable debug output, you have to load the driver manually. +If you want to enable debug output, you have to load the driver manually and +from withing the dvb-kernel cvs repository. first have a look, which debug level are available: -modinfo dvb-dibusb modinfo dib3000mb +modinfo dvb-dibusb -modprobe dvb-dibusb debug= modprobe dib3000mb debug= +modprobe dvb-dibusb debug= should do the trick. @@ -118,21 +165,19 @@ 2. Known problems and bugs TODO: -- remote control tasklet +- remote control - signal-quality and strength calculations -- debug messages restructure - i2c address probing -- 2.1. Adding support for devices It is not possible to determine the range of devices based on the DiBcom -reference design. This is because the reference design of DiBcom can be sold -to third persons, without telling DiBcom (so done with the Twinhan VP7041 and +reference designs. This is because the reference design of DiBcom can be sold +to thirds, without telling DiBcom (so done with the Twinhan VP7041 and the HAMA device). When you think you have a device like this and the driver does not recognizes it, -please send the ****load.inf and the ****cap.inf of the Windows driver to me. +please send the ****load*.inf and the ****cap*.inf of the Windows driver to me. Sometimes the Vendor or Product ID is identical to the ones of Twinhan, even though it is not a Twinhan device (e.g. HAMA), then please send me the name @@ -152,6 +197,9 @@ Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for providing specs, code and help, on which the dvb-dibusb and dib3000mb are based. + + David Matthews for identifying a new device type (Artec T1 with AN2235) + and for extending dibusb with remote control event handling. Thank you. Alex Woods for frequently answering question about usb and dvb stuff, a big thank you diff -Nru a/Documentation/dvb/cards.txt b/Documentation/dvb/cards.txt --- a/Documentation/dvb/cards.txt 2004-12-12 17:40:53 -08:00 +++ b/Documentation/dvb/cards.txt 2004-12-12 17:40:53 -08:00 @@ -38,7 +38,7 @@ Comtech DVBT-6k07 (SP5730 PLL) (NxtWave Communications NXT6000 demodulator) - sp887x : Microtune 7202D - - dib3000mb : DiBcom 3000-MB Frontend + - dib3000mb : DiBcom 3000-MB demodulator DVB-S/C/T: - dst : TwinHan DST Frontend @@ -69,7 +69,17 @@ o DiBcom DVB-T USB based devices: - Twinhan VisionPlus VisionDTV USB-Ter DVB-T Device - - KWorld V-Stream XPERT DTV - DVB-T USB - HAMA DVB-T USB device + - CTS Portable (Chinese Television System) + - KWorld V-Stream XPERT DTV DVB-T USB + - JetWay DTV DVB-T USB + - ADSTech Instant TV DVB-T USB + - Ultima Electronic/Artec T1 USB TVBOX (AN2135 and AN2235) + - Compro Videomate DVB-U2000 - DVB-T USB + - Grandtec USB DVB-T + - Avermedia AverTV DVBT USB + - DiBcom USB DVB-T reference device (non-public) + - Yakumo DVB-T mobile USB2.0 + - DiBcom USB2.0 DVB-T reference device (non-public) o Experimental support for the analog module of the Siemens DVB-C PCI card diff -Nru a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware --- a/Documentation/dvb/get_dvb_firmware 2004-12-12 17:40:53 -08:00 +++ b/Documentation/dvb/get_dvb_firmware 2004-12-12 17:40:53 -08:00 @@ -21,7 +21,7 @@ use File::Temp qw/ tempdir /; use IO::Handle; -@components = ( "alps_tdlb7", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" ); +@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" ); # Check args syntax() if (scalar(@ARGV) != 1); @@ -32,7 +32,7 @@ if ($cid eq $components[$i]) { $outfile = eval($cid); die $@ if $@; - print STDERR "Firmware $outfile extracted successfully. Now copy it to /usr/lib/hotplug/firmware/.\n"; + print STDERR "Firmware $outfile extracted successfully. Now copy it to either /lib/firmware or /usr/lib/hotplug/firmware/ (depending on your hotplug version).\n"; exit(0); } } @@ -47,11 +47,11 @@ # --------------------------------------------------------------- # Firmware-specific extraction subroutines -sub alps_tdlb7 { +sub sp8870 { my $sourcefile = "tt_Premium_217g.zip"; my $url = "http://www.technotrend.de/new/217g/$sourcefile"; my $hash = "53970ec17a538945a6d8cb608a7b3899"; - my $outfile = "dvb-fe-tdlb7.fw"; + my $outfile = "dvb-fe-sp8870.fw"; my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); checkstandard(); diff -Nru a/arch/arm/Kconfig b/arch/arm/Kconfig --- a/arch/arm/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/arm/Kconfig 2004-12-12 17:40:52 -08:00 @@ -317,7 +317,7 @@ config FIQ bool - depends on ARCH_ACORN || ARCH_L7200 || ARCH_LH7A400 + depends on ARCH_ACORN || ARCH_L7200 default y # Compressed boot loader in ROM. Yes, we really want to ask about diff -Nru a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S --- a/arch/arm/kernel/vmlinux.lds.S 2004-12-12 17:40:52 -08:00 +++ b/arch/arm/kernel/vmlinux.lds.S 2004-12-12 17:40:52 -08:00 @@ -56,6 +56,10 @@ __initramfs_start = .; usr/built-in.o(.init.ramfs) __initramfs_end = .; + . = ALIGN(64); + __per_cpu_start = .; + *(.data.percpu) + __per_cpu_end = .; #ifndef CONFIG_XIP_KERNEL __init_begin = _stext; *(.init.data) diff -Nru a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S --- a/arch/arm/lib/getuser.S 2004-12-12 17:40:53 -08:00 +++ b/arch/arm/lib/getuser.S 2004-12-12 17:40:53 -08:00 @@ -17,7 +17,7 @@ * * Inputs: r0 contains the address * Outputs: r0 is the error code - * r1, r2 contains the zero-extended value + * r2, r3 contains the zero-extended value * lr corrupted * * No other registers must be altered. (see include/asm-arm/uaccess.h @@ -32,39 +32,39 @@ .global __get_user_1 __get_user_1: -1: ldrbt r1, [r0] +1: ldrbt r2, [r0] mov r0, #0 mov pc, lr .global __get_user_2 __get_user_2: -2: ldrbt r1, [r0], #1 -3: ldrbt r2, [r0] +2: ldrbt r2, [r0], #1 +3: ldrbt r3, [r0] #ifndef __ARMEB__ - orr r1, r1, r2, lsl #8 + orr r2, r2, r3, lsl #8 #else - orr r1, r2, r1, lsl #8 + orr r2, r3, r2, lsl #8 #endif mov r0, #0 mov pc, lr .global __get_user_4 __get_user_4: -4: ldrt r1, [r0] +4: ldrt r2, [r0] mov r0, #0 mov pc, lr .global __get_user_8 __get_user_8: -5: ldrt r1, [r0], #4 -6: ldrt r2, [r0] +5: ldrt r2, [r0], #4 +6: ldrt r3, [r0] mov r0, #0 mov pc, lr __get_user_bad_8: - mov r2, #0 + mov r3, #0 __get_user_bad: - mov r1, #0 + mov r2, #0 mov r0, #-EFAULT mov pc, lr diff -Nru a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S --- a/arch/arm/lib/putuser.S 2004-12-12 17:40:53 -08:00 +++ b/arch/arm/lib/putuser.S 2004-12-12 17:40:53 -08:00 @@ -16,7 +16,7 @@ * __put_user_X * * Inputs: r0 contains the address - * r1, r2 contains the value + * r2, r3 contains the value * Outputs: r0 is the error code * lr corrupted * @@ -32,33 +32,33 @@ .global __put_user_1 __put_user_1: -1: strbt r1, [r0] +1: strbt r2, [r0] mov r0, #0 mov pc, lr .global __put_user_2 __put_user_2: - mov ip, r1, lsr #8 + mov ip, r2, lsr #8 #ifndef __ARMEB__ -2: strbt r1, [r0], #1 +2: strbt r2, [r0], #1 3: strbt ip, [r0] #else 2: strbt ip, [r0], #1 -3: strbt r1, [r0] +3: strbt r2, [r0] #endif mov r0, #0 mov pc, lr .global __put_user_4 __put_user_4: -4: strt r1, [r0] +4: strt r2, [r0] mov r0, #0 mov pc, lr .global __put_user_8 __put_user_8: -5: strt r1, [r0], #4 -6: strt r2, [r0] +5: strt r2, [r0], #4 +6: strt r3, [r0] mov r0, #0 mov pc, lr diff -Nru a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c --- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c 2004-12-12 17:40:52 -08:00 +++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c 2004-12-12 17:40:52 -08:00 @@ -267,7 +267,7 @@ BOOT_PARAMS (0xc0000100) MAPIO (lpd7a400_map_io) INITIRQ (lh7a400_init_irq) - .timer = &lpd7a40x_timer, + .timer = &lh7a40x_timer, INIT_MACHINE (lpd7a40x_init) MACHINE_END @@ -281,7 +281,7 @@ BOOT_PARAMS (0xc0000100) MAPIO (lpd7a400_map_io) INITIRQ (lh7a404_init_irq) - .timer = &lpd7a40x_timer, + .timer = &lh7a40x_timer, INIT_MACHINE (lpd7a40x_init) MACHINE_END diff -Nru a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h --- a/arch/arm/mach-lh7a40x/common.h 2004-12-12 17:40:52 -08:00 +++ b/arch/arm/mach-lh7a40x/common.h 2004-12-12 17:40:52 -08:00 @@ -1,9 +1,14 @@ -/* - * linux/arch/arm/mach-lh7a40x/common.h +/* arch/arm/mach-lh7a40x/common.h + * + * Copyright (C) 2004 Marc Singer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. * - * Header file for common stuff. */ -struct sys_timer; + extern struct sys_timer lh7a40x_timer; extern void lh7a400_init_irq (void); +extern void lh7a404_init_irq (void); diff -Nru a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c --- a/arch/arm/mach-lh7a40x/time.c 2004-12-12 17:40:52 -08:00 +++ b/arch/arm/mach-lh7a40x/time.c 2004-12-12 17:40:52 -08:00 @@ -71,5 +71,5 @@ } struct sys_timer lh7a40x_timer = { - .init = &lh7a40x_timer, + .init = &lh7a40x_timer_init, }; diff -Nru a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c --- a/arch/arm/mach-s3c2410/time.c 2004-12-12 17:40:52 -08:00 +++ b/arch/arm/mach-s3c2410/time.c 2004-12-12 17:40:52 -08:00 @@ -37,7 +37,49 @@ #include "clock.h" static unsigned long timer_startval; -static unsigned long timer_ticks_usec; +static unsigned long timer_usec_ticks; + +#define TIMER_USEC_SHIFT 16 + +/* we use the shifted arithmetic to work out the ratio of timer ticks + * to usecs, as often the peripheral clock is not a nice even multiple + * of 1MHz. + * + * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok + * for the current HZ value of 200 without producing overflows. + * + * Original patch by Dimitry Andric, updated by Ben Dooks +*/ + + +/* timer_mask_usec_ticks + * + * given a clock and divisor, make the value to pass into timer_ticks_to_usec + * to scale the ticks into usecs +*/ + +static inline unsigned long +timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk) +{ + unsigned long den = pclk / 1000; + + return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den; +} + +/* timer_ticks_to_usec + * + * convert timer ticks to usec. +*/ + +static inline unsigned long timer_ticks_to_usec(unsigned long ticks) +{ + unsigned long res; + + res = ticks * timer_usec_ticks; + res += 1 << (TIMER_USEC_SHIFT - 4); /* round up slightly */ + + return res >> TIMER_USEC_SHIFT; +} /*** * Returns microsecond since last clock interrupt. Note that interrupts @@ -50,31 +92,31 @@ static unsigned long s3c2410_gettimeoffset (void) { unsigned long tdone; - unsigned long usec; unsigned long irqpend; + unsigned long tval; /* work out how many ticks have gone since last timer interrupt */ - tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); + tval = __raw_readl(S3C2410_TCNTO(4)); + tdone = timer_startval - tval; /* check to see if there is an interrupt pending */ irqpend = __raw_readl(S3C2410_SRCPND); if (irqpend & SRCPND_TIMER4) { /* re-read the timer, and try and fix up for the missed - * interrupt */ - - tdone = timer_startval - __raw_readl(S3C2410_TCNTO(4)); - tdone += 1<<16; - } + * interrupt. Note, the interrupt may go off before the + * timer has re-loaded from wrapping. + */ - /* currently, tcnt is in 12MHz units, but this may change - * for non-bast machines... - */ + tval = __raw_readl(S3C2410_TCNTO(4)); + tdone = timer_startval - tval; - usec = tdone / timer_ticks_usec; + if (tval != 0) + tdone += timer_startval; + } - return usec; + return timer_ticks_to_usec(tdone); } @@ -120,8 +162,9 @@ /* configure the system for whichever machine is in use */ if (machine_is_bast() || machine_is_vr1000()) { - timer_ticks_usec = 12; /* timer is at 12MHz */ - tcnt = (timer_ticks_usec * (1000*1000)) / HZ; + /* timer is at 12MHz, scaler is 1 */ + timer_usec_ticks = timer_mask_usec_ticks(1, 12000000); + tcnt = 12000000 / HZ; tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1; @@ -129,13 +172,15 @@ /* for the h1940 (and others), we use the pclk from the core * to generate the timer values. since values around 50 to * 70MHz are not values we can directly generate the timer - * value from, we need to pre-scaleand divide before using it. + * value from, we need to pre-scale and divide before using it. + * + * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz + * (8.45 ticks per usec) */ /* this is used as default if no other timer can be found */ - timer_ticks_usec = s3c24xx_pclk / (1000*1000); - timer_ticks_usec /= 6; + timer_usec_ticks = timer_mask_usec_ticks(6, s3c24xx_pclk); tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK; tcfg1 |= S3C2410_TCFG1_MUX4_DIV2; @@ -146,8 +191,12 @@ tcnt = (s3c24xx_pclk / 6) / HZ; } - printk("setup_timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx\n", - tcon, tcnt, tcfg0, tcfg1); + /* timers reload after counting zero, so reduce the count by 1 */ + + tcnt--; + + printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n", + tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks); /* check to see if timer is within 16bit range... */ if (tcnt > 0xffff) { diff -Nru a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c --- a/arch/arm/mach-sa1100/lart.c 2004-12-12 17:40:53 -08:00 +++ b/arch/arm/mach-sa1100/lart.c 2004-12-12 17:40:53 -08:00 @@ -17,6 +17,8 @@ #include "generic.h" +#warning "include/asm/arch-sa1100/ide.h needs fixing for lart" + static struct map_desc lart_io_desc[] __initdata = { /* virtual physical length type */ { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */ diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/i386/Kconfig 2004-12-12 17:40:52 -08:00 @@ -200,7 +200,7 @@ bool "586/K5/5x86/6x86/6x86MX" help Select this for an 586 or 686 series processor such as the AMD K5, - the Intel 5x86 or 6x86, or the Intel 6x86MX. This choice does not + the Cyrix 5x86, 6x86 and 6x86MX. This choice does not assume the RDTSC (Read Time Stamp Counter) instruction. config M586TSC diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S 2004-12-12 17:40:52 -08:00 +++ b/arch/i386/kernel/entry.S 2004-12-12 17:40:52 -08:00 @@ -235,6 +235,7 @@ /* if something modifies registers it must also disable sysexit */ movl EIP(%esp), %edx movl OLDESP(%esp), %ecx + xorl %ebp,%ebp sti sysexit diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c 2004-12-12 17:40:52 -08:00 +++ b/arch/i386/kernel/process.c 2004-12-12 17:40:52 -08:00 @@ -99,6 +99,8 @@ safe_halt(); else local_irq_enable(); + } else { + cpu_relax(); } } diff -Nru a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c --- a/arch/i386/kernel/quirks.c 2004-12-12 17:40:52 -08:00 +++ b/arch/i386/kernel/quirks.c 2004-12-12 17:40:52 -08:00 @@ -1,10 +1,11 @@ /* * This file contains work-arounds for x86 and x86_64 platform bugs. */ +#include #include #include -#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) +#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI) void __devinit quirk_intel_irqbalance(struct pci_dev *dev) { diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c --- a/arch/i386/kernel/time.c 2004-12-12 17:40:52 -08:00 +++ b/arch/i386/kernel/time.c 2004-12-12 17:40:52 -08:00 @@ -381,9 +381,9 @@ void __init hpet_time_init(void) { xtime.tv_sec = get_cmos_time(); - wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = -xtime.tv_nsec; + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); if (hpet_enable() >= 0) { printk("Using HPET for base-timer\n"); @@ -409,9 +409,9 @@ } #endif xtime.tv_sec = get_cmos_time(); - wall_to_monotonic.tv_sec = -xtime.tv_sec; xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_nsec = -xtime.tv_nsec; + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); cur_timer = select_timer(); printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c --- a/arch/i386/kernel/vm86.c 2004-12-12 17:40:52 -08:00 +++ b/arch/i386/kernel/vm86.c 2004-12-12 17:40:52 -08:00 @@ -723,7 +723,14 @@ irqbits |= irq_bit; if (vm86_irqs[intno].sig) send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1); - /* else user will poll for IRQs */ + spin_unlock_irqrestore(&irqbits_lock, flags); + /* + * IRQ will be re-enabled when user asks for the irq (whether + * polling or as a result of the signal) + */ + disable_irq(intno); + return IRQ_HANDLED; + out: spin_unlock_irqrestore(&irqbits_lock, flags); return IRQ_NONE; diff -Nru a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c --- a/arch/m32r/kernel/time.c 2004-12-12 17:40:53 -08:00 +++ b/arch/m32r/kernel/time.c 2004-12-12 17:40:53 -08:00 @@ -275,8 +275,8 @@ xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); - wall_to_monotonic.tv_sec = -xtime.tv_sec; - wall_to_monotonic.tv_nsec = -xtime.tv_nsec; + set_normalized_timespec(&wall_to_monotonic, + -xtime.tv_sec, -xtime.tv_nsec); #if defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_XNUX2) \ || defined(CONFIG_CHIP_VDEC2) || defined(CONFIG_CHIP_M32700) \ diff -Nru a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig --- a/arch/m68k/configs/amiga_defconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/m68k/configs/amiga_defconfig 2004-12-12 17:40:52 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:46:49 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:25 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -137,6 +137,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -722,6 +723,10 @@ # CONFIG_USB_ARCH_HAS_OHCI is not set # +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -953,7 +958,7 @@ # Library routines # CONFIG_CRC_CCITT=m -CONFIG_CRC32=m +CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig --- a/arch/m68k/configs/apollo_defconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/m68k/configs/apollo_defconfig 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:47:18 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:29 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -122,6 +122,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -579,6 +580,10 @@ # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# # # USB Gadget Support diff -Nru a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig --- a/arch/m68k/configs/atari_defconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/m68k/configs/atari_defconfig 2004-12-12 17:40:52 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:48:18 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:34 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -129,6 +129,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -634,6 +635,10 @@ # CONFIG_USB_ARCH_HAS_OHCI is not set # +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -865,7 +870,7 @@ # Library routines # CONFIG_CRC_CCITT=m -CONFIG_CRC32=m +CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig --- a/arch/m68k/configs/bvme6000_defconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/m68k/configs/bvme6000_defconfig 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:48:27 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:38 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -122,6 +122,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -578,6 +579,10 @@ # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# # # USB Gadget Support diff -Nru a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig --- a/arch/m68k/configs/hp300_defconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/m68k/configs/hp300_defconfig 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:48:53 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:44 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -123,6 +123,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -580,6 +581,10 @@ # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# # # USB Gadget Support diff -Nru a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig --- a/arch/m68k/configs/mac_defconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/m68k/configs/mac_defconfig 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:49:04 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:47 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -124,6 +124,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -641,6 +642,10 @@ # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# # # USB Gadget Support diff -Nru a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig --- a/arch/m68k/configs/mvme147_defconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/m68k/configs/mvme147_defconfig 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:49:10 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:49 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -122,6 +122,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -595,6 +596,10 @@ # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# # # USB Gadget Support diff -Nru a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig --- a/arch/m68k/configs/mvme16x_defconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/m68k/configs/mvme16x_defconfig 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:49:35 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:52 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -122,6 +122,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -596,6 +597,10 @@ # CONFIG_USB_ARCH_HAS_OHCI is not set # +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -827,7 +832,7 @@ # Library routines # CONFIG_CRC_CCITT=m -CONFIG_CRC32=m +CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig --- a/arch/m68k/configs/q40_defconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/m68k/configs/q40_defconfig 2004-12-12 17:40:52 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:49:42 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:55 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -127,6 +127,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -673,6 +674,10 @@ # CONFIG_USB_ARCH_HAS_OHCI is not set # +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -900,7 +905,7 @@ # Library routines # CONFIG_CRC_CCITT=m -CONFIG_CRC32=m +CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig --- a/arch/m68k/configs/sun3_defconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/m68k/configs/sun3_defconfig 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:49:50 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:58 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -110,6 +110,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -586,6 +587,10 @@ # CONFIG_USB_ARCH_HAS_OHCI is not set # +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -815,7 +820,7 @@ # Library routines # CONFIG_CRC_CCITT=m -CONFIG_CRC32=m +CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig --- a/arch/m68k/configs/sun3x_defconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/m68k/configs/sun3x_defconfig 2004-12-12 17:40:52 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:49:55 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:22:01 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -121,6 +121,7 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -596,6 +597,10 @@ # CONFIG_USB_ARCH_HAS_OHCI is not set # +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# # USB Gadget Support # # CONFIG_USB_GADGET is not set @@ -825,7 +830,7 @@ # Library routines # CONFIG_CRC_CCITT=m -CONFIG_CRC32=m +CONFIG_CRC32=y CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/m68k/defconfig b/arch/m68k/defconfig --- a/arch/m68k/defconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/m68k/defconfig 2004-12-12 17:40:52 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2-m68k -# Mon Nov 15 12:48:44 2004 +# Linux kernel version: 2.6.10-rc3-m68k +# Sun Dec 5 14:21:41 2004 # CONFIG_M68K=y CONFIG_MMU=y @@ -115,6 +115,7 @@ # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y CONFIG_INITRAMFS_SOURCE="" @@ -450,6 +451,10 @@ # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# # # USB Gadget Support diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c --- a/arch/ppc/platforms/prep_pci.c 2004-12-12 17:40:53 -08:00 +++ b/arch/ppc/platforms/prep_pci.c 2004-12-12 17:40:53 -08:00 @@ -49,10 +49,10 @@ 0, /* Slot 1 - unused */ 5, /* Slot 2 - SCSI - NCR825A */ 0, /* Slot 3 - unused */ - 1, /* Slot 4 - Ethernet - DEC2114x */ + 3, /* Slot 4 - Ethernet - DEC2114x */ 0, /* Slot 5 - unused */ - 3, /* Slot 6 - PCI Card slot #1 */ - 4, /* Slot 7 - PCI Card slot #2 */ + 2, /* Slot 6 - PCI Card slot #1 */ + 3, /* Slot 7 - PCI Card slot #2 */ 5, /* Slot 8 - PCI Card slot #3 */ 5, /* Slot 9 - PCI Bridge */ /* added here in case we ever support PCI bridges */ diff -Nru a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c --- a/arch/ppc64/kernel/prom_init.c 2004-12-12 17:40:53 -08:00 +++ b/arch/ppc64/kernel/prom_init.c 2004-12-12 17:40:53 -08:00 @@ -1108,6 +1108,16 @@ } } +static void __init prom_close_stdin(void) +{ + unsigned long offset = reloc_offset(); + struct prom_t *_prom = PTRRELOC(&prom); + ihandle val; + + if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0) + call_prom("close", 1, 0, val); +} + static int __init prom_find_machine_type(void) { unsigned long offset = reloc_offset(); @@ -1685,6 +1695,9 @@ */ prom_printf("copying OF device tree ...\n"); flatten_device_tree(); + + /* in case stdin is USB and still active on IBM machines... */ + prom_close_stdin(); /* * Call OF "quiesce" method to shut down pending DMA's from diff -Nru a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S --- a/arch/sparc/kernel/entry.S 2004-12-12 17:40:52 -08:00 +++ b/arch/sparc/kernel/entry.S 2004-12-12 17:40:52 -08:00 @@ -1508,7 +1508,7 @@ .globl ret_sys_call ret_sys_call: ld [%curptr + TI_FLAGS], %l6 - cmp %o0, -ENOIOCTLCMD + cmp %o0, -ERESTART_RESTARTBLOCK ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 set PSR_C, %g2 bgeu 1f @@ -1587,7 +1587,7 @@ st %o0, [%sp + STACKFRAME_SZ + PT_I0] set PSR_C, %g2 - cmp %o0, -ENOIOCTLCMD + cmp %o0, -ERESTART_RESTARTBLOCK bgeu 1f ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 @@ -1678,7 +1678,7 @@ st %o0, [%sp + STACKFRAME_SZ + PT_I0] set PSR_C, %g2 - cmp %o0, -ENOIOCTLCMD + cmp %o0, -ERESTART_RESTARTBLOCK bgeu 1f ld [%sp + STACKFRAME_SZ + PT_PSR], %g3 diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig 2004-12-12 17:40:52 -08:00 +++ b/arch/sparc64/defconfig 2004-12-12 17:40:52 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc2 -# Tue Nov 16 11:09:23 2004 +# Linux kernel version: 2.6.10-rc3 +# Wed Dec 8 21:14:26 2004 # CONFIG_64BIT=y CONFIG_MMU=y @@ -233,6 +233,7 @@ CONFIG_BLK_DEV_SX8=m CONFIG_BLK_DEV_UB=m # CONFIG_BLK_DEV_RAM is not set +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_INITRAMFS_SOURCE="" CONFIG_CDROM_PKTCDVD=m CONFIG_CDROM_PKTCDVD_BUFFERS=8 @@ -387,7 +388,6 @@ CONFIG_SCSI_QLOGIC_FC=y CONFIG_SCSI_QLOGIC_FC_FIRMWARE=y # CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_QLOGIC_1280_1040 is not set CONFIG_SCSI_QLOGICPTI=m CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA21XX is not set @@ -1045,6 +1045,11 @@ # Active AVM cards # CONFIG_CAPI_AVM=y +CONFIG_ISDN_DRV_AVMB1_B1PCI=m +CONFIG_ISDN_DRV_AVMB1_B1PCIV4=y +CONFIG_ISDN_DRV_AVMB1_B1PCMCIA=m +CONFIG_ISDN_DRV_AVMB1_T1PCI=m +CONFIG_ISDN_DRV_AVMB1_C4=m # # Active Eicon DIVA Server cards @@ -1178,6 +1183,7 @@ CONFIG_I2C_SENSOR=m CONFIG_SENSORS_ADM1021=m CONFIG_SENSORS_ADM1025=m +CONFIG_SENSORS_ADM1026=m CONFIG_SENSORS_ADM1031=m CONFIG_SENSORS_ASB100=m CONFIG_SENSORS_DS1621=m @@ -1439,39 +1445,6 @@ CONFIG_DVB_CORE=m # -# DVB-S (satellite) frontends -# -CONFIG_DVB_STV0299=m -CONFIG_DVB_CX24110=m -CONFIG_DVB_GRUNDIG_29504_491=m -CONFIG_DVB_MT312=m -CONFIG_DVB_VES1X93=m - -# -# DVB-T (terrestrial) frontends -# -CONFIG_DVB_SP887X=m -CONFIG_DVB_ALPS_TDLB7=m -CONFIG_DVB_ALPS_TDMB7=m -CONFIG_DVB_CX22702=m -CONFIG_DVB_GRUNDIG_29504_401=m -CONFIG_DVB_TDA1004X=m -CONFIG_DVB_NXT6000=m -CONFIG_DVB_MT352=m -CONFIG_DVB_DIB3000MB=m - -# -# DVB-C (cable) frontends -# -CONFIG_DVB_ATMEL_AT76C651=m -CONFIG_DVB_VES1820=m - -# -# Misc. Frontend Modules -# -CONFIG_DVB_TWINHAN_DST=m - -# # Supported SAA7146 based PCI Adapters # CONFIG_DVB_AV7110=m @@ -1487,6 +1460,8 @@ # CONFIG_DVB_TTUSB_BUDGET is not set CONFIG_DVB_TTUSB_DEC=m CONFIG_DVB_DIBUSB=m +CONFIG_DVB_DIBUSB_MISDESIGNED_AN2235=y +CONFIG_DVB_DIBCOM_DEBUG=y CONFIG_DVB_CINERGYT2=m # CONFIG_DVB_CINERGYT2_TUNING is not set @@ -1499,6 +1474,45 @@ # Supported BT878 Adapters # CONFIG_DVB_BT8XX=m + +# +# Supported DVB Frontends +# + +# +# Customise DVB Frontends +# + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_STV0299=m +CONFIG_DVB_CX24110=m +CONFIG_DVB_TDA8083=m +CONFIG_DVB_TDA80XX=m +CONFIG_DVB_MT312=m +CONFIG_DVB_VES1X93=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_SP8870=m +CONFIG_DVB_SP887X=m +CONFIG_DVB_CX22700=m +CONFIG_DVB_CX22702=m +CONFIG_DVB_L64781=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_DIB3000MB=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_ATMEL_AT76C651=m +CONFIG_DVB_VES1820=m +CONFIG_DVB_TDA10021=m +CONFIG_DVB_STV0297=m CONFIG_VIDEO_SAA7146=m CONFIG_VIDEO_SAA7146_VV=m CONFIG_VIDEO_VIDEOBUF=m @@ -1634,6 +1648,10 @@ # CONFIG_USB_MIDI is not set CONFIG_USB_ACM=m CONFIG_USB_PRINTER=m + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set CONFIG_USB_STORAGE_RW_DETECT=y diff -Nru a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c --- a/arch/sparc64/kernel/binfmt_elf32.c 2004-12-12 17:40:53 -08:00 +++ b/arch/sparc64/kernel/binfmt_elf32.c 2004-12-12 17:40:53 -08:00 @@ -79,7 +79,7 @@ #define elf_check_arch(x) (((x)->e_machine == EM_SPARC) || ((x)->e_machine == EM_SPARC32PLUS)) -#define ELF_ET_DYN_BASE 0x08000000 +#define ELF_ET_DYN_BASE 0x70000000 #include diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S --- a/arch/sparc64/kernel/entry.S 2004-12-12 17:40:52 -08:00 +++ b/arch/sparc64/kernel/entry.S 2004-12-12 17:40:52 -08:00 @@ -1778,7 +1778,7 @@ stx %l0, [%curptr + TI_FLAGS] 1: - cmp %o0, -ENOIOCTLCMD + cmp %o0, -ERESTART_RESTARTBLOCK bgeu,pn %xcc, 1f andcc %l0, _TIF_SYSCALL_TRACE, %l6 80: diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c --- a/arch/sparc64/kernel/smp.c 2004-12-12 17:40:52 -08:00 +++ b/arch/sparc64/kernel/smp.c 2004-12-12 17:40:52 -08:00 @@ -103,15 +103,6 @@ void __init smp_callin(void) { int cpuid = hard_smp_processor_id(); - extern int bigkernel; - extern unsigned long kern_locked_tte_data; - - if (bigkernel) { - prom_dtlb_load(sparc64_highest_locked_tlbent()-1, - kern_locked_tte_data + 0x400000, KERNBASE + 0x400000); - prom_itlb_load(sparc64_highest_locked_tlbent()-1, - kern_locked_tte_data + 0x400000, KERNBASE + 0x400000); - } inherit_locked_prom_mappings(0); diff -Nru a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S --- a/arch/sparc64/kernel/trampoline.S 2004-12-12 17:40:52 -08:00 +++ b/arch/sparc64/kernel/trampoline.S 2004-12-12 17:40:52 -08:00 @@ -90,7 +90,9 @@ sllx %g2, 32, %g2 wr %g2, 0, %tick_cmpr - /* Call OBP by hand to lock KERNBASE into i/d tlbs. */ + /* Call OBP by hand to lock KERNBASE into i/d tlbs. + * We lock 2 consequetive entries if we are 'bigkernel'. + */ mov %o0, %l0 sethi %hi(prom_entry_lock), %g2 @@ -136,6 +138,46 @@ call %o1 add %sp, (2047 + 128), %o0 + sethi %hi(bigkernel), %g2 + lduw [%g2 + %lo(bigkernel)], %g2 + cmp %g2, 0 + be,pt %icc, do_dtlb + nop + + sethi %hi(call_method), %g2 + or %g2, %lo(call_method), %g2 + stx %g2, [%sp + 2047 + 128 + 0x00] + mov 5, %g2 + stx %g2, [%sp + 2047 + 128 + 0x08] + mov 1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x10] + sethi %hi(itlb_load), %g2 + or %g2, %lo(itlb_load), %g2 + stx %g2, [%sp + 2047 + 128 + 0x18] + sethi %hi(mmu_ihandle_cache), %g2 + lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x20] + sethi %hi(KERNBASE + 0x400000), %g2 + stx %g2, [%sp + 2047 + 128 + 0x28] + sethi %hi(kern_locked_tte_data), %g2 + ldx [%g2 + %lo(kern_locked_tte_data)], %g2 + sethi %hi(0x400000), %g1 + add %g2, %g1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x30] + + mov 14, %g2 + BRANCH_IF_ANY_CHEETAH(g1,g5,1f) + + mov 62, %g2 +1: + stx %g2, [%sp + 2047 + 128 + 0x38] + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x08], %o1 + call %o1 + add %sp, (2047 + 128), %o0 + +do_dtlb: sethi %hi(call_method), %g2 or %g2, %lo(call_method), %g2 stx %g2, [%sp + 2047 + 128 + 0x00] @@ -168,6 +210,47 @@ call %o1 add %sp, (2047 + 128), %o0 + sethi %hi(bigkernel), %g2 + lduw [%g2 + %lo(bigkernel)], %g2 + cmp %g2, 0 + be,pt %icc, do_unlock + nop + + sethi %hi(call_method), %g2 + or %g2, %lo(call_method), %g2 + stx %g2, [%sp + 2047 + 128 + 0x00] + mov 5, %g2 + stx %g2, [%sp + 2047 + 128 + 0x08] + mov 1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x10] + sethi %hi(dtlb_load), %g2 + or %g2, %lo(dtlb_load), %g2 + stx %g2, [%sp + 2047 + 128 + 0x18] + sethi %hi(mmu_ihandle_cache), %g2 + lduw [%g2 + %lo(mmu_ihandle_cache)], %g2 + stx %g2, [%sp + 2047 + 128 + 0x20] + sethi %hi(KERNBASE + 0x400000), %g2 + stx %g2, [%sp + 2047 + 128 + 0x28] + sethi %hi(kern_locked_tte_data), %g2 + ldx [%g2 + %lo(kern_locked_tte_data)], %g2 + sethi %hi(0x400000), %g1 + add %g2, %g1, %g2 + stx %g2, [%sp + 2047 + 128 + 0x30] + + mov 14, %g2 + BRANCH_IF_ANY_CHEETAH(g1,g5,1f) + + mov 62, %g2 +1: + + stx %g2, [%sp + 2047 + 128 + 0x38] + sethi %hi(p1275buf), %g2 + or %g2, %lo(p1275buf), %g2 + ldx [%g2 + 0x08], %o1 + call %o1 + add %sp, (2047 + 128), %o0 + +do_unlock: sethi %hi(prom_entry_lock), %g2 stb %g0, [%g2 + %lo(prom_entry_lock)] membar #StoreStore | #StoreLoad diff -Nru a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S --- a/arch/sparc64/solaris/entry64.S 2004-12-12 17:40:52 -08:00 +++ b/arch/sparc64/solaris/entry64.S 2004-12-12 17:40:52 -08:00 @@ -109,7 +109,7 @@ sra %o0, 0, %o0 mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3 - cmp %o0, -ENOIOCTLCMD + cmp %o0, -ERESTART_RESTARTBLOCK sllx %g2, 32, %g2 bgeu,pn %xcc, 1f andcc %l6, _TIF_SYSCALL_TRACE, %l6 diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig 2004-12-12 17:40:53 -08:00 +++ b/arch/x86_64/Kconfig 2004-12-12 17:40:53 -08:00 @@ -306,6 +306,7 @@ config GART_IOMMU bool "IOMMU support" + depends on PCI help Support the K8 IOMMU. Needed to run systems with more than 4GB of memory properly with 32-bit PCI devices that do not support DAC (Double Address diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/block/cciss.c 2004-12-12 17:40:53 -08:00 @@ -1100,7 +1100,7 @@ return(status); } default: - return -EBADRQC; + return -ENOTTY; } } diff -Nru a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c --- a/drivers/block/cfq-iosched.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/block/cfq-iosched.c 2004-12-12 17:40:53 -08:00 @@ -867,6 +867,9 @@ struct cfq_data *cfqd = cfqq->cfqd; unsigned long now, elapsed; + if (!blk_fs_request(crq->request)) + return; + /* * accounted bit is necessary since some drivers will call * elv_next_request() many times for the same request (eg ide) @@ -911,6 +914,9 @@ cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq) { struct cfq_data *cfqd = cfqq->cfqd; + + if (!crq->accounted) + return; WARN_ON(!cfqd->rq_in_driver); cfqd->rq_in_driver--; diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/bluetooth/hci_usb.c 2004-12-12 17:40:53 -08:00 @@ -67,7 +67,7 @@ #endif #ifdef CONFIG_BT_HCIUSB_SCO -static int isoc = 1; +static int isoc = 2; #endif #define VERSION "2.7" @@ -898,7 +898,7 @@ switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_ISOC: if (ep->desc.wMaxPacketSize < size || - uif->desc.bAlternateSetting > 2) + uif->desc.bAlternateSetting != isoc) break; size = ep->desc.wMaxPacketSize; @@ -1037,7 +1037,7 @@ module_exit(hci_usb_exit); #ifdef CONFIG_BT_HCIUSB_SCO -module_param(isoc, bool, 0); +module_param(isoc, int, 0644); MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support"); #endif diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c --- a/drivers/char/vt.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/char/vt.c 2004-12-12 17:40:53 -08:00 @@ -768,6 +768,8 @@ * [this is to be used together with some user program * like resize that changes the hardware videomode] */ +#define VC_RESIZE_MAXCOL (32767) +#define VC_RESIZE_MAXROW (32767) int vc_resize(int currcons, unsigned int cols, unsigned int lines) { unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; @@ -779,6 +781,9 @@ if (!vc_cons_allocated(currcons)) return -ENXIO; + + if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) + return -EINVAL; new_cols = (cols ? cols : video_num_columns); new_rows = (lines ? lines : video_num_lines); diff -Nru a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c --- a/drivers/char/watchdog/ixp4xx_wdt.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/char/watchdog/ixp4xx_wdt.c 2004-12-12 17:40:53 -08:00 @@ -216,7 +216,7 @@ module_init(ixp4xx_wdt_init); module_exit(ixp4xx_wdt_exit); -MODULE_AUTHOR("Deepak Saxena ); +MODULE_AUTHOR("Deepak Saxena "); MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog"); module_param(heartbeat, int, 0); diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c --- a/drivers/ieee1394/ohci1394.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/ieee1394/ohci1394.c 2004-12-12 17:40:53 -08:00 @@ -2933,8 +2933,8 @@ d->ctrlClear = 0; d->cmdPtr = 0; - d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL); - d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); + d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_ATOMIC); + d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_ATOMIC); if (d->buf_cpu == NULL || d->buf_bus == NULL) { PRINT(KERN_ERR, "Failed to allocate dma buffer"); @@ -2945,8 +2945,8 @@ memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t)); d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*), - GFP_KERNEL); - d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); + GFP_ATOMIC); + d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_ATOMIC); if (d->prg_cpu == NULL || d->prg_bus == NULL) { PRINT(KERN_ERR, "Failed to allocate dma prg"); @@ -2956,7 +2956,7 @@ memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*)); memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); - d->spb = kmalloc(d->split_buf_size, GFP_KERNEL); + d->spb = kmalloc(d->split_buf_size, GFP_ATOMIC); if (d->spb == NULL) { PRINT(KERN_ERR, "Failed to allocate split buffer"); diff -Nru a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c --- a/drivers/input/gameport/fm801-gp.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/input/gameport/fm801-gp.c 2004-12-12 17:40:52 -08:00 @@ -98,8 +98,8 @@ pci_enable_device(pci); gp->gameport.io = pci_resource_start(pci, 0); if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) { - kfree(gp); printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f); + kfree(gp); return -1; } diff -Nru a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c --- a/drivers/media/common/saa7146_core.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/common/saa7146_core.c 2004-12-12 17:40:53 -08:00 @@ -25,11 +25,11 @@ struct semaphore saa7146_devices_lock; static int initialized = 0; -int saa7146_num = 0; +static int saa7146_num = 0; unsigned int saa7146_debug = 0; -MODULE_PARM(saa7146_debug,"i"); +module_param(saa7146_debug, int, 0644); MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); #if 0 @@ -48,7 +48,7 @@ * gpio and debi helper functions ****************************************************************************/ -/* write "data" to the gpio-pin "pin" */ +/* write "data" to the gpio-pin "pin" -- unused */ void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data) { u32 value = 0; @@ -67,7 +67,7 @@ } /* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */ -int saa7146_wait_for_debi_done(struct saa7146_dev *dev) +int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) { unsigned long start; @@ -80,6 +80,8 @@ DEB_S(("timed out while waiting for registers getting programmed\n")); return -ETIMEDOUT; } + if (nobusyloop) + msleep(1); } /* wait for transfer to complete */ @@ -92,6 +94,8 @@ DEB_S(("timed out while waiting for transfer completion\n")); return -ETIMEDOUT; } + if (nobusyloop) + msleep(1); } return 0; @@ -248,10 +252,9 @@ /********************************************************************************/ /* interrupt handler */ - static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) { - struct saa7146_dev *dev = (struct saa7146_dev*)dev_id; + struct saa7146_dev *dev = dev_id; u32 isr = 0; /* read out the interrupt status register */ @@ -318,16 +321,15 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent) { - unsigned long adr = 0, len = 0; - struct saa7146_dev* dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL); - struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data; struct saa7146_extension* ext = pci_ext->ext; - int err = 0; + struct saa7146_dev *dev; + int err = -ENOMEM; - if (!(dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL))) { + dev = kmalloc(sizeof(struct saa7146_dev), GFP_KERNEL); + if (!dev) { ERR(("out of memory.\n")); - return -ENOMEM; + goto out; } /* clear out mem for sure */ @@ -335,38 +337,37 @@ DEB_EE(("pci:%p\n",pci)); - if (pci_enable_device(pci)) { + err = pci_enable_device(pci); + if (err < 0) { ERR(("pci_enable_device() failed.\n")); - err = -EIO; - goto pci_error; + goto err_free; } /* enable bus-mastering */ pci_set_master(pci); dev->pci = pci; + /* get chip-revision; this is needed to enable bug-fixes */ - if( 0 > pci_read_config_dword(dev->pci, PCI_CLASS_REVISION, &dev->revision)) { + err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision); + if (err < 0) { ERR(("pci_read_config_dword() failed.\n")); - err = -ENODEV; - goto pci_error; + goto err_disable; } dev->revision &= 0xf; /* remap the memory from virtual to physical adress */ - adr = pci_resource_start(pci,0); - len = pci_resource_len(pci,0); - - if (!request_mem_region(pci_resource_start(pci,0), pci_resource_len(pci,0), "saa7146")) { - ERR(("request_mem_region() failed.\n")); - err = -ENODEV; - goto pci_error; - } - if (!(dev->mem = ioremap(adr,len))) { + err = pci_request_region(pci, 0, "saa7146"); + if (err < 0) + goto err_disable; + + dev->mem = ioremap(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + if (!dev->mem) { ERR(("ioremap() failed.\n")); err = -ENODEV; - goto ioremap_error; + goto err_release; } /* we don't do a master reset here anymore, it screws up @@ -386,42 +387,40 @@ saa7146_write(dev, MC2, 0xf8000000); /* request an interrupt for the saa7146 */ - if (request_irq(dev->pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT, - dev->name, dev)) - { + err = request_irq(pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT, + dev->name, dev); + if (err < 0) { ERR(("request_irq() failed.\n")); - err = -ENODEV; - goto irq_error; + goto err_unmap; } - /* get memory for various stuff */ - dev->d_rps0.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_rps0.dma_handle); - if( NULL == dev->d_rps0.cpu_addr ) { err = -ENOMEM; - goto kmalloc_error_1; - } + + /* get memory for various stuff */ + dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, + &dev->d_rps0.dma_handle); + if (!dev->d_rps0.cpu_addr) + goto err_free_irq; memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM); - dev->d_rps1.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_rps1.dma_handle); - if( NULL == dev->d_rps1.cpu_addr ) { - err = -ENOMEM; - goto kmalloc_error_2; - } + dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, + &dev->d_rps1.dma_handle); + if (!dev->d_rps1.cpu_addr) + goto err_free_rps0; memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM); - dev->d_i2c.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_i2c.dma_handle); - if( NULL == dev->d_i2c.cpu_addr ) { - err = -ENOMEM; - goto kmalloc_error_3; - } + dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM, + &dev->d_i2c.dma_handle); + if (!dev->d_i2c.cpu_addr) + goto err_free_rps1; memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM); /* the rest + print status message */ /* create a nice device name */ - sprintf(&dev->name[0], "saa7146 (%d)",saa7146_num); + sprintf(dev->name, "saa7146 (%d)", saa7146_num); - INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision,dev->pci->irq,dev->pci->subsystem_vendor,dev->pci->subsystem_device)); + INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device)); dev->ext = ext; pci_set_drvdata(pci,dev); @@ -438,18 +437,18 @@ /* set some sane pci arbitrition values */ saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - if( 0 != ext->probe) { - if( 0 != ext->probe(dev) ) { - DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); + /* TODO: use the status code of the callback */ + err = -ENODEV; - goto probe_error; - } + + if (ext->probe && ext->probe(dev)) { + DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); + goto err_free_i2c; } - if( 0 != ext->attach(dev,pci_ext) ) { + if (ext->attach(dev, pci_ext)) { DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); - err = -ENODEV; - goto attach_error; + goto err_unprobe; } INIT_LIST_HEAD(&dev->item); @@ -457,30 +456,46 @@ saa7146_num++; err = 0; - goto out; -attach_error: -probe_error: +out: + return err; + +err_unprobe: pci_set_drvdata(pci,NULL); - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle); -kmalloc_error_3: - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle); -kmalloc_error_2: - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle); -kmalloc_error_1: - free_irq(dev->pci->irq, (void *)dev); -irq_error: +err_free_i2c: + pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, + dev->d_i2c.dma_handle); +err_free_rps1: + pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, + dev->d_rps1.dma_handle); +err_free_rps0: + pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, + dev->d_rps0.dma_handle); +err_free_irq: + free_irq(pci->irq, (void *)dev); +err_unmap: iounmap(dev->mem); -ioremap_error: - release_mem_region(adr,len); -pci_error: +err_release: + pci_release_region(pci, 0); +err_disable: + pci_disable_device(pci); +err_free: kfree(dev); -out: - return err; + goto out; } static void saa7146_remove_one(struct pci_dev *pdev) { - struct saa7146_dev* dev = (struct saa7146_dev*) pci_get_drvdata(pdev); + struct saa7146_dev* dev = pci_get_drvdata(pdev); + struct { + void *addr; + dma_addr_t dma; + } dev_map[] = { + { dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle }, + { dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle }, + { dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle }, + { NULL, 0 } + }, *p; + DEB_EE(("dev:%p\n",dev)); dev->ext->detach(dev); @@ -491,17 +506,15 @@ /* disable all irqs, release irq-routine */ saa7146_write(dev, IER, 0); - free_irq(dev->pci->irq, (void *)dev); + free_irq(pdev->irq, dev); - /* free kernel memory */ - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle); - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle); - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle); + for (p = dev_map; p->addr; p++) + pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma); iounmap(dev->mem); - release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); - + pci_release_region(pdev, 0); list_del(&dev->item); + pci_disable_device(pdev); kfree(dev); saa7146_num--; diff -Nru a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c --- a/drivers/media/common/saa7146_fops.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/common/saa7146_fops.c 2004-12-12 17:40:52 -08:00 @@ -1,4 +1,5 @@ #include +#include #define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1) @@ -30,17 +31,6 @@ DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources)); up(&dev->lock); return 1; -} - -int saa7146_res_check(struct saa7146_fh *fh, unsigned int bit) -{ - return (fh->resources & bit); -} - -int saa7146_res_locked(struct saa7146_dev *dev, unsigned int bit) -{ - struct saa7146_vv *vv = dev->vv_data; - return (vv->resources & bit); } void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits) diff -Nru a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c --- a/drivers/media/common/saa7146_hlp.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/common/saa7146_hlp.c 2004-12-12 17:40:53 -08:00 @@ -9,11 +9,6 @@ *clip_format |= (( ((palette&0xf00)>>8) << 30) | ((palette&0x00f) << 24) | (((palette&0x0f0)>>4) << 16)); } -static void calculate_bcs_ctrl_register(struct saa7146_dev *dev, int brightness, int contrast, int colour, u32 *bcs_ctrl) -{ - *bcs_ctrl = ((brightness << 24) | (contrast << 16) | (colour << 0)); -} - static void calculate_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync, u32* hps_ctrl) { *hps_ctrl &= ~(MASK_30 | MASK_31 | MASK_28); @@ -62,7 +57,7 @@ }; /* table of attenuation values for horizontal scaling */ -u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0}; +static u8 h_attenuation[] = { 1, 2, 4, 8, 2, 4, 8, 16, 0}; /* calculate horizontal scale registers */ static int calculate_h_scale_registers(struct saa7146_dev *dev, @@ -208,7 +203,7 @@ }; /* table of attenuation values for vertical scaling */ -u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0}; +static u16 v_attenuation[] = { 2, 4, 8, 16, 32, 64, 128, 256, 0}; /* calculate vertical scale registers */ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field field, @@ -619,18 +614,6 @@ saa7146_write(dev, CLIP_FORMAT_CTRL, clip_format); saa7146_write(dev, MC2, (MASK_05 | MASK_21)); } - -void saa7146_set_picture_prop(struct saa7146_dev *dev, int brightness, int contrast, int colour) -{ - u32 bcs_ctrl = 0; - - calculate_bcs_ctrl_register(dev, brightness, contrast, colour, &bcs_ctrl); - saa7146_write(dev, BCS_CTRL, bcs_ctrl); - - /* update the bcs register */ - saa7146_write(dev, MC2, (MASK_06 | MASK_22)); -} - /* select input-source */ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sync) diff -Nru a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c --- a/drivers/media/common/saa7146_i2c.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/common/saa7146_i2c.c 2004-12-12 17:40:53 -08:00 @@ -1,7 +1,7 @@ #include #include -u32 saa7146_i2c_func(struct i2c_adapter *adapter) +static u32 saa7146_i2c_func(struct i2c_adapter *adapter) { //fm DEB_I2C(("'%s'.\n", adapter->name)); diff -Nru a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c --- a/drivers/media/common/saa7146_vbi.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/common/saa7146_vbi.c 2004-12-12 17:40:52 -08:00 @@ -130,7 +130,7 @@ return 0; } -void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) +static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) { struct saa7146_vv *vv = dev->vv_data; diff -Nru a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c --- a/drivers/media/common/saa7146_video.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/common/saa7146_video.c 2004-12-12 17:40:53 -08:00 @@ -2,7 +2,7 @@ static int max_memory = 32; -MODULE_PARM(max_memory,"i"); +module_param(max_memory, int, 0644); MODULE_PARM_DESC(max_memory, "maximum memory usage for capture buffers (default: 32Mb)"); #define IS_CAPTURE_ACTIVE(fh) \ diff -Nru a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig --- a/drivers/media/dvb/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/Kconfig 2004-12-12 17:40:52 -08:00 @@ -21,8 +21,6 @@ source "drivers/media/dvb/dvb-core/Kconfig" -source "drivers/media/dvb/frontends/Kconfig" - comment "Supported SAA7146 based PCI Adapters" depends on DVB_CORE && PCI source "drivers/media/dvb/ttpci/Kconfig" @@ -42,5 +40,8 @@ depends on DVB_CORE && PCI source "drivers/media/dvb/bt8xx/Kconfig" -endmenu +comment "Supported DVB Frontends" + depends on DVB_CORE +source "drivers/media/dvb/frontends/Kconfig" +endmenu diff -Nru a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig --- a/drivers/media/dvb/b2c2/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/b2c2/Kconfig 2004-12-12 17:40:52 -08:00 @@ -1,6 +1,8 @@ config DVB_B2C2_SKYSTAR tristate "Technisat Skystar2 PCI" depends on DVB_CORE && PCI + select DVB_STV0299 + select DVB_MT352 help Support for the Skystar2 PCI DVB card by Technisat, which is equipped with the FlexCopII chipset by B2C2. diff -Nru a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile --- a/drivers/media/dvb/b2c2/Makefile 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/b2c2/Makefile 2004-12-12 17:40:52 -08:00 @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -Nru a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c --- a/drivers/media/dvb/b2c2/skystar2.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/b2c2/skystar2.c 2004-12-12 17:40:53 -08:00 @@ -50,6 +50,8 @@ #include "dvbdev.h" #include "demux.h" #include "dvb_net.h" +#include "stv0299.h" +#include "mt352.h" static int debug; @@ -77,6 +79,9 @@ u8 *buffer; }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) +#define __iomem +#endif struct adapter { struct pci_dev *pdev; @@ -118,6 +123,9 @@ int pid_count; int whole_bandwidth_count; u32 mac_filter; + + struct dvb_frontend* fe; + int (*fe_sleep)(struct dvb_frontend* fe); }; #define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg) @@ -297,13 +305,6 @@ for (i = 0; i < num; i++) { ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - - /* allow only the mt312, mt352 and stv0299 frontends to access the bus */ - if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) && - (msgs[i].addr != 0x61) && (msgs[i].addr != 0x0f)) { - up(&tmp->i2c_sem); - return -EREMOTEIO; - } } // read command @@ -785,7 +786,7 @@ return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len); } -u8 calc_lrc(u8 *buf, int len) +static u8 calc_lrc(u8 *buf, int len) { int i; u8 sum; @@ -1773,6 +1774,7 @@ if (adapter->io_mem) iounmap(adapter->io_mem); + if (adapter != 0) kfree(adapter); } @@ -2024,6 +2026,7 @@ return 0; } +#if 0 /* lnb control */ static void set_tuner_tone(struct adapter *adapter, u8 tone) { @@ -2058,6 +2061,7 @@ write_reg_dw(adapter, 0x200, 0x40ff8000); } } +#endif static void set_tuner_polarity(struct adapter *adapter, u8 polarity) { @@ -2085,6 +2089,7 @@ write_reg_dw(adapter, 0x204, var); } +#if 0 static void diseqc_send_bit(struct adapter *adapter, int data) { set_tuner_tone(adapter, 1); @@ -2135,7 +2140,7 @@ } -int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg) +static int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg) { switch (cmd) { case FE_SET_TONE: @@ -2169,107 +2174,252 @@ return 0; } +#endif -static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct adapter *adapter = fe->before_after_data; - - struct dvb_frontend_info info; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; - fe->ioctl(fe, FE_GET_INFO, &info); + dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - // we must use different DiSEqC hw + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); + set_tuner_polarity(adapter, 1); + return 0; - if (strcmp(info.name, "Zarlink MT312") == 0) { - //VP310 using mt312 driver for tuning only: diseqc not wired - //use FCII instead - if (!soft_diseqc(adapter, cmd, arg)) + case SEC_VOLTAGE_18: + dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); + set_tuner_polarity(adapter, 2); return 0; + + default: + return -EINVAL; + } } - switch (cmd) { - case FE_SLEEP: +static int flexcop_sleep(struct dvb_frontend* fe) { - dprintk("%s: FE_SLEEP\n", __FUNCTION__); + struct adapter* adapter = (struct adapter*) fe->dvb->priv; + dprintk("%s: FE_SLEEP\n", __FUNCTION__); set_tuner_polarity(adapter, 0); - // return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend. - return -EOPNOTSUPP; + if (adapter->fe_sleep) return adapter->fe_sleep(fe); + return 0; } - case FE_SET_VOLTAGE: +static u32 flexcop_i2c_func(struct i2c_adapter *adapter) { - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - - switch ((fe_sec_voltage_t) arg) { - case SEC_VOLTAGE_13: + printk("flexcop_i2c_func\n"); - dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); + return I2C_FUNC_I2C; +} - set_tuner_polarity(adapter, 1); +static struct i2c_algorithm flexcop_algo = { + .name = "flexcop i2c algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = master_xfer, + .functionality = flexcop_i2c_func, +}; - return 0; - case SEC_VOLTAGE_18: - dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); - set_tuner_polarity(adapter, 2); +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; - return 0; + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); - default: + return 0; +} - return -EINVAL; - }; - } +static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; + div = params->frequency / 125; - default: + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; // 0xC4 + buf[3] = 0x08; - return -EOPNOTSUPP; - }; + if (params->frequency < 1500000) buf[3] |= 0x10; + if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, + }; + +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, + .pll_set = samsung_tbmu24112_pll_set, +}; + + + + -static int client_register(struct i2c_client *client) +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) { - struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter); + static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - dprintk("client_register\n"); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - if (client->driver->command) - return client->driver->command(client, FE_REGISTER, adapter->dvb_adapter); return 0; } -static int client_unregister(struct i2c_client *client) +int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) { - struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter); + u32 div; + unsigned char bs = 0; - dprintk("client_unregister\n"); + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; + if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; + if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; + + pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = 0xcc; + pllbuf[4] = bs; - if (client->driver->command) - return client->driver->command(client, FE_UNREGISTER, adapter->dvb_adapter); return 0; } -u32 flexcop_i2c_func(struct i2c_adapter *adapter) +static struct mt352_config samsung_tdtc9251dh0_config = { + + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, + .pll_set = samsung_tdtc9251dh0_pll_set, +}; + + + + + +static void frontend_init(struct adapter *skystar2) { - printk("flexcop_i2c_func\n"); + switch(skystar2->pdev->device) { + case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 - return I2C_FUNC_I2C; + // try the skystar2 first (stv0299/Samsung tbmu24112(sl1935)) + skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe->ops->set_voltage = flexcop_set_voltage; + skystar2->fe_sleep = skystar2->fe->ops->sleep; + skystar2->fe->ops->sleep = flexcop_sleep; + break; } -static struct i2c_algorithm flexcop_algo = { - .name = "flexcop i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = master_xfer, - .functionality = flexcop_i2c_func, -}; + // try the airstar2 (mt352/Samsung tdtc9251dh0(??)) + skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe->ops->info.frequency_min = 474000000; + skystar2->fe->ops->info.frequency_max = 858000000; + break; + } + break; + } + + if (skystar2->fe == NULL) { + printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + skystar2->pdev->vendor, + skystar2->pdev->device, + skystar2->pdev->subsystem_vendor, + skystar2->pdev->subsystem_device); + } else { + if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) { + printk("skystar2: Frontend registration failed!\n"); + if (skystar2->fe->ops->release) + skystar2->fe->ops->release(skystar2->fe); + skystar2->fe = NULL; + } + } +} static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -2298,8 +2448,10 @@ adapter = (struct adapter *) pci_get_drvdata(pdev); + dvb_adapter->priv = adapter; adapter->dvb_adapter = dvb_adapter; + init_MUTEX(&adapter->i2c_sem); @@ -2316,16 +2468,12 @@ adapter->i2c_adap.algo = &flexcop_algo; adapter->i2c_adap.algo_data = NULL; adapter->i2c_adap.id = I2C_ALGO_BIT; - adapter->i2c_adap.client_register = client_register; - adapter->i2c_adap.client_unregister = client_unregister; if (i2c_add_adapter(&adapter->i2c_adap) < 0) { dvb_unregister_adapter (adapter->dvb_adapter); return -ENOMEM; } - dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter); - dvbdemux = &adapter->demux; dvbdemux->priv = (void *) adapter; @@ -2361,6 +2509,9 @@ return ret; dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); + + frontend_init(adapter); + return 0; } @@ -2385,9 +2536,9 @@ dvb_dmxdev_release(&adapter->dmxdev); dvb_dmx_release(&adapter->demux); - if (adapter->dvb_adapter != NULL) { - dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL); + if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe); + if (adapter->dvb_adapter != NULL) { i2c_del_adapter(&adapter->i2c_adap); dvb_unregister_adapter(adapter->dvb_adapter); @@ -2398,7 +2549,7 @@ static struct pci_device_id skystar2_pci_tbl[] = { {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, - {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, //FCIII +/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII {0,}, }; diff -Nru a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig --- a/drivers/media/dvb/bt8xx/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/bt8xx/Kconfig 2004-12-12 17:40:52 -08:00 @@ -1,6 +1,8 @@ config DVB_BT8XX tristate "Nebula/Pinnacle PCTV/Twinhan PCI cards" depends on DVB_CORE && PCI && VIDEO_BT848 + select DVB_MT352 + select DVB_SP887X help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards. diff -Nru a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile --- a/drivers/media/dvb/bt8xx/Makefile 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/bt8xx/Makefile 2004-12-12 17:40:53 -08:00 @@ -1,5 +1,5 @@ -obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o +obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video -Idrivers/media/dvb/frontends diff -Nru a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c --- a/drivers/media/dvb/bt8xx/bt878.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/bt8xx/bt878.c 2004-12-12 17:40:52 -08:00 @@ -44,7 +44,7 @@ #include "dmxdev.h" #include "dvbdev.h" #include "bt878.h" -#include "dst-bt878.h" +#include "dst_priv.h" /**************************************/ @@ -559,22 +559,11 @@ static int bt878_pci_driver_registered = 0; -/* This will be used later by dvb-bt8xx to only use the audio - * dma of certain cards */ -int bt878_find_audio_dma(void) -{ - // pci_register_driver(&bt878_pci_driver); - bt878_pci_driver_registered = 1; - return 0; -} - -EXPORT_SYMBOL(bt878_find_audio_dma); - /*******************************/ /* Module management functions */ /*******************************/ -int bt878_init_module(void) +static int bt878_init_module(void) { bt878_num = 0; bt878_pci_driver_registered = 0; @@ -586,13 +575,13 @@ /* bt878_check_chipset(); */ - /* later we register inside of bt878_find_audio_dma + /* later we register inside of bt878_find_audio_dma() * because we may want to ignore certain cards */ bt878_pci_driver_registered = 1; return pci_module_init(&bt878_pci_driver); } -void bt878_cleanup_module(void) +static void bt878_cleanup_module(void) { if (bt878_pci_driver_registered) { bt878_pci_driver_registered = 0; @@ -601,12 +590,10 @@ return; } -EXPORT_SYMBOL(bt878_init_module); -EXPORT_SYMBOL(bt878_cleanup_module); module_init(bt878_init_module); module_exit(bt878_cleanup_module); - +//MODULE_AUTHOR("XXX"); MODULE_LICENSE("GPL"); /* diff -Nru a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/bt8xx/dst.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,1089 @@ +/* + Frontend-driver for TwinHan DST Frontend + + Copyright (C) 2003 Jamie Honan + + 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 "dvb_frontend.h" +#include "dst_priv.h" +#include "dst.h" + +struct dst_state { + + struct i2c_adapter* i2c; + + struct bt878* bt; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct dst_config* config; + + struct dvb_frontend frontend; + + /* private demodulator data */ + u8 tx_tuna[10]; + u8 rx_tuna[10]; + u8 rxbuffer[10]; + u8 diseq_flags; + u8 dst_type; + u32 type_flags; + u32 frequency; /* intermediate frequency in kHz for QPSK */ + fe_spectral_inversion_t inversion; + u32 symbol_rate; /* symbol rate in Symbols per second */ + fe_code_rate_t fec; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + u32 decode_freq; + u8 decode_lock; + u16 decode_strength; + u16 decode_snr; + unsigned long cur_jiff; + u8 k22; + fe_bandwidth_t bandwidth; +}; + +static unsigned int dst_verbose = 0; +module_param(dst_verbose, int, 0644); +MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)"); +static unsigned int dst_debug = 0; +module_param(dst_debug, int, 0644); +MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)"); + +#define dprintk if (dst_debug) printk + +#define DST_TYPE_IS_SAT 0 +#define DST_TYPE_IS_TERR 1 +#define DST_TYPE_IS_CABLE 2 + +#define DST_TYPE_HAS_NEWTUNE 1 +#define DST_TYPE_HAS_TS204 2 +#define DST_TYPE_HAS_SYMDIV 4 + +#define HAS_LOCK 1 +#define ATTEMPT_TUNE 2 +#define HAS_POWER 4 + +static void dst_packsize(struct dst_state* state, int psize) +{ + union dst_gpio_packet bits; + + bits.psize = 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) +{ + union dst_gpio_packet enb; + union dst_gpio_packet bits; + int err; + + enb.enb.mask = mask; + enb.enb.enable = enbb; + if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { + dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb); + return -EREMOTEIO; + } + + /* because complete disabling means no output, no need to do output packet */ + if (enbb == 0) + return 0; + + bits.outp.mask = enbb; + bits.outp.highvals = outhigh; + + if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { + dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh); + return -EREMOTEIO; + } + return 0; +} + +static int dst_gpio_inb(struct dst_state *state, u8 * result) +{ + union dst_gpio_packet rd_packet; + int err; + + *result = 0; + + if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { + dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err); + return -EREMOTEIO; + } + + *result = (u8) rd_packet.rd.value; + return 0; +} + +#define DST_I2C_ENABLE 1 +#define DST_8820 2 + +static int dst_reset8820(struct dst_state *state) +{ + int retval; + /* pull 8820 gpio pin low, wait, high, wait, then low */ + // dprintk ("%s: reset 8820\n", __FUNCTION__); + retval = dst_gpio_outb(state, DST_8820, DST_8820, 0); + if (retval < 0) + return retval; + msleep(10); + retval = dst_gpio_outb(state, DST_8820, DST_8820, DST_8820); + if (retval < 0) + return retval; + /* wait for more feedback on what works here * + msleep(10); + retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0); + if (retval < 0) + return retval; + */ + return 0; +} + +static int dst_i2c_enable(struct dst_state *state) +{ + int retval; + /* pull I2C enable gpio pin low, wait */ + // dprintk ("%s: i2c enable\n", __FUNCTION__); + retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0); + if (retval < 0) + return retval; + // dprintk ("%s: i2c enable delay\n", __FUNCTION__); + msleep(33); + return 0; +} + +static int dst_i2c_disable(struct dst_state *state) +{ + int retval; + /* release I2C enable gpio pin, wait */ + // dprintk ("%s: i2c disable\n", __FUNCTION__); + retval = dst_gpio_outb(state, ~0, 0, 0); + if (retval < 0) + return retval; + // dprintk ("%s: i2c disable delay\n", __FUNCTION__); + msleep(33); + return 0; +} + +static int dst_wait_dst_ready(struct dst_state *state) +{ + u8 reply; + int retval; + int i; + for (i = 0; i < 200; i++) { + retval = dst_gpio_inb(state, &reply); + if (retval < 0) + return retval; + if ((reply & DST_I2C_ENABLE) == 0) { + dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); + return 1; + } + msleep(10); + } + dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); + return 0; +} + +static int write_dst(struct dst_state *state, u8 * data, u8 len) +{ + struct i2c_msg msg = { + .addr = state->config->demod_address,.flags = 0,.buf = data,.len = len + }; + int err; + int cnt; + + if (dst_debug && dst_verbose) { + u8 i; + dprintk("%s writing", __FUNCTION__); + for (i = 0; i < len; i++) { + dprintk(" 0x%02x", data[i]); + } + dprintk("\n"); + } + msleep(30); + for (cnt = 0; cnt < 4; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); + dst_i2c_disable(state); + msleep(500); + dst_i2c_enable(state); + msleep(500); + continue; + } else + break; + } + if (cnt >= 4) + return -EREMOTEIO; + return 0; +} + +static int read_dst(struct dst_state *state, u8 * ret, u8 len) +{ + struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len }; + int err; + int cnt; + + for (cnt = 0; cnt < 4; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]); + dst_i2c_disable(state); + dst_i2c_enable(state); + continue; + } else + break; + } + if (cnt >= 4) + return -EREMOTEIO; + dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); + if (dst_debug && dst_verbose) { + for (err = 1; err < len; err++) + dprintk(" 0x%x", ret[err]); + if (err > 1) + dprintk("\n"); + } + return 0; +} + +static int dst_set_freq(struct dst_state *state, u32 freq) +{ + u8 *val; + + state->frequency = freq; + + // dprintk("%s: set frequency %u\n", __FUNCTION__, freq); + if (state->dst_type == DST_TYPE_IS_SAT) { + freq = freq / 1000; + if (freq < 950 || freq > 2150) + return -EINVAL; + val = &state->tx_tuna[0]; + val[2] = (freq >> 8) & 0x7f; + val[3] = (u8) freq; + val[4] = 1; + val[8] &= ~4; + if (freq < 1531) + val[8] |= 4; + } else if (state->dst_type == DST_TYPE_IS_TERR) { + freq = freq / 1000; + if (freq < 137000 || freq > 858000) + return -EINVAL; + val = &state->tx_tuna[0]; + val[2] = (freq >> 16) & 0xff; + val[3] = (freq >> 8) & 0xff; + val[4] = (u8) freq; + val[5] = 0; + switch (state->bandwidth) { + case BANDWIDTH_6_MHZ: + val[6] = 6; + break; + + case BANDWIDTH_7_MHZ: + case BANDWIDTH_AUTO: + val[6] = 7; + break; + + case BANDWIDTH_8_MHZ: + val[6] = 8; + break; + } + + val[7] = 0; + val[8] = 0; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + /* guess till will get one */ + freq = freq / 1000; + val = &state->tx_tuna[0]; + val[2] = (freq >> 16) & 0xff; + val[3] = (freq >> 8) & 0xff; + val[4] = (u8) freq; + } else + return -EINVAL; + return 0; +} + +static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) +{ + u8 *val; + + state->bandwidth = bandwidth; + + if (state->dst_type != DST_TYPE_IS_TERR) + return 0; + + val = &state->tx_tuna[0]; + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + val[6] = 6; + break; + + case BANDWIDTH_7_MHZ: + val[6] = 7; + break; + + case BANDWIDTH_8_MHZ: + val[6] = 8; + break; + + default: + return -EINVAL; + } + return 0; +} + +static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion) +{ + u8 *val; + + state->inversion = inversion; + + val = &state->tx_tuna[0]; + + val[8] &= ~0x80; + + switch (inversion) { + case INVERSION_OFF: + break; + case INVERSION_ON: + val[8] |= 0x80; + break; + default: + return -EINVAL; + } + return 0; +} + +static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec) +{ + state->fec = fec; + return 0; +} + +static fe_code_rate_t dst_get_fec(struct dst_state* state) +{ + return state->fec; +} + +static int dst_set_symbolrate(struct dst_state* state, u32 srate) +{ + u8 *val; + u32 symcalc; + u64 sval; + + state->symbol_rate = srate; + + if (state->dst_type == DST_TYPE_IS_TERR) { + return 0; + } + // dprintk("%s: set srate %u\n", __FUNCTION__, srate); + srate /= 1000; + val = &state->tx_tuna[0]; + + if (state->type_flags & DST_TYPE_HAS_SYMDIV) { + sval = srate; + sval <<= 20; + do_div(sval, 88000); + symcalc = (u32) sval; + // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); + val[5] = (u8) (symcalc >> 12); + val[6] = (u8) (symcalc >> 4); + val[7] = (u8) (symcalc << 4); + } else { + val[5] = (u8) (srate >> 16) & 0x7f; + val[6] = (u8) (srate >> 8); + val[7] = (u8) srate; + } + val[8] &= ~0x20; + if (srate > 8000) + val[8] |= 0x20; + return 0; +} + +static u8 dst_check_sum(u8 * buf, u32 len) +{ + u32 i; + u8 val = 0; + if (!len) + return 0; + for (i = 0; i < len; i++) { + val += buf[i]; + } + return ((~val) + 1); +} + +struct dst_types { + char *mstr; + int offs; + u8 dst_type; + u32 type_flags; +}; + +static struct dst_types dst_tlist[] = { + {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, + {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, + {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204}, + {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, + {"DST-CI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, + {"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, + {"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, + {"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE}, + {"DCT-CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204}, + {"DTTDIG", 1, DST_TYPE_IS_TERR, 0} +}; + +/* DCTNEW and DCT-CI are guesses */ + +static void dst_type_flags_print(u32 type_flags) +{ + printk("DST type flags :"); + if (type_flags & DST_TYPE_HAS_NEWTUNE) + printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); + if (type_flags & DST_TYPE_HAS_TS204) + printk(" 0x%x ts204", DST_TYPE_HAS_TS204); + if (type_flags & DST_TYPE_HAS_SYMDIV) + printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + printk("\n"); +} + +static int dst_type_print(u8 type) +{ + char *otype; + switch (type) { + case DST_TYPE_IS_SAT: + otype = "satellite"; + break; + case DST_TYPE_IS_TERR: + otype = "terrestial TV"; + break; + case DST_TYPE_IS_CABLE: + otype = "terrestial TV"; + break; + default: + printk("%s: invalid dst type %d\n", __FUNCTION__, type); + return -EINVAL; + } + printk("DST type : %s\n", otype); + return 0; +} + +static int dst_check_ci(struct dst_state *state) +{ + u8 txbuf[8]; + u8 rxbuf[8]; + int retval; + int i; + struct dst_types *dsp; + u8 use_dst_type; + u32 use_type_flags; + + memset(txbuf, 0, sizeof(txbuf)); + txbuf[1] = 6; + txbuf[7] = dst_check_sum(txbuf, 7); + + dst_i2c_enable(state); + dst_reset8820(state); + retval = write_dst(state, txbuf, 8); + if (retval < 0) { + dst_i2c_disable(state); + dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__); + return retval; + } + msleep(3); + retval = read_dst(state, rxbuf, 1); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__); + return retval; + } + if (rxbuf[0] != 0xff) { + dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]); + return retval; + } + if (!dst_wait_dst_ready(state)) + return 0; + // dst_i2c_enable(i2c); Dimitri + retval = read_dst(state, rxbuf, 8); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read not successful\n", __FUNCTION__); + return retval; + } + if (rxbuf[7] != dst_check_sum(rxbuf, 7)) { + dprintk("%s: checksum failure\n", __FUNCTION__); + return retval; + } + rxbuf[7] = '\0'; + for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) { + if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) { + use_type_flags = dsp->type_flags; + use_dst_type = dsp->dst_type; + printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr); + break; + } + } + if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) { + printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]); + printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); + use_dst_type = DST_TYPE_IS_SAT; + use_type_flags = DST_TYPE_HAS_SYMDIV; + } + dst_type_print(use_dst_type); + + state->type_flags = use_type_flags; + state->dst_type = use_dst_type; + dst_type_flags_print(state->type_flags); + + if (state->type_flags & DST_TYPE_HAS_TS204) { + dst_packsize(state, 204); + } + return 0; +} + +static int dst_command(struct dst_state* state, u8 * data, u8 len) +{ + int retval; + u8 reply; + + dst_i2c_enable(state); + dst_reset8820(state); + retval = write_dst(state, data, len); + if (retval < 0) { + dst_i2c_disable(state); + dprintk("%s: write not successful\n", __FUNCTION__); + return retval; + } + msleep(33); + retval = read_dst(state, &reply, 1); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read verify not successful\n", __FUNCTION__); + return retval; + } + if (reply != 0xff) { + dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); + return 0; + } + if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) + return 0; + if (!dst_wait_dst_ready(state)) + return 0; + // dst_i2c_enable(i2c); Per dimitri + retval = read_dst(state, state->rxbuffer, 8); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read not successful\n", __FUNCTION__); + return 0; + } + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { + dprintk("%s: checksum failure\n", __FUNCTION__); + return 0; + } + return 0; +} + +static int dst_get_signal(struct dst_state* state) +{ + int retval; + u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; + + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (0 == (state->diseq_flags & HAS_LOCK)) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { + retval = dst_command(state, get_signal, 8); + if (retval < 0) + return retval; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; + state->decode_strength = state->rxbuffer[5] << 8; + state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; + } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { + state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; + state->decode_strength = state->rxbuffer[4] << 8; + state->decode_snr = state->rxbuffer[3] << 8; + } + state->cur_jiff = jiffies; + } + return 0; +} + +static int dst_tone_power_cmd(struct dst_state* state) +{ + u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + if (state->voltage == SEC_VOLTAGE_OFF) + paket[4] = 0; + else + paket[4] = 1; + if (state->tone == SEC_TONE_ON) + paket[2] = state->k22; + else + paket[2] = 0; + paket[7] = dst_check_sum(&paket[0], 7); + dst_command(state, paket, 8); + return 0; +} + +static int dst_get_tuna(struct dst_state* state) +{ + int retval; + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) + return 0; + state->diseq_flags &= ~(HAS_LOCK); + if (!dst_wait_dst_ready(state)) + return 0; + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + /* how to get variable length reply ???? */ + retval = read_dst(state, state->rx_tuna, 10); + } else { + retval = read_dst(state, &state->rx_tuna[2], 8); + } + if (retval < 0) { + dprintk("%s: read not successful\n", __FUNCTION__); + return 0; + } + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { + dprintk("%s: checksum failure?\n", __FUNCTION__); + return 0; + } + } else { + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { + dprintk("%s: checksum failure?\n", __FUNCTION__); + return 0; + } + } + if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) + return 0; + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; + + state->decode_lock = 1; + /* + dst->decode_n1 = (dst->rx_tuna[4] << 8) + + (dst->rx_tuna[5]); + + dst->decode_n2 = (dst->rx_tuna[8] << 8) + + (dst->rx_tuna[7]); + */ + state->diseq_flags |= HAS_LOCK; + /* dst->cur_jiff = jiffies; */ + return 1; +} + +static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + +static int dst_write_tuna(struct dvb_frontend* fe) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + int retval; + u8 reply; + + dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags); + state->decode_freq = 0; + state->decode_lock = state->decode_strength = state->decode_snr = 0; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (!(state->diseq_flags & HAS_POWER)) + dst_set_voltage(fe, SEC_VOLTAGE_13); + } + state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); + dst_i2c_enable(state); + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + dst_reset8820(state); + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); + retval = write_dst(state, &state->tx_tuna[0], 10); + } else { + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); + retval = write_dst(state, &state->tx_tuna[2], 8); + } + if (retval < 0) { + dst_i2c_disable(state); + dprintk("%s: write not successful\n", __FUNCTION__); + return retval; + } + msleep(3); + retval = read_dst(state, &reply, 1); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read verify not successful\n", __FUNCTION__); + return retval; + } + if (reply != 0xff) { + dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); + return 0; + } + state->diseq_flags |= ATTEMPT_TUNE; + return dst_get_tuna(state); +} + +/* + * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 + * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 + * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 + * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 + * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec + * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 + * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 + * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 + */ + +static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + if (cmd->msg_len == 0 || cmd->msg_len > 4) + return -EINVAL; + memcpy(&paket[3], cmd->msg, cmd->msg_len); + paket[7] = dst_check_sum(&paket[0], 7); + dst_command(state, paket, 8); + return 0; +} + +static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + u8 *val; + int need_cmd; + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + state->voltage = voltage; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + need_cmd = 0; + val = &state->tx_tuna[0]; + val[8] &= ~0x40; + switch (voltage) { + case SEC_VOLTAGE_13: + if ((state->diseq_flags & HAS_POWER) == 0) + need_cmd = 1; + state->diseq_flags |= HAS_POWER; + break; + case SEC_VOLTAGE_18: + if ((state->diseq_flags & HAS_POWER) == 0) + need_cmd = 1; + state->diseq_flags |= HAS_POWER; + val[8] |= 0x40; + break; + case SEC_VOLTAGE_OFF: + need_cmd = 1; + state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); + break; + default: + return -EINVAL; + } + if (need_cmd) { + dst_tone_power_cmd(state); + } + return 0; +} + +static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + u8 *val; + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + state->tone = tone; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + val = &state->tx_tuna[0]; + + val[8] &= ~0x1; + + switch (tone) { + case SEC_TONE_OFF: + break; + case SEC_TONE_ON: + val[8] |= 1; + break; + default: + return -EINVAL; + } + dst_tone_power_cmd(state); + return 0; +} + +static int dst_init(struct dvb_frontend* fe) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 }; + static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 }; + static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + state->inversion = INVERSION_ON; + state->voltage = SEC_VOLTAGE_13; + state->tone = SEC_TONE_OFF; + state->symbol_rate = 29473000; + state->fec = FEC_AUTO; + state->diseq_flags = 0; + state->k22 = 0x02; + state->bandwidth = BANDWIDTH_7_MHZ; + state->cur_jiff = jiffies; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->frequency = 950000; + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna)); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + state->frequency = 137000000; + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna)); + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + state->frequency = 51000000; + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna)); + } + + return 0; +} + +static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + *status = 0; + if (state->diseq_flags & HAS_LOCK) { + dst_get_signal(state); + if (state->decode_lock) + *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; + } + + return 0; +} + +static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + dst_get_signal(state); + *strength = state->decode_strength; + + return 0; +} + +static int dst_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + dst_get_signal(state); + *snr = state->decode_snr; + + return 0; +} + +static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + dst_set_freq(state, p->frequency); + dst_set_inversion(state, p->inversion); + if (state->dst_type == DST_TYPE_IS_SAT) { + dst_set_fec(state, p->u.qpsk.fec_inner); + dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + dst_set_bandwidth(state, p->u.ofdm.bandwidth); + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + dst_set_fec(state, p->u.qam.fec_inner); + dst_set_symbolrate(state, p->u.qam.symbol_rate); + } + dst_write_tuna(fe); + + return 0; +} + +static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + p->frequency = state->decode_freq; + p->inversion = state->inversion; + if (state->dst_type == DST_TYPE_IS_SAT) { + p->u.qpsk.symbol_rate = state->symbol_rate; + p->u.qpsk.fec_inner = dst_get_fec(state); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + p->u.ofdm.bandwidth = state->bandwidth; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + p->u.qam.symbol_rate = state->symbol_rate; + p->u.qam.fec_inner = dst_get_fec(state); + p->u.qam.modulation = QAM_AUTO; + } + + return 0; +} + +static void dst_release(struct dvb_frontend* fe) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops dst_dvbt_ops; +static struct dvb_frontend_ops dst_dvbs_ops; +static struct dvb_frontend_ops dst_dvbc_ops; + +struct dvb_frontend* dst_attach(const struct dst_config* config, + struct i2c_adapter* i2c, + struct bt878 *bt) +{ + struct dst_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->bt = bt; + + /* check if the demod is there */ + if (dst_check_ci(state) < 0) goto error; + + /* determine settings based on type */ + switch (state->dst_type) { + case DST_TYPE_IS_TERR: + memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_CABLE: + memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_SAT: + memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); + break; + default: + printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n"); + goto error; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops dst_dvbt_ops = { + + .info = { + .name = "DST DVB-T", + .type = FE_OFDM, + .frequency_min = 137000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = dst_release, + + .init = dst_init, + + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +static struct dvb_frontend_ops dst_dvbs_ops = { + + .info = { + .name = "DST DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* . symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK + }, + + .release = dst_release, + + .init = dst_init, + + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, + + .diseqc_send_master_cmd = dst_set_diseqc, + .set_voltage = dst_set_voltage, + .set_tone = dst_set_tone, +}; + +static struct dvb_frontend_ops dst_dvbc_ops = { + + .info = { + .name = "DST DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* . symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO + }, + + .release = dst_release, + + .init = dst_init, + + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver"); +MODULE_AUTHOR("Jamie Honan"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(dst_attach); diff -Nru a/drivers/media/dvb/bt8xx/dst.h b/drivers/media/dvb/bt8xx/dst.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/bt8xx/dst.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,40 @@ +/* + Frontend-driver for TwinHan DST Frontend + + Copyright (C) 2003 Jamie Honan + + 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 DST_H +#define DST_H + +#include +#include +#include "bt878.h" + +struct dst_config +{ + /* the demodulator's i2c address */ + u8 demod_address; +}; + +extern struct dvb_frontend* dst_attach(const struct dst_config* config, + struct i2c_adapter* i2c, + struct bt878 *bt); + +#endif // DST_H diff -Nru a/drivers/media/dvb/bt8xx/dst_priv.h b/drivers/media/dvb/bt8xx/dst_priv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/bt8xx/dst_priv.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,37 @@ +/* + * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend + * + * Copyright (C) 2003 Jamie Honan + */ + +struct dst_gpio_enable { + u32 mask; + u32 enable; +}; + +struct dst_gpio_output { + u32 mask; + u32 highvals; +}; + +struct dst_gpio_read { + unsigned long value; +}; + +union dst_gpio_packet { + struct dst_gpio_enable enb; + struct dst_gpio_output outp; + struct dst_gpio_read rd; + int psize; +}; + +#define DST_IG_ENABLE 0 +#define DST_IG_WRITE 1 +#define DST_IG_READ 2 +#define DST_IG_TS 3 + +struct bt878; + +int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); + +struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap); diff -Nru a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c 2004-12-12 17:40:52 -08:00 @@ -126,7 +126,286 @@ return NULL; } -static int __init dvb_bt8xx_load_card( struct dvb_bt8xx_card *card) + +static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; + static u8 mt352_gpp_ctl_cfg [] = { 0x75, 0x33 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency < 542000000) cp = 0xb4; + else if (params->frequency < 771000000) cp = 0xbc; + else cp = 0xf4; + + if (params->frequency == 0) bs = 0x03; + else if (params->frequency < 443250000) bs = 0x02; + else bs = 0x08; + + pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 0; +} + +static struct mt352_config thomson_dtt7579_config = { + + .demod_address = 0x0f, + .demod_init = thomson_dtt7579_demod_init, + .pll_set = thomson_dtt7579_pll_set, +}; + + + +static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 cfg, cpump, band_select; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36000000 + params->frequency + 83333) / 166666; + cfg = 0x88; + + if (params->frequency < 175000000) cpump = 2; + else if (params->frequency < 390000000) cpump = 1; + else if (params->frequency < 470000000) cpump = 2; + else if (params->frequency < 750000000) cpump = 2; + else cpump = 3; + + if (params->frequency < 175000000) band_select = 0x0e; + else if (params->frequency < 470000000) band_select = 0x05; + else band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = cpump | band_select; + + i2c_transfer(card->i2c_adapter, &msg, 1); + return (div * 166666 - 36000000); +} + +static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; + + return request_firmware(fw, name, &bt->bt->dev->dev); +} + +struct sp887x_config microtune_mt7202dtf_config = { + + .demod_address = 0x70, + .pll_set = microtune_mt7202dtf_pll_set, + .request_firmware = microtune_mt7202dtf_request_firmware, +}; + + + +static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + udelay(2000); + mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency < 150000000) cp = 0xB4; + else if (params->frequency < 173000000) cp = 0xBC; + else if (params->frequency < 250000000) cp = 0xB4; + else if (params->frequency < 400000000) cp = 0xBC; + else if (params->frequency < 420000000) cp = 0xF4; + else if (params->frequency < 470000000) cp = 0xFC; + else if (params->frequency < 600000000) cp = 0xBC; + else if (params->frequency < 730000000) cp = 0xF4; + else cp = 0xFC; + + if (params->frequency < 150000000) bs = 0x01; + else if (params->frequency < 173000000) bs = 0x01; + else if (params->frequency < 250000000) bs = 0x02; + else if (params->frequency < 400000000) bs = 0x02; + else if (params->frequency < 420000000) bs = 0x02; + else if (params->frequency < 470000000) bs = 0x02; + else if (params->frequency < 600000000) bs = 0x08; + else if (params->frequency < 730000000) bs = 0x08; + else bs = 0x08; + + pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 0; +} + +static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { + + .demod_address = 0x0f, + .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, + .pll_set = advbt771_samsung_tdtc9251dh0_pll_set, +}; + + +static struct dst_config dst_config = { + + .demod_address = 0x55, +}; + + +static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; + + div = (params->frequency + 36166667) / 166667; + + buf[0] = (div >> 8) & 0x7F; + buf[1] = div & 0xFF; + buf[2] = 0x85; + if ((params->frequency >= 47000000) && (params->frequency < 153000000)) + buf[3] = 0x01; + else if ((params->frequency >= 153000000) && (params->frequency < 430000000)) + buf[3] = 0x02; + else if ((params->frequency >= 430000000) && (params->frequency < 824000000)) + buf[3] = 0x0C; + else if ((params->frequency >= 824000000) && (params->frequency < 863000000)) + buf[3] = 0x8C; + else + return -EINVAL; + + i2c_transfer(card->i2c_adapter, &msg, 1); + return 0; +} + +static struct nxt6000_config vp3021_alps_tded4_config = { + + .demod_address = 0x0a, + .clock_inversion = 1, + .pll_set = vp3021_alps_tded4_pll_set, +}; + + +static void frontend_init(struct dvb_bt8xx_card *card, u32 type) +{ + switch(type) { +#ifdef BTTV_DVICO_DVBT_LITE + case BTTV_DVICO_DVBT_LITE: + card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops->info.frequency_min = 174000000; + card->fe->ops->info.frequency_max = 862000000; + break; + } + break; +#endif + +#ifdef BTTV_TWINHAN_VP3021 + case BTTV_TWINHAN_VP3021: +#else + case BTTV_NEBULA_DIGITV: +#endif + card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); + if (card->fe != NULL) { + break; + } + break; + + case BTTV_AVDVBT_761: + card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter); + if (card->fe != NULL) { + break; + } + break; + + case BTTV_AVDVBT_771: + card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops->info.frequency_min = 174000000; + card->fe->ops->info.frequency_max = 862000000; + break; + } + break; + + case BTTV_TWINHAN_DST: + card->fe = dst_attach(&dst_config, card->i2c_adapter, card->bt); + if (card->fe != NULL) { + break; + } + break; + } + + if (card->fe == NULL) { + printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + card->bt->dev->vendor, + card->bt->dev->device, + card->bt->dev->subsystem_vendor, + card->bt->dev->subsystem_device); + } else { + if (dvb_register_frontend(card->dvb_adapter, card->fe)) { + printk("dvb-bt8xx: Frontend registration failed!\n"); + if (card->fe->ops->release) + card->fe->ops->release(card->fe); + card->fe = NULL; + } + } +} + +static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) { int result; @@ -136,6 +415,7 @@ return result; } + card->dvb_adapter->priv = card; card->bt->adapter = card->i2c_adapter; @@ -207,6 +487,8 @@ tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); + frontend_init(card, type); + return 0; } @@ -228,7 +510,7 @@ switch(sub->core->type) { - case BTTV_PINNACLESAT: +/* case BTTV_PINNACLESAT: UNDEFINED HARDWARE */ #ifdef BTTV_DVICO_DVBT_LITE case BTTV_DVICO_DVBT_LITE: #endif @@ -240,7 +522,11 @@ * DA_APP(parallel) */ break; +#ifdef BTTV_TWINHAN_VP3021 + case BTTV_TWINHAN_VP3021: +#else case BTTV_NEBULA_DIGITV: +#endif case BTTV_AVDVBT_761: card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->op_sync_orin = 0; @@ -302,7 +588,7 @@ init_MUTEX(&card->bt->gpio_lock); card->bt->bttv_nr = sub->core->nr; - if ( (ret = dvb_bt8xx_load_card(card)) ) { + if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { kfree(card); return ret; } @@ -324,6 +610,7 @@ card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); + if (card->fe) dvb_unregister_frontend(card->fe); dvb_unregister_adapter(card->dvb_adapter); kfree(card); @@ -331,24 +618,6 @@ return 0; } -static void dvb_bt8xx_i2c_info(struct bttv_sub_device *sub, - struct i2c_client *client, int attach) -{ - struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); - - if (attach) { - printk("xxx attach\n"); - if (client->driver->command) - client->driver->command(client, FE_REGISTER, - card->dvb_adapter); - } else { - printk("xxx detach\n"); - if (client->driver->command) - client->driver->command(client, FE_UNREGISTER, - card->dvb_adapter); - } -} - static struct bttv_sub_driver driver = { .drv = { .name = "dvb-bt8xx", @@ -360,7 +629,6 @@ * .resume = dvb_bt8xx_resume, */ }, - .i2c_info = dvb_bt8xx_i2c_info, }; static int __init dvb_bt8xx_init(void) diff -Nru a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h 2004-12-12 17:40:53 -08:00 @@ -26,6 +26,10 @@ #include "dvbdev.h" #include "dvb_net.h" #include "bttv.h" +#include "mt352.h" +#include "sp887x.h" +#include "dst.h" +#include "nxt6000.h" struct dvb_bt8xx_card { struct semaphore lock; @@ -44,4 +48,5 @@ struct i2c_adapter *i2c_adapter; struct dvb_net dvbnet; + struct dvb_frontend* fe; }; diff -Nru a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig --- a/drivers/media/dvb/cinergyT2/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/cinergyT2/Kconfig 2004-12-12 17:40:52 -08:00 @@ -23,8 +23,10 @@ depends on DVB_CINERGYT2_TUNING default "32" help - USB Request Blocks for Highspeed Stream transfers are queued in a - for the Host Controller. Usually the default value is a safe choice. + USB Request Blocks for Highspeed Stream transfers are scheduled in + a queue for the Host Controller. + + Usually the default value is a safe choice. You may increase this number if you are using this device in a Server Environment with many high-traffic USB Highspeed devices @@ -44,6 +46,21 @@ sharing the same USB bus. +config DVB_CINERGYT2_QUERY_INTERVAL + int "Status update interval [milliseconds]" + depends on DVB_CINERGYT2_TUNING + default "250" + help + This is the interval for status readouts from the demodulator. + You may try lower values if you need more responsive signal quality + measurements. + + Please keep in mind that these updates cause traffic on the tuner + control bus and thus may or may not affect receiption sensitivity. + + The default value should be a safe choice for common applications. + + config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE bool "Register the onboard IR Remote Control Receiver as Input Device" depends on DVB_CINERGYT2_TUNING @@ -56,4 +73,13 @@ delivered with the device is supported, please see the driver source code to find out how to add support for other controls. + +config DVB_CINERGYT2_RC_QUERY_INTERVAL + int "Infrared Remote Controller update interval [milliseconds]" + depends on DVB_CINERGYT2_TUNING && DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE + default "100" + help + If you have a very fast-repeating remote control you can try lower + values, for normal consumer receivers the default value should be + a safe choice. diff -Nru a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c --- a/drivers/media/dvb/cinergyT2/cinergyT2.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c 2004-12-12 17:40:52 -08:00 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,16 +36,28 @@ #include "dvb_demux.h" #include "dvb_net.h" + + + + + + + + #ifdef CONFIG_DVB_CINERGYT2_TUNING #define STREAM_URB_COUNT (CONFIG_DVB_CINERGYT2_STREAM_URB_COUNT) #define STREAM_BUF_SIZE (CONFIG_DVB_CINERGYT2_STREAM_BUF_SIZE) + #define QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_QUERY_INTERVAL) #ifdef CONFIG_DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE + #define RC_QUERY_INTERVAL (CONFIG_DVB_CINERGYT2_RC_QUERY_INTERVAL) #define ENABLE_RC (1) #endif #else #define STREAM_URB_COUNT (32) - #define STREAM_BUF_SIZE (512) + #define STREAM_BUF_SIZE (512) /* bytes */ #define ENABLE_RC (1) + #define RC_QUERY_INTERVAL (100) /* milliseconds */ + #define QUERY_INTERVAL (333) /* milliseconds */ #endif #define DRIVER_NAME "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver" @@ -54,7 +67,12 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); #define dprintk(level, args...) \ - do { if ((debug & level)) { printk("%s: %s(): ",__stringify(KBUILD_MODNAME), __FUNCTION__); printk(args); } } while (0) +do { \ + if ((debug & level)) { \ + printk("%s: %s(): ", __stringify(KBUILD_MODNAME), \ + __FUNCTION__); \ + printk(args); } \ +} while (0) enum cinergyt2_ep1_cmd { CINERGYT2_EP1_PID_TABLE_RESET = 0x01, @@ -68,13 +86,34 @@ CINERGYT2_EP1_SLEEP_MODE = 0x09 }; +struct dvbt_set_parameters_msg { + uint8_t cmd; + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; +} __attribute__((packed)); + +struct dvbt_get_status_msg { + uint32_t freq; + uint8_t bandwidth; + uint16_t tps; + uint8_t flags; + uint16_t gain; + uint8_t snr; + uint32_t viterbi_error_rate; + uint32_t rs_error_rate; + uint32_t uncorrected_block_count; + uint8_t lock_bits; + uint8_t prev_lock_bits; +} __attribute__((packed)); + static struct dvb_frontend_info cinergyt2_fe_info = { .name = DRIVER_NAME, .type = FE_OFDM, .frequency_min = 174000000, .frequency_max = 862000000, .frequency_stepsize = 166667, - .notifier_delay = 0, .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | @@ -93,6 +132,13 @@ struct dvb_net dvbnet; int streaming; + int sleeping; + + struct dvbt_set_parameters_msg param; + struct dvbt_get_status_msg status; + struct work_struct query_work; + + wait_queue_head_t poll_wq; void *streambuf; dma_addr_t streambuf_dmahandle; @@ -156,6 +202,45 @@ CINERGYT2_RC_EVENT_TYPE_NEC, 0xa35ceb04, KEY_NEXT }; +static int cinergyt2_command (struct cinergyt2 *cinergyt2, + char *send_buf, int send_buf_len, + char *rec_buf, int rec_buf_len) +{ + int actual_len; + char dummy; + int ret; + + ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1), + send_buf, send_buf_len, &actual_len, HZ); + + if (ret) + dprintk(1, "usb_bulk_msg (send) failed, err %i\n", ret); + + if (!rec_buf) + rec_buf = &dummy; + + ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1), + rec_buf, rec_buf_len, &actual_len, HZ); + + if (ret) + dprintk(1, "usb_bulk_msg (read) failed, err %i\n", ret); + + return ret ? ret : actual_len; +} + +static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable) +{ + char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; + cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); +} + +static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep) +{ + char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 }; + cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); + cinergyt2->sleeping = sleep; +} + static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs); static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb) @@ -236,6 +321,8 @@ { int i; + cinergyt2_control_stream_transfer(cinergyt2, 0); + for (i=0; istream_urb[i]) usb_unlink_urb(cinergyt2->stream_urb[i]); @@ -253,65 +340,23 @@ } } + cinergyt2_control_stream_transfer(cinergyt2, 1); return 0; } -static int cinergyt2_command (struct cinergyt2 *cinergyt2, - char *send_buf, int send_buf_len, - char *rec_buf, int rec_buf_len) -{ - int ret; - int actual_len; - char dummy; - - if (down_interruptible(&cinergyt2->sem)) - return -EBUSY; - - ret = usb_bulk_msg(cinergyt2->udev, usb_sndbulkpipe(cinergyt2->udev, 1), - send_buf, send_buf_len, &actual_len, HZ); - - if (ret) - dprintk(1, "usb_bulk_msg() (send) failed, err %i\n", ret); - - if (!rec_buf) - rec_buf = &dummy; - - ret = usb_bulk_msg(cinergyt2->udev, usb_rcvbulkpipe(cinergyt2->udev, 1), - rec_buf, rec_buf_len, &actual_len, HZ); - - if (ret) - dprintk(1, "usb_bulk_msg() (read) failed, err %i\n", ret); - - up(&cinergyt2->sem); - - return ret ? ret : actual_len; -} - -static void cinergyt2_control_stream_transfer (struct cinergyt2 *cinergyt2, int enable) -{ - char buf [] = { CINERGYT2_EP1_CONTROL_STREAM_TRANSFER, enable ? 1 : 0 }; - cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); -} - -static void cinergyt2_control_sleep_mode (struct cinergyt2 *cinergyt2, int sleep) -{ - char buf [] = { CINERGYT2_EP1_SLEEP_MODE, sleep ? 1 : 0 }; - cinergyt2_command(cinergyt2, buf, sizeof(buf), NULL, 0); -} - static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *demux = dvbdmxfeed->demux; struct cinergyt2 *cinergyt2 = demux->priv; + if (down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; - if (cinergyt2->streaming == 0) { - if (cinergyt2_start_stream_xfer (cinergyt2) == 0) - cinergyt2_control_stream_transfer (cinergyt2, 1); - } + if (cinergyt2->streaming == 0) + cinergyt2_start_stream_xfer(cinergyt2); cinergyt2->streaming++; - + up(&cinergyt2->sem); return 0; } @@ -320,11 +365,13 @@ struct dvb_demux *demux = dvbdmxfeed->demux; struct cinergyt2 *cinergyt2 = demux->priv; - if (--cinergyt2->streaming == 0) { - cinergyt2_control_stream_transfer(cinergyt2, 0); + if (down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + + if (--cinergyt2->streaming == 0) cinergyt2_stop_stream_xfer(cinergyt2); - } + up(&cinergyt2->sem); return 0; } @@ -337,11 +384,10 @@ * * We replace errornous fields by default TPS fields (the ones with value 0). */ - -static uint16_t compute_tps (struct dvb_frontend_parameters *param) +static uint16_t compute_tps (struct dvb_frontend_parameters *p) { + struct dvb_ofdm_parameters *op = &p->u.ofdm; uint16_t tps = 0; - struct dvb_ofdm_parameters *op = ¶m->u.ofdm; switch (op->code_rate_HP) { case FEC_2_3: @@ -435,147 +481,126 @@ return tps; } -struct dvbt_set_parameters_msg { - uint8_t cmd; - uint32_t freq; - uint8_t bandwidth; - uint16_t tps; - uint8_t flags; -} __attribute__((packed)); - -struct dvbt_get_parameters_msg { - uint32_t freq; - uint8_t bandwidth; - uint16_t tps; - uint8_t flags; - uint16_t gain; - uint8_t snr; - uint32_t viterbi_error_rate; - uint32_t rs_error_rate; - uint32_t uncorrected_block_count; - uint8_t lock_bits; - uint8_t prev_lock_bits; -} __attribute__((packed)); - -static int cinergyt2_fe_open (struct inode *inode, struct file *file) +static int cinergyt2_open (struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; - cinergyt2_control_sleep_mode((struct cinergyt2 *) dvbdev->priv, 0); - return dvb_generic_open(inode, file); + struct cinergyt2 *cinergyt2 = dvbdev->priv; + int err; + + if ((err = dvb_generic_open(inode, file))) + return err; + + if (down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + cinergyt2_sleep(cinergyt2, 0); + schedule_delayed_work(&cinergyt2->query_work, HZ/2); } -static int cinergyt2_fe_release (struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev = file->private_data; - cinergyt2_control_sleep_mode((struct cinergyt2 *) dvbdev->priv, 1); - return dvb_generic_release (inode, file); + up(&cinergyt2->sem); + return 0; } -static int cinergyt2_fe_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int cinergyt2_release (struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; - int ret = 0; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &cinergyt2_fe_info, sizeof(struct dvb_frontend_info)); - break; - case FE_READ_STATUS: - { - struct dvbt_get_parameters_msg msg; - char cmd = CINERGYT2_EP1_GET_TUNER_STATUS; - fe_status_t *status = arg; - - *status = 0; - - cinergyt2_command(cinergyt2, &cmd, 1, (char *) &msg, sizeof(msg)); - - if (msg.lock_bits & (1 << 6)) - *status |= FE_HAS_LOCK; - if (msg.lock_bits & (1 << 5)) - *status |= FE_HAS_SYNC; - if (msg.lock_bits & (1 << 4)) - *status |= FE_HAS_CARRIER; - if (msg.lock_bits & (1 << 1)) - *status |= FE_HAS_VITERBI; + if (down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; - break; + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + cancel_delayed_work(&cinergyt2->query_work); + flush_scheduled_work(); + cinergyt2_sleep(cinergyt2, 1); } - case FE_READ_BER: - { - struct dvbt_get_parameters_msg msg; - char cmd = CINERGYT2_EP1_GET_TUNER_STATUS; - u32 *ber = (u32 *) arg; - - cinergyt2_command(cinergyt2, &cmd, 1, (char *) &msg, sizeof(msg)); - - *ber = le32_to_cpu(msg.viterbi_error_rate); + up(&cinergyt2->sem); - break; + return dvb_generic_release(inode, file); } - case FE_READ_SIGNAL_STRENGTH: +static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct *wait) { - struct dvbt_get_parameters_msg msg; - char cmd = CINERGYT2_EP1_GET_TUNER_STATUS; - u16 *signal = (u16 *) arg; - - cinergyt2_command(cinergyt2, &cmd, 1, (char *) &msg, sizeof(msg)); - - *signal = ~(le16_to_cpu(msg.gain)); - - break; + struct dvb_device *dvbdev = file->private_data; + struct cinergyt2 *cinergyt2 = dvbdev->priv; + poll_wait(file, &cinergyt2->poll_wq, wait); + return (POLLIN | POLLRDNORM | POLLPRI); } - case FE_READ_SNR: + +static int cinergyt2_ioctl (struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) { - struct dvbt_get_parameters_msg msg; - char cmd = CINERGYT2_EP1_GET_TUNER_STATUS; - u16 *snr = (u16 *) arg; + struct dvb_device *dvbdev = file->private_data; + struct cinergyt2 *cinergyt2 = dvbdev->priv; + struct dvbt_get_status_msg *stat = &cinergyt2->status; + fe_status_t status = 0; - cinergyt2_command(cinergyt2, &cmd, 1, (char *) &msg, sizeof(msg)); + switch (cmd) { + case FE_GET_INFO: + return copy_to_user((void*) arg, &cinergyt2_fe_info, + sizeof(struct dvb_frontend_info)); - *snr = (msg.snr << 8) | msg.snr; + case FE_READ_STATUS: + if (0xffff - le16_to_cpu(stat->gain) > 30) + status |= FE_HAS_SIGNAL; + if (stat->lock_bits & (1 << 6)) + status |= FE_HAS_LOCK; + if (stat->lock_bits & (1 << 5)) + status |= FE_HAS_SYNC; + if (stat->lock_bits & (1 << 4)) + status |= FE_HAS_CARRIER; + if (stat->lock_bits & (1 << 1)) + status |= FE_HAS_VITERBI; - break; - } + return copy_to_user((void *) arg, &status, sizeof(status)); - case FE_READ_UNCORRECTED_BLOCKS: - { - struct dvbt_get_parameters_msg msg; - char cmd = CINERGYT2_EP1_GET_TUNER_STATUS; - u32 *ubc = (u32 *) arg; + case FE_READ_BER: + return put_user(le32_to_cpu(stat->viterbi_error_rate), + (__u32 __user *) arg); - cinergyt2_command(cinergyt2, &cmd, 1, (char *) &msg, sizeof(msg)); + case FE_READ_SIGNAL_STRENGTH: + return put_user(0xffff - le16_to_cpu(stat->gain), + (__u16 __user *) arg); - *ubc = le32_to_cpu(msg.uncorrected_block_count); + case FE_READ_SNR: + return put_user((stat->snr << 8) | stat->snr, + (__u16 __user *) arg); - break; - } + case FE_READ_UNCORRECTED_BLOCKS: + /* UNC are already converted to host byte order... */ + return put_user(stat->uncorrected_block_count, + (__u32 __user *) arg); case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = (void*) arg; - struct dvb_ofdm_parameters *op = &p->u.ofdm; - struct dvbt_set_parameters_msg msg; - - msg.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; - msg.tps = cpu_to_le16(compute_tps(p)); - msg.freq = cpu_to_le32(p->frequency / 1000); - msg.bandwidth = 8 - op->bandwidth - BANDWIDTH_8_MHZ; - - cinergyt2_command(cinergyt2, (char *) &msg, sizeof(msg), NULL, 0); + struct dvbt_set_parameters_msg *param = &cinergyt2->param; + struct dvb_frontend_parameters p; + int err; + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return -EPERM; + + if (copy_from_user(&p, (void *) arg, sizeof(p))) + return -EFAULT; + + param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; + param->tps = cpu_to_le16(compute_tps(&p)); + param->freq = cpu_to_le32(p.frequency / 1000); + param->bandwidth = 8 - p.u.ofdm.bandwidth - BANDWIDTH_8_MHZ; + + err = cinergyt2_command(cinergyt2, + (char *) param, sizeof(*param), + NULL, 0); - break; + return (err < 0) ? err : 0; } case FE_GET_FRONTEND: /** - * trivial to implement (see struct dvbt_get_parameters_msg). + * trivial to implement (see struct dvbt_get_status_msg). * equivalent to FE_READ ioctls, but needs * TPS -> linux-dvb parameter set conversion. Feel free * to implement this and send us a patch if you need this @@ -584,32 +609,56 @@ break; default: + ; + } + + return -EINVAL; +} + +static int cinergyt2_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dvb_device *dvbdev = file->private_data; + struct cinergyt2 *cinergyt2 = dvbdev->priv; + int ret = 0; + + lock_kernel(); + + if (vma->vm_flags & (VM_WRITE | VM_EXEC)) { + ret = -EPERM; + goto bailout; + } + + if (vma->vm_end > vma->vm_start + STREAM_URB_COUNT * STREAM_BUF_SIZE) { ret = -EINVAL; - break; + goto bailout; } + vma->vm_flags |= (VM_IO | VM_DONTCOPY); + vma->vm_file = file; + + ret = remap_pfn_range(vma, vma->vm_start, + virt_to_phys(cinergyt2->streambuf) >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot) ? -EAGAIN : 0; +bailout: + unlock_kernel(); return ret; } -static -struct file_operations cinergyt2_fe_fops = { +static struct file_operations cinergyt2_fops = { .owner = THIS_MODULE, - .ioctl = dvb_generic_ioctl, - /** - * do we really need this? If so, let's implement it via - * schedule_delayed_work() similiar to the IR code. - */ - /*.poll = cinergyt2_fe_poll, */ - .open = cinergyt2_fe_open, - .release = cinergyt2_fe_release + .ioctl = cinergyt2_ioctl, + .poll = cinergyt2_poll, + .open = cinergyt2_open, + .release = cinergyt2_release, + .mmap = cinergyt2_mmap }; static struct dvb_device cinergyt2_fe_template = { .users = ~0, .writers = 1, .readers = (~0)-1, - .fops = &cinergyt2_fe_fops, - .kernel_ioctl = cinergyt2_fe_ioctl + .fops = &cinergyt2_fops }; #ifdef ENABLE_RC @@ -620,6 +669,9 @@ struct cinergyt2_rc_event rc_events[12]; int n, len; + if (down_interruptible(&cinergyt2->sem)) + return; + len = cinergyt2_command(cinergyt2, buf, sizeof(buf), (char *) rc_events, sizeof(rc_events)); @@ -656,11 +708,43 @@ } } - schedule_delayed_work(&cinergyt2->rc_query_work, (HZ/5)); + schedule_delayed_work(&cinergyt2->rc_query_work, + msecs_to_jiffies(RC_QUERY_INTERVAL)); + + up(&cinergyt2->sem); } #endif -static int cinergyt2_probe (struct usb_interface *intf, const struct usb_device_id *id) +static void cinergyt2_query (void *data) +{ + struct cinergyt2 *cinergyt2 = (struct cinergyt2 *) data; + char cmd [] = { CINERGYT2_EP1_GET_TUNER_STATUS }; + struct dvbt_get_status_msg *s = &cinergyt2->status; + uint8_t lock_bits; + uint32_t unc; + + if (down_interruptible(&cinergyt2->sem)) + return; + + unc = s->uncorrected_block_count; + lock_bits = s->lock_bits; + + cinergyt2_command(cinergyt2, cmd, sizeof(cmd), (char *) s, sizeof(*s)); + + unc += le32_to_cpu(s->uncorrected_block_count); + s->uncorrected_block_count = unc; + + if (lock_bits != s->lock_bits) + wake_up_interruptible(&cinergyt2->poll_wq); + + schedule_delayed_work(&cinergyt2->query_work, + msecs_to_jiffies(QUERY_INTERVAL)); + + up(&cinergyt2->sem); +} + +static int cinergyt2_probe (struct usb_interface *intf, + const struct usb_device_id *id) { struct cinergyt2 *cinergyt2; int i, err; @@ -674,6 +758,8 @@ usb_set_intfdata (intf, (void *) cinergyt2); init_MUTEX(&cinergyt2->sem); + init_waitqueue_head (&cinergyt2->poll_wq); + INIT_WORK(&cinergyt2->query_work, cinergyt2_query, cinergyt2); cinergyt2->udev = interface_to_usbdev(intf); @@ -722,10 +808,6 @@ cinergyt2->rc_input_dev.keycodesize = sizeof(unsigned char); cinergyt2->rc_input_dev.keycodemax = KEY_MAX; cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control"; - cinergyt2->rc_input_dev.id.bustype = BUS_USB; - cinergyt2->rc_input_dev.id.vendor = 0x0001; - cinergyt2->rc_input_dev.id.product = 0x0001; - cinergyt2->rc_input_dev.id.version = 0x0100; for (i=0; irc_input_dev.keybit); @@ -735,9 +817,8 @@ cinergyt2->rc_input_event = KEY_MAX; INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); - schedule_delayed_work(&cinergyt2->rc_query_work, HZ); + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); #endif - return 0; bailout: @@ -753,6 +834,9 @@ { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); + if (down_interruptible(&cinergyt2->sem)) + return; + #ifdef ENABLE_RC cancel_delayed_work(&cinergyt2->rc_query_work); flush_scheduled_work(); @@ -768,9 +852,56 @@ dvb_unregister_adapter(cinergyt2->adapter); cinergyt2_free_stream_urbs(cinergyt2); + up(&cinergyt2->sem); kfree(cinergyt2); } +static int cinergyt2_suspend (struct usb_interface *intf, u32 state) +{ + struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); + + if (down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + + if (state > 0) { /* state 0 seems to mean DEVICE_PM_ON */ + struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); +#ifdef ENABLE_RC + cancel_delayed_work(&cinergyt2->rc_query_work); +#endif + cancel_delayed_work(&cinergyt2->query_work); + if (cinergyt2->streaming) + cinergyt2_stop_stream_xfer(cinergyt2); + flush_scheduled_work(); + cinergyt2_sleep(cinergyt2, 1); + } + + up(&cinergyt2->sem); + return 0; +} + +static int cinergyt2_resume (struct usb_interface *intf) +{ + struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); + struct dvbt_set_parameters_msg *param = &cinergyt2->param; + + if (down_interruptible(&cinergyt2->sem)) + return -ERESTARTSYS; + + if (!cinergyt2->sleeping) { + cinergyt2_sleep(cinergyt2, 0); + cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0); + if (cinergyt2->streaming) + cinergyt2_start_stream_xfer(cinergyt2); + schedule_delayed_work(&cinergyt2->query_work, HZ/2); + } + +#ifdef ENABLE_RC + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); +#endif + up(&cinergyt2->sem); + return 0; +} + static const struct usb_device_id cinergyt2_table [] __devinitdata = { { USB_DEVICE(0x0ccd, 0x0038) }, { 0 } @@ -780,9 +911,11 @@ static struct usb_driver cinergyt2_driver = { .owner = THIS_MODULE, - .name = "cinergyt2", + .name = "cinergyT2", .probe = cinergyt2_probe, .disconnect = cinergyt2_disconnect, + .suspend = cinergyt2_suspend, + .resume = cinergyt2_resume, .id_table = cinergyt2_table }; @@ -790,12 +923,10 @@ { int err; - if ((err = usb_register(&cinergyt2_driver)) < 0) { + if ((err = usb_register(&cinergyt2_driver)) < 0) dprintk(1, "usb_register() failed! (err %i)\n", err); - return err; - } - return 0; + return err; } static void __exit cinergyt2_exit (void) diff -Nru a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig --- a/drivers/media/dvb/dibusb/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dibusb/Kconfig 2004-12-12 17:40:52 -08:00 @@ -1,9 +1,10 @@ config DVB_DIBUSB - tristate "DiBcom/Twinhan/KWorld/Hama/Artec/Compro USB DVB-T devices" + tristate "DiBcom USB DVB-T devices (see help for device list)" depends on DVB_CORE && USB select FW_LOADER + select DVB_DIB3000MB help - Support for USB 1.1 DVB-T devices based on a reference design made by + Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by DiBcom (http://www.dibcom.fr). Devices supported by this driver: @@ -15,19 +16,35 @@ DiBcom reference device (non-public) Ultima Electronic/Artec T1 USB TVBOX Compro Videomate DVB-U2000 - DVB-T USB + Grandtec DVB-T USB + Avermedia AverTV DVBT USB + Yakumo DVB-T mobile USB2.0 The VP7041 seems to be identical to "CTS Portable" (Chinese Television System). These devices can be understood as budget ones, they "only" deliver - the MPEG data. + (a part of) the MPEG2 transport stream. - Currently all known copies of the DiBcom reference design have the DiBcom 3000-MB - frontend onboard. Please enable and load this one manually in order to use this - device. - - A firmware is needed to use the device. See Documentation/dvb/README.dibusb + A firmware is needed to get the device working. See Documentation/dvb/README.dibusb details. Say Y if you own such a device and want to use it. You should build it as a module. + +config DVB_DIBUSB_MISDESIGNED_AN2235 + bool "Enable support for some Artec T1 device, which identifies as AN2235" + depends on DVB_DIBUSB + help + Somehow Artec forgot to program the eeprom for some of their T1 devices. So + comes that they identify with the default Vendor and Product ID of the Cypress + CY7C64613 (AN2235). + + Say Y if your Artec device has 0x0574 as Vendor ID and 0x2235 as Product ID. + +config DVB_DIBCOM_DEBUG + bool "Enable extended debug support for DiBcom USB device" + depends on DVB_DIBUSB + help + Say Y if you want to enable debuging. See modinfo dvb-dibusb for + debug level. diff -Nru a/drivers/media/dvb/dibusb/Makefile b/drivers/media/dvb/dibusb/Makefile --- a/drivers/media/dvb/dibusb/Makefile 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dibusb/Makefile 2004-12-12 17:40:52 -08:00 @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb.c b/drivers/media/dvb/dibusb/dvb-dibusb.c --- a/drivers/media/dvb/dibusb/dvb-dibusb.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dibusb/dvb-dibusb.c 2004-12-12 17:40:52 -08:00 @@ -11,6 +11,8 @@ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) * * + * Remote control code added by David Matthews (dm@prolingua.co.uk) + * * 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. @@ -18,9 +20,7 @@ * Acknowledgements * * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver - * sources, on which this driver (and the dib3000mb frontend) are based. - * - * + * sources, on which this driver (and the dib3000mb/mc/p frontends) are based. * * see Documentation/dvb/README.dibusb for more information */ @@ -32,19 +32,21 @@ #include #include #include +#include #include "dmxdev.h" #include "dvb_demux.h" #include "dvb_filter.h" #include "dvb_net.h" #include "dvb_frontend.h" +#include "dib3000.h" #include "dvb-dibusb.h" -/* debug */ +/* debug */ #ifdef CONFIG_DVB_DIBCOM_DEBUG -#define dprintk_new(level,args...) \ +#define dprintk(level,args...) \ do { if ((debug & level)) { printk(args); } } while (0) #define debug_dump(b,l) if (debug) {\ @@ -55,20 +57,22 @@ static int debug; module_param(debug, int, 0x644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err (|-able))."); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))."); #else -#define dprintk_new(args...) +#define dprintk(args...) #define debug_dump(b,l) #endif -#define deb_info(args...) dprintk_new(0x01,args) -#define deb_xfer(args...) dprintk_new(0x02,args) -#define deb_alot(args...) dprintk_new(0x04,args) -#define deb_ts(args...) dprintk_new(0x08,args) -#define deb_err(args...) dprintk_new(0x10,args) +#define deb_info(args...) dprintk(0x01,args) +#define deb_xfer(args...) dprintk(0x02,args) +#define deb_alot(args...) dprintk(0x04,args) +#define deb_ts(args...) dprintk(0x08,args) +#define deb_err(args...) dprintk(0x10,args) +#define deb_rc(args...) dprintk(0x20,args) + /* Version information */ -#define DRIVER_VERSION "0.0" +#define DRIVER_VERSION "0.1" #define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device" #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" @@ -83,25 +87,28 @@ if ((ret = down_interruptible(&dib->usb_sem))) return ret; - if (dib->streaming && wbuf[0] == DIBUSB_REQ_I2C_WRITE) - deb_err("BUG: writing to i2c, while TS-streaming destroys the stream. What" - " did you do ? Please enable debugging and send the syslog to the author. (%x reg: %x %x)", - wbuf[0],wbuf[2],wbuf[3]); + if (dib->feedcount && + wbuf[0] == DIBUSB_REQ_I2C_WRITE && + dib->dibdev->parm->type == DIBUSB1_1) + deb_err("BUG: writing to i2c, while TS-streaming destroys the stream." + "(%x reg: %x %x)", wbuf[0],wbuf[2],wbuf[3]); debug_dump(wbuf,wlen); - ret = usb_bulk_msg(dib->udev,COMMAND_PIPE, - wbuf,wlen,&actlen,DIBUSB_I2C_TIMEOUT); + ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev, + dib->dibdev->parm->cmd_pipe), wbuf,wlen,&actlen, + DIBUSB_I2C_TIMEOUT); if (ret) err("bulk message failed: %d (%d/%d)",ret,wlen,actlen); else ret = actlen != wlen ? -1 : 0; - /* an answer is expected */ + /* an answer is expected, and no error before */ if (!ret && rbuf && rlen) { - ret = usb_bulk_msg(dib->udev,RESULT_PIPE,rbuf,rlen, - &actlen,DIBUSB_I2C_TIMEOUT); + ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev, + dib->dibdev->parm->result_pipe),rbuf,rlen,&actlen, + DIBUSB_I2C_TIMEOUT); if (ret) err("recv bulk message failed: %d",ret); @@ -115,11 +122,6 @@ return ret; } -static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len) -{ - return dibusb_readwrite_usb(dib,buf,len,NULL,0); -} - static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { @@ -146,97 +148,21 @@ /* * DVB stuff */ - -static struct dibusb_pid * dibusb_get_free_pid(struct usb_dibusb *dib) -{ - int i; - unsigned long flags; - struct dibusb_pid *dpid = NULL; - - spin_lock_irqsave(&dib->pid_list_lock,flags); - for (i=0; i < DIBUSB_MAX_PIDS; i++) - if (!dib->pid_list[i].active) { - dpid = dib->pid_list + i; - dpid->active = 1; - break; - } - spin_unlock_irqrestore(&dib->pid_list_lock,flags); - return dpid; -} - -static int dibusb_start_xfer(struct usb_dibusb *dib) -{ - u8 b[4] = { - (DIB3000MB_REG_FIFO >> 8) & 0xff, - (DIB3000MB_REG_FIFO) & 0xff, - (DIB3000MB_FIFO_ACTIVATE >> 8) & 0xff, - (DIB3000MB_FIFO_ACTIVATE) & 0xff - }; - dib->streaming = 1; - deb_ts("start streaming\n"); - return dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0); -} - -static int dibusb_stop_xfer(struct usb_dibusb *dib) -{ - u8 b[4] = { - (DIB3000MB_REG_FIFO >> 8) & 0xff, - (DIB3000MB_REG_FIFO) & 0xff, - (DIB3000MB_FIFO_INHIBIT >> 8) & 0xff, - (DIB3000MB_FIFO_INHIBIT) & 0xff - }; - dib->streaming = 0; - deb_ts("stop streaming\n"); - return dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0); -} - -static int dibusb_set_pid(struct dibusb_pid *dpid) -{ - struct usb_dibusb *dib = dpid->dib; - u16 pid = dpid->pid | (dpid->active ? DIB3000MB_ACTIVATE_FILTERING : 0); - u8 b[4] = { - (dpid->reg >> 8) & 0xff, - (dpid->reg) & 0xff, - (pid >> 8) & 0xff, - (pid) & 0xff - }; - int ret; - - /* firmware bug, i2c write during mpeg transfer */ - if (dib->feedcount) { - deb_info("stop streaming\n"); - ret = dibusb_stop_xfer(dib); - } - - if (dpid->active) - dib->feedcount++; - else - dib->feedcount--; - - ret = dibusb_i2c_msg(dib,DIBUSB_DEMOD_I2C_ADDR_DEFAULT,b,4,NULL,0); - - if (ret == 0 && dib->feedcount) { - deb_info("start streaming\n"); - ret = dibusb_start_xfer(dib); - } - return ret; -} - static void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs) { struct usb_dibusb *dib = urb->context; - deb_xfer("urb complete feedcount: %d, status: %d\n",dib->feedcount,urb->status); + deb_ts("urb complete feedcount: %d, status: %d\n",dib->feedcount,urb->status); if (dib->feedcount > 0 && urb->status == 0) { - deb_xfer("URB return len: %d\n",urb->actual_length); + deb_ts("URB return len: %d\n",urb->actual_length); if (urb->actual_length % 188) - deb_xfer("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188); + deb_ts("TS Packets: %d, %d\n", urb->actual_length/188,urb->actual_length % 188); /* Francois recommends to drop not full-filled packets, even if they may * contain valid TS packets */ - if (urb->actual_length == DIBUSB_TS_DEFAULT_SIZE && dib->dvb_is_ready) + if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready) dvb_dmx_swfilter_packets(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length/188); else deb_ts("URB dropped because of the " @@ -247,78 +173,181 @@ usb_submit_urb(urb,GFP_KERNEL); } - -static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +static int dibusb_ctrl_feed(struct usb_dibusb *dib, int pid, int onoff) { -// struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct usb_dibusb *dib = dvbdmxfeed->demux->priv; - struct dibusb_pid *dpid; + if (dib->dibdev->parm->firmware_bug && dib->feedcount) { + deb_ts("stop feeding\n"); + if (dib->xfer_ops.fifo_ctrl != NULL) { + if (dib->xfer_ops.fifo_ctrl(dib->fe,0)) { + err("error while inhibiting fifo."); + return -ENODEV; + } + } else { + err("fifo_ctrl is not set."); + return -ENODEV; + } + } - deb_ts("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); + dib->feedcount += onoff ? 1 : -1; - if ((dpid = dibusb_get_free_pid(dib)) == NULL) { + if (dib->xfer_ops.pid_ctrl != NULL) { + if (dib->xfer_ops.pid_ctrl(dib->fe,pid,onoff) < 0) { err("no free pid in list."); return -ENODEV; } - dvbdmxfeed->priv = dpid; - dpid->pid = dvbdmxfeed->pid; - - dibusb_set_pid(dpid); - - return 0; + } else { + err("no pid ctrl callback."); + return -ENODEV; + } + /* + * start the feed, either if there is the firmware bug or + * if this was the first pid to set. + */ + if (dib->dibdev->parm->firmware_bug || dib->feedcount == onoff) { + deb_ts("start feeding\n"); + if (dib->xfer_ops.fifo_ctrl != NULL) { + if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) { + err("error while enabling fifo."); + return -ENODEV; + } + } else { + err("fifo_ctrl is not set."); + return -ENODEV; } - -static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dibusb_pid *dpid = (struct dibusb_pid *) dvbdmxfeed->priv; - - deb_ts("stopfeed pid: 0x%04x, feedtype: %d\n",dvbdmxfeed->pid, dvbdmxfeed->type); - - if (dpid == NULL) - err("channel in dmxfeed->priv was NULL"); - else { - dpid->active = 0; - dpid->pid = 0; - dibusb_set_pid(dpid); } - return 0; } -/* - * firmware transfers - */ +static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct usb_dibusb *dib = dvbdmxfeed->demux->priv; + deb_ts("pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); + dvbdmxfeed->priv = dib; + return dibusb_ctrl_feed(dib,dvbdmxfeed->pid,1); +} -/* - * do not use this, just a workaround for a bug, - * which will hopefully never occur :). - */ -static int dibusb_interrupt_read_loop(struct usb_dibusb *dib) +static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - u8 b[1] = { DIBUSB_REQ_INTR_READ }; - return dibusb_write_usb(dib,b,1); + struct usb_dibusb *dib = (struct usb_dibusb *) dvbdmxfeed->priv; + if (dib == NULL) { + err("dib in dmxfeed->priv was NULL"); + return -EINVAL; } + deb_ts("dvbdmxfeed pid: 0x%04x, feedtype: %d\n", + dvbdmxfeed->pid, dvbdmxfeed->type); + return dibusb_ctrl_feed(dib,dvbdmxfeed->pid,0); +} + +/* Table to map raw key codes to key events. This should not be hard-wired + into the kernel. */ +static const struct { u8 c0, c1, c2; uint32_t key; } rc_keys [] = +{ + /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */ + { 0x00, 0xff, 0x16, KEY_POWER }, + { 0x00, 0xff, 0x10, KEY_MUTE }, + { 0x00, 0xff, 0x03, KEY_1 }, + { 0x00, 0xff, 0x01, KEY_2 }, + { 0x00, 0xff, 0x06, KEY_3 }, + { 0x00, 0xff, 0x09, KEY_4 }, + { 0x00, 0xff, 0x1d, KEY_5 }, + { 0x00, 0xff, 0x1f, KEY_6 }, + { 0x00, 0xff, 0x0d, KEY_7 }, + { 0x00, 0xff, 0x19, KEY_8 }, + { 0x00, 0xff, 0x1b, KEY_9 }, + { 0x00, 0xff, 0x15, KEY_0 }, + { 0x00, 0xff, 0x05, KEY_CHANNELUP }, + { 0x00, 0xff, 0x02, KEY_CHANNELDOWN }, + { 0x00, 0xff, 0x1e, KEY_VOLUMEUP }, + { 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN }, + { 0x00, 0xff, 0x11, KEY_RECORD }, + { 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */ + { 0x00, 0xff, 0x14, KEY_PLAY }, + { 0x00, 0xff, 0x1a, KEY_STOP }, + { 0x00, 0xff, 0x40, KEY_REWIND }, + { 0x00, 0xff, 0x12, KEY_FASTFORWARD }, + { 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */ + { 0x00, 0xff, 0x4c, KEY_PAUSE }, + { 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */ + { 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ + /* Key codes for the KWorld/ADSTech/JetWay remote. */ + { 0x86, 0x6b, 0x12, KEY_POWER }, + { 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */ + { 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */ + { 0x86, 0x6b, 0x0b, KEY_EPG }, + { 0x86, 0x6b, 0x10, KEY_MUTE }, + { 0x86, 0x6b, 0x01, KEY_1 }, + { 0x86, 0x6b, 0x02, KEY_2 }, + { 0x86, 0x6b, 0x03, KEY_3 }, + { 0x86, 0x6b, 0x04, KEY_4 }, + { 0x86, 0x6b, 0x05, KEY_5 }, + { 0x86, 0x6b, 0x06, KEY_6 }, + { 0x86, 0x6b, 0x07, KEY_7 }, + { 0x86, 0x6b, 0x08, KEY_8 }, + { 0x86, 0x6b, 0x09, KEY_9 }, + { 0x86, 0x6b, 0x0a, KEY_0 }, + { 0x86, 0x6b, 0x18, KEY_ZOOM }, + { 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */ + { 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */ + { 0x86, 0x6b, 0x00, KEY_UNDO }, + { 0x86, 0x6b, 0x1d, KEY_RECORD }, + { 0x86, 0x6b, 0x0d, KEY_STOP }, + { 0x86, 0x6b, 0x0e, KEY_PAUSE }, + { 0x86, 0x6b, 0x16, KEY_PLAY }, + { 0x86, 0x6b, 0x11, KEY_BACK }, + { 0x86, 0x6b, 0x19, KEY_FORWARD }, + { 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */ + { 0x86, 0x6b, 0x15, KEY_ESC }, + { 0x86, 0x6b, 0x1a, KEY_UP }, + { 0x86, 0x6b, 0x1e, KEY_DOWN }, + { 0x86, 0x6b, 0x1f, KEY_LEFT }, + { 0x86, 0x6b, 0x1b, KEY_RIGHT }, +}; /* - * TODO: a tasklet should run with a delay of 1/10 second - * and feed an appropriate event device ? - * NEC protocol is used for remote controlls + * Read the remote control and feed the appropriate event. + * NEC protocol is used for remote controls */ static int dibusb_read_remote_control(struct usb_dibusb *dib) { u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5]; int ret; + int i; if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5))) return ret; - - switch (rb[0]) { case DIBUSB_RC_NEC_KEY_PRESSED: + /* rb[1-3] is the actual key, rb[4] is a checksum */ + deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + rb[1], rb[2], rb[3], rb[4]); + if ((0xff - rb[3]) != rb[4]) { + deb_rc("remote control checksum failed.\n"); + break; + } + + /* See if we can match the raw key code. */ + for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) { + if (rc_keys[i].c0 == rb[1] && + rc_keys[i].c1 == rb[2] && + rc_keys[i].c2 == rb[3]) { + dib->rc_input_event = rc_keys[i].key; + deb_rc("Translated key 0x%04x\n", dib->rc_input_event); + /* Signal down and up events for this key. */ + input_report_key(&dib->rc_input_dev, dib->rc_input_event, 1); + input_report_key(&dib->rc_input_dev, dib->rc_input_event, 0); + input_sync(&dib->rc_input_dev); + break; + } + } + break; + case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */ break; - case DIBUSB_RC_NEC_EMPTY: case DIBUSB_RC_NEC_KEY_REPEATED: + /* rb[1]..rb[4] are always zero.*/ + /* Repeats often seem to occur so for the moment just ignore this. */ + deb_rc("Key repeat\n"); + break; default: break; } @@ -326,6 +355,46 @@ return 0; } +#define RC_QUERY_INTERVAL (100) /* milliseconds */ + +/* Remote-control poll function - called every RC_QUERY_INTERVAL ms to see + whether the remote control has received anything. */ +static void dibusb_query_rc (void *data) +{ + struct usb_dibusb *dib = (struct usb_dibusb *) data; + /* TODO: need a lock here. We can simply skip checking for the remote control + if we're busy. */ + dibusb_read_remote_control(dib); + schedule_delayed_work(&dib->rc_query_work, + msecs_to_jiffies(RC_QUERY_INTERVAL)); +} + +/* + * Cypress controls + */ + +#if 0 + +/* + * #if 0'ing the following 5 functions as they are not in use _now_, + * but probably will be sometime. + */ + +static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len) +{ + return dibusb_readwrite_usb(dib,buf,len,NULL,0); +} + +/* + * do not use this, just a workaround for a bug, + * which will hopefully never occur :). + */ +static int dibusb_interrupt_read_loop(struct usb_dibusb *dib) +{ + u8 b[1] = { DIBUSB_REQ_INTR_READ }; + return dibusb_write_usb(dib,b,1); +} + /* * ioctl for the firmware */ @@ -355,6 +424,8 @@ return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1); } +#endif + /* * I2C */ @@ -387,19 +458,44 @@ return I2C_FUNC_I2C; } -static int dibusb_i2c_client_register (struct i2c_client *i2c) -{ - struct usb_dibusb *dib = i2c_get_adapdata(i2c->adapter); - if (i2c->driver->command) - return i2c->driver->command(i2c,FE_REGISTER,dib->adapter); - return 0; -} +static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); -static int dibusb_i2c_client_unregister (struct i2c_client *i2c) +static struct dib3000_config thomson_cable_eu_config = { + .demod_address = 0x10, + .pll_addr = 194, + .pll_set = thomson_cable_eu_pll_set, +}; + +static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { - struct usb_dibusb *dib = i2c_get_adapdata(i2c->adapter); - if (i2c->driver->command) - return i2c->driver->command(i2c,FE_UNREGISTER,dib->adapter); + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + u8 buf[4]; + struct i2c_msg msg = { + .addr = thomson_cable_eu_config.pll_addr, + .flags = 0, + .buf = buf, + .len = sizeof(buf) + }; + u32 tfreq = (params->frequency + 36125000) / 62500; + int vu,p0,p1,p2; + + if (params->frequency > 403250000) + vu = 1, p2 = 1, p1 = 0, p0 = 1; + else if (params->frequency > 115750000) + vu = 0, p2 = 1, p1 = 1, p0 = 0; + else if (params->frequency > 44250000) + vu = 0, p2 = 0, p1 = 1, p0 = 1; + else + return -EINVAL; + + buf[0] = (tfreq >> 8) & 0x7f; + buf[1] = tfreq & 0xff; + buf[2] = 0x8e; + buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0; + + if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) return -EIO; + + msleep(1); return 0; } @@ -410,6 +506,24 @@ .functionality = dibusb_i2c_func, }; +static void frontend_init(struct usb_dibusb* dib) +{ + dib->fe = dib3000mb_attach(&thomson_cable_eu_config, &dib->i2c_adap,&dib->xfer_ops); + + if (dib->fe == NULL) { + printk("dvb-dibusb: A frontend driver was not found for device %04x/%04x\n", + dib->udev->descriptor.idVendor, + dib->udev->descriptor.idProduct); + } else { + if (dvb_register_frontend(dib->adapter, dib->fe)) { + printk("dvb-dibusb: Frontend registration failed!\n"); + if (dib->fe->ops->release) + dib->fe->ops->release(dib->fe); + dib->fe = NULL; + } + } +} + static int dibusb_dvb_init(struct usb_dibusb *dib) { int ret; @@ -423,6 +537,7 @@ deb_info("dvb_register_adapter failed: error %d", ret); goto err; } + dib->adapter->priv = dib; strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE); #ifdef I2C_ADAP_CLASS_TV_DIGITAL @@ -433,8 +548,6 @@ dib->i2c_adap.algo = &dibusb_algo; dib->i2c_adap.algo_data = NULL; dib->i2c_adap.id = I2C_ALGO_BIT; - dib->i2c_adap.client_register = dibusb_i2c_client_register, - dib->i2c_adap.client_unregister = dibusb_i2c_client_unregister, i2c_set_adapdata(&dib->i2c_adap, dib); @@ -446,8 +559,8 @@ dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; dib->demux.priv = (void *)dib; - dib->demux.filternum = DIBUSB_MAX_PIDS; - dib->demux.feednum = DIBUSB_MAX_PIDS; + /* get pidcount from demod */ + dib->demux.feednum = dib->demux.filternum = 16; dib->demux.start_feed = dibusb_start_feed; dib->demux.stop_feed = dibusb_stop_feed; dib->demux.write_to_decoder = NULL; @@ -466,6 +579,11 @@ dvb_net_init(dib->adapter, &dib->dvb_net, &dib->demux.dmx); + frontend_init(dib); + + /* Start the remote-control polling. */ + schedule_delayed_work(&dib->rc_query_work, msecs_to_jiffies(RC_QUERY_INTERVAL)); + goto success; err_dmx_dev: dvb_dmx_release(&dib->demux); @@ -482,12 +600,17 @@ static int dibusb_dvb_exit(struct usb_dibusb *dib) { + cancel_delayed_work(&dib->rc_query_work); + flush_scheduled_work(); + input_unregister_device(&dib->rc_input_dev); + dib->dvb_is_ready = 0; deb_info("unregistering DVB part\n"); dvb_net_release(&dib->dvb_net); dib->demux.dmx.close(&dib->demux.dmx); dvb_dmxdev_release(&dib->dmxdev); dvb_dmx_release(&dib->demux); + if (dib->fe != NULL) dvb_unregister_frontend(dib->fe); i2c_del_adapter(&dib->i2c_adap); dvb_unregister_adapter(dib->adapter); @@ -497,21 +620,36 @@ static int dibusb_exit(struct usb_dibusb *dib) { int i; - for (i = 0; i < DIBUSB_TS_NUM_URBS; i++) - if (dib->buf_urb[i] != NULL) { + if (dib->urb_list != NULL) { + for (i = 0; i < dib->dibdev->parm->num_urbs; i++) { + if (dib->urb_list[i] != NULL) { deb_info("killing URB no. %d.\n",i); - usb_kill_urb(dib->buf_urb[i]); // TODO kernel version ifdef for unlink_urb + + /* stop the URBs */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7) + usb_unlink_urb(dib->urb_list[i]); +#else + usb_kill_urb(dib->urb_list[i]); +#endif deb_info("freeing URB no. %d.\n",i); - usb_free_urb(dib->buf_urb[i]); + /* free the URBs */ + usb_free_urb(dib->urb_list[i]); + } } - pci_free_consistent(NULL,DIBUSB_TS_BUFFER_SIZE,dib->buffer,dib->dma_handle); + /* free the urb array */ + kfree(dib->urb_list); + } + + pci_free_consistent(NULL, + dib->dibdev->parm->urb_buf_size*dib->dibdev->parm->num_urbs,dib->buffer, + dib->dma_handle); return 0; } static int dibusb_init(struct usb_dibusb *dib) { - int ret,i; + int ret,i,bufsize; sema_init(&dib->usb_sem, 1); sema_init(&dib->i2c_sem, 1); @@ -519,46 +657,70 @@ * when reloading the driver w/o replugging the device * a timeout occures, this helps */ - usb_clear_halt(dib->udev,COMMAND_PIPE); - usb_clear_halt(dib->udev,RESULT_PIPE); - usb_clear_halt(dib->udev,DATA_PIPE); - - /* dibusb_reset_cpu(dib); */ + usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->parm->cmd_pipe)); + usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->result_pipe)); + usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->data_pipe)); + + /* allocate the array for the data transfer URBs */ + dib->urb_list = kmalloc(dib->dibdev->parm->num_urbs*sizeof(struct urb *),GFP_KERNEL); + if (dib->urb_list == NULL) + return -ENOMEM; + memset(dib->urb_list,0,dib->dibdev->parm->num_urbs*sizeof(struct urb *)); - if ((dib->buffer = pci_alloc_consistent(NULL,DIBUSB_TS_BUFFER_SIZE, &dib->dma_handle)) == NULL) { + bufsize = dib->dibdev->parm->num_urbs*dib->dibdev->parm->urb_buf_size; + deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize); + /* allocate the actual buffer for the URBs */ + if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) { + dibusb_exit(dib); return -ENOMEM; } - memset(dib->buffer,0,DIBUSB_TS_BUFFER_SIZE); - for (i = 0; i < DIBUSB_TS_NUM_URBS; i++) { - if (!(dib->buf_urb[i] = usb_alloc_urb(0,GFP_KERNEL))) { + memset(dib->buffer,0,bufsize); + + /* allocate and submit the URBs */ + for (i = 0; i < dib->dibdev->parm->num_urbs; i++) { + if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_KERNEL))) { dibusb_exit(dib); return -ENOMEM; } deb_info("submitting URB no. %d\n",i); - usb_fill_bulk_urb( dib->buf_urb[i], dib->udev, DATA_PIPE, - &dib->buffer[i*DIBUSB_TS_URB_BUFFER_SIZE], DIBUSB_TS_URB_BUFFER_SIZE, + usb_fill_bulk_urb( dib->urb_list[i], dib->udev, + usb_rcvbulkpipe(dib->udev,dib->dibdev->parm->data_pipe), + &dib->buffer[i*dib->dibdev->parm->urb_buf_size], + dib->dibdev->parm->urb_buf_size, dibusb_urb_complete, dib); - dib->buf_urb[i]->transfer_flags = 0; - if ((ret = usb_submit_urb(dib->buf_urb[i],GFP_KERNEL))) { + dib->urb_list[i]->transfer_flags = 0; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,7) + dib->urb_list[i]->timeout = 0; +#endif + + if ((ret = usb_submit_urb(dib->urb_list[i],GFP_KERNEL))) { err("could not submit buffer urb no. %d\n",i); dibusb_exit(dib); return ret; } } - for (i=0; i < DIBUSB_MAX_PIDS; i++) { - dib->pid_list[i].reg = i+DIB3000MB_REG_FIRST_PID; - dib->pid_list[i].pid = 0; - dib->pid_list[i].active = 0; - dib->pid_list[i].dib = dib; - } - - dib->feedcount = 0; - dib->streaming = 0; dib->dvb_is_ready = 0; + /* Initialise the remote-control structures.*/ + init_input_dev(&dib->rc_input_dev); + + dib->rc_input_dev.evbit[0] = BIT(EV_KEY); + dib->rc_input_dev.keycodesize = sizeof(unsigned char); + dib->rc_input_dev.keycodemax = KEY_MAX; + dib->rc_input_dev.name = DRIVER_DESC " remote control"; + + for (i=0; irc_input_dev.keybit); + + input_register_device(&dib->rc_input_dev); + + dib->rc_input_event = KEY_MAX; + + INIT_WORK(&dib->rc_query_work, dibusb_query_rc, dib); + if ((ret = dibusb_dvb_init(dib))) { dibusb_exit(dib); return ret; @@ -579,17 +741,20 @@ struct dibusb_device *dibdev) { const struct firmware *fw = NULL; + const char **fws; u16 addr; u8 *b,*p; int ret = 0,i; - for (i = 0; i < sizeof(valid_firmware_filenames)/sizeof(const char*); i++) { - if ((ret = request_firmware(&fw, valid_firmware_filenames[i], &udev->dev)) == 0) { - info("using firmware file (%s).",valid_firmware_filenames[i]); + fws = dibdev->parm->fw_filenames; + + for (i = 0; i < sizeof(fws)/sizeof(const char*); i++) { + if ((ret = request_firmware(&fw, fws[i], &udev->dev)) == 0) { + info("using firmware file (%s).",fws[i]); break; } deb_info("tried to find '%s' firmware - unsuccessful. (%d)\n", - valid_firmware_filenames[i],ret); + fws[i],ret); } if (fw == NULL) { @@ -609,7 +774,7 @@ /* stop the CPU */ reset = 1; - if ((ret = dibusb_writemem(udev,DIBUSB_CPU_CSREG,&reset,1)) != 1) + if ((ret = dibusb_writemem(udev,dibdev->parm->usb_cpu_csreg,&reset,1)) != 1) err("could not stop the USB controller CPU."); for(i = 0; p[i+3] == 0 && i < fw->size; ) { b = (u8 *) &p[i]; @@ -631,7 +796,7 @@ ret = 0; /* restart the CPU */ reset = 0; - if (ret || dibusb_writemem(udev,DIBUSB_CPU_CSREG,&reset,1) != 1) { + if (ret || dibusb_writemem(udev,dibdev->parm->usb_cpu_csreg,&reset,1) != 1) { err("could not restart the USB controller CPU."); ret = -EINVAL; } @@ -679,6 +844,21 @@ if (cold) ret = dibusb_loadfirmware(udev,dibdev); else { + switch (udev->speed) { + case USB_SPEED_LOW: + err("cannot handle USB speed because it is to sLOW."); + break; + case USB_SPEED_FULL: + info("running at FULL speed, will use pid filter."); + break; + case USB_SPEED_HIGH: + info("running at HIGH speed, will deliver the complete TS."); + break; + case USB_SPEED_UNKNOWN: /* fall through */ + default: + err("cannot handle USB speed because it is unkown."); + break; + } dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL); if (dib == NULL) { err("no memory"); diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h --- a/drivers/media/dvb/dibusb/dvb-dibusb.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dibusb/dvb-dibusb.h 2004-12-12 17:40:52 -08:00 @@ -7,136 +7,252 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. * - * - * * for more information see dvb-dibusb.c . */ #ifndef __DVB_DIBUSB_H__ #define __DVB_DIBUSB_H__ -#define DIBUSB_DEMOD_I2C_ADDR_DEFAULT 0x10 +#include "dib3000.h" -/* Vendor IDs */ -#define USB_VID_TWINHAN_ID 0x1822 -#define USB_VID_IMC_NETWORKS_ID 0x13d3 -#define USB_VID_EMPIA_ID 0xeb1a -#define USB_VID_DIBCOM_ID 0x10b8 -#define USB_VID_ULTIMA_ELECTRONIC_ID 0x05d8 -#define USB_VID_COMPRO_ID 0x185b -#define USB_VID_HYPER_PALTEK 0x1025 +typedef enum { + DIBUSB1_1 = 0, + DIBUSB2_0, + DIBUSB1_1_AN2235, +} dibusb_type; + +static const char * dibusb_fw_filenames1_1[] = { + "dvb-dibusb-5.0.0.11.fw" +}; -/* Product IDs before loading the firmware */ -#define USB_PID_TWINHAN_VP7041_COLD_ID 0x3201 -#define USB_PID_KWORLD_VSTREAM_COLD_ID 0x17de -#define USB_PID_DIBCOM_MOD3000_COLD_ID 0x0bb8 -#define USB_PID_ULTIMA_TVBOX_COLD_ID 0x8105 -#define USB_PID_COMPRO_DVBU2000_COLD_ID 0xd000 -#define USB_PID_UNK_HYPER_PALTEK_COLD_ID 0x005e - -/* product ID afterwards */ -#define USB_PID_TWINHAN_VP7041_WARM_ID 0x3202 -#define USB_PID_KWORLD_VSTREAM_WARM_ID 0x17df -#define USB_PID_DIBCOM_MOD3000_WARM_ID 0x0bb9 -#define USB_PID_ULTIMA_TVBOX_WARM_ID 0x8106 -#define USB_PID_COMPRO_DVBU2000_WARM_ID 0xd001 -#define USB_PID_UNK_HYPER_PALTEK_WARM_ID 0x005f - -/* static array of valid firmware names, the best one first */ -static const char * valid_firmware_filenames[] = { - "dvb-dibusb-5.0.0.11.fw", +static const char * dibusb_fw_filenames1_1_an2235[] = { + "dvb-dibusb-an2235-1.fw" +}; + +static const char * dibusb_fw_filenames2_0[] = { + "dvb-dibusb-6.0.0.5.fw" +}; + +struct dibusb_device_parameter { + dibusb_type type; + u8 demod_addr; + const char **fw_filenames; + const char *usb_controller; + u16 usb_cpu_csreg; + + int num_urbs; + int urb_buf_size; + int default_size; + int firmware_bug; + + int cmd_pipe; + int result_pipe; + int data_pipe; +}; + +static struct dibusb_device_parameter dibusb_dev_parm[3] = { + { .type = DIBUSB1_1, + .demod_addr = 0x10, + .fw_filenames = dibusb_fw_filenames1_1, + .usb_controller = "Cypress AN2135", + .usb_cpu_csreg = 0x7f92, + + .num_urbs = 3, + .urb_buf_size = 4096, + .default_size = 188*21, + .firmware_bug = 1, + + .cmd_pipe = 0x01, + .result_pipe = 0x81, + .data_pipe = 0x82, + }, + { .type = DIBUSB2_0, + .demod_addr = 0x10, + .fw_filenames = dibusb_fw_filenames2_0, + .usb_controller = "Cypress FX2", + .usb_cpu_csreg = 0xe600, + + .num_urbs = 3, + .urb_buf_size = 40960, + .default_size = 188*210, + .firmware_bug = 0, + + .cmd_pipe = 0x01, + .result_pipe = 0x81, + .data_pipe = 0x86, + }, + { .type = DIBUSB1_1_AN2235, + .demod_addr = 0x10, + .fw_filenames = dibusb_fw_filenames1_1_an2235, + .usb_controller = "Cypress CY7C64613 (AN2235)", + .usb_cpu_csreg = 0x7f92, + + .num_urbs = 3, + .urb_buf_size = 4096, + .default_size = 188*21, + .firmware_bug = 1, + + .cmd_pipe = 0x01, + .result_pipe = 0x81, + .data_pipe = 0x82, + } }; struct dibusb_device { + const char *name; u16 cold_product_id; u16 warm_product_id; - u8 demod_addr; - const char *name; + struct dibusb_device_parameter *parm; }; -#define DIBUSB_SUPPORTED_DEVICES 6 +/* Vendor IDs */ +#define USB_VID_ANCHOR 0x0547 +#define USB_VID_AVERMEDIA 0x14aa +#define USB_VID_COMPRO 0x185b +#define USB_VID_DIBCOM 0x10b8 +#define USB_VID_EMPIA 0xeb1a +#define USB_VID_GRANDTEC 0x5032 +#define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_IMC_NETWORKS 0x13d3 +#define USB_VID_TWINHAN 0x1822 +#define USB_VID_ULTIMA_ELECTRONIC 0x05d8 + +/* Product IDs */ +#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 +#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 +#define USB_PID_COMPRO_DVBU2000_COLD 0xd000 +#define USB_PID_COMPRO_DVBU2000_WARM 0xd001 +#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 +#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9 +#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6 +#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 +#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 +#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 +#define USB_PID_KWORLD_VSTREAM_COLD 0x17de +#define USB_PID_KWORLD_VSTREAM_WARM 0x17df +#define USB_PID_TWINHAN_VP7041_COLD 0x3201 +#define USB_PID_TWINHAN_VP7041_WARM 0x3202 +#define USB_PID_ULTIMA_TVBOX_COLD 0x8105 +#define USB_PID_ULTIMA_TVBOX_WARM 0x8106 +#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107 +#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108 +#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235 +#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e +#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f +#define USB_PID_YAKUMO_DTT200U_COLD 0x0201 +#define USB_PID_YAKUMO_DTT200U_WARM 0x0301 + +#define DIBUSB_SUPPORTED_DEVICES 12 /* USB Driver stuff */ static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = { - { .cold_product_id = USB_PID_TWINHAN_VP7041_COLD_ID, - .warm_product_id = USB_PID_TWINHAN_VP7041_WARM_ID, - .name = "TwinhanDTV USB-Ter/Magic Box / HAMA USB DVB-T device", - .demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT, - }, - { .cold_product_id = USB_PID_KWORLD_VSTREAM_COLD_ID, - .warm_product_id = USB_PID_KWORLD_VSTREAM_WARM_ID, - .name = "KWorld V-Stream XPERT DTV - DVB-T USB", - .demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT, - }, - { .cold_product_id = USB_PID_DIBCOM_MOD3000_COLD_ID, - .warm_product_id = USB_PID_DIBCOM_MOD3000_WARM_ID, - .name = "DiBcom USB DVB-T reference design (MOD300)", - .demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT, - }, - { .cold_product_id = USB_PID_ULTIMA_TVBOX_COLD_ID, - .warm_product_id = USB_PID_ULTIMA_TVBOX_WARM_ID, - .name = "Ultima Electronic/Artec T1 USB TVBOX", - .demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT, - }, - { .cold_product_id = USB_PID_COMPRO_DVBU2000_COLD_ID, - .warm_product_id = USB_PID_COMPRO_DVBU2000_WARM_ID, - .name = "Compro Videomate DVB-U2000 - DVB-T USB", - .demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT, - }, - { .cold_product_id = USB_PID_UNK_HYPER_PALTEK_COLD_ID, - .warm_product_id = USB_PID_UNK_HYPER_PALTEK_WARM_ID, - .name = "Unkown USB DVB-T device ???? please report the name to linux-dvb or to the author", - .demod_addr = DIBUSB_DEMOD_I2C_ADDR_DEFAULT, + { .name = "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device", + .cold_product_id = USB_PID_TWINHAN_VP7041_COLD, + .warm_product_id = USB_PID_TWINHAN_VP7041_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "KWorld V-Stream XPERT DTV - DVB-T USB1.1", + .cold_product_id = USB_PID_KWORLD_VSTREAM_COLD, + .warm_product_id = USB_PID_KWORLD_VSTREAM_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "Grandtec USB1.1 DVB-T/DiBcom USB1.1 DVB-T reference design (MOD3000)", + .cold_product_id = USB_PID_DIBCOM_MOD3000_COLD, + .warm_product_id = USB_PID_DIBCOM_MOD3000_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "Artec T1 USB1.1 TVBOX with AN2135", + .cold_product_id = USB_PID_ULTIMA_TVBOX_COLD, + .warm_product_id = USB_PID_ULTIMA_TVBOX_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "Artec T1 USB1.1 TVBOX with AN2235", + .cold_product_id = USB_PID_ULTIMA_TVBOX_AN2235_COLD, + .warm_product_id = USB_PID_ULTIMA_TVBOX_AN2235_WARM, + .parm = &dibusb_dev_parm[2], + }, + { .name = "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)", + .cold_product_id = USB_PID_ULTIMA_TVBOX_ANCHOR_COLD, + .warm_product_id = 0, /* undefined, this design becomes USB_PID_DIBCOM_MOD3000_WARM in warm state */ + .parm = &dibusb_dev_parm[2], + }, + { .name = "Compro Videomate DVB-U2000 - DVB-T USB1.1", + .cold_product_id = USB_PID_COMPRO_DVBU2000_COLD, + .warm_product_id = USB_PID_COMPRO_DVBU2000_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "Unkown USB1.1 DVB-T device ???? please report the name to the author", + .cold_product_id = USB_PID_UNK_HYPER_PALTEK_COLD, + .warm_product_id = USB_PID_UNK_HYPER_PALTEK_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "DiBcom USB2.0 DVB-T reference design (MOD3000P)", + .cold_product_id = USB_PID_DIBCOM_MOD3001_COLD, + .warm_product_id = USB_PID_DIBCOM_MOD3001_WARM, + .parm = &dibusb_dev_parm[1], + }, + { .name = "Grandtec DVB-T USB1.1", + .cold_product_id = USB_PID_GRANDTEC_DVBT_USB_COLD, + .warm_product_id = USB_PID_GRANDTEC_DVBT_USB_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "Avermedia AverTV DVBT USB1.1", + .cold_product_id = USB_PID_AVERMEDIA_DVBT_USB_COLD, + .warm_product_id = USB_PID_AVERMEDIA_DVBT_USB_WARM, + .parm = &dibusb_dev_parm[0], + }, + { .name = "Yakumo DVB-T mobile USB2.0", + .cold_product_id = USB_PID_YAKUMO_DTT200U_COLD, + .warm_product_id = USB_PID_YAKUMO_DTT200U_WARM, + .parm = &dibusb_dev_parm[1], } }; /* USB Driver stuff */ /* table of devices that work with this driver */ static struct usb_device_id dibusb_table [] = { - { USB_DEVICE(USB_VID_TWINHAN_ID, USB_PID_TWINHAN_VP7041_COLD_ID) }, - { USB_DEVICE(USB_VID_TWINHAN_ID, USB_PID_TWINHAN_VP7041_WARM_ID) }, - { USB_DEVICE(USB_VID_IMC_NETWORKS_ID,USB_PID_TWINHAN_VP7041_COLD_ID) }, - { USB_DEVICE(USB_VID_IMC_NETWORKS_ID,USB_PID_TWINHAN_VP7041_WARM_ID) }, - { USB_DEVICE(USB_VID_EMPIA_ID, USB_PID_KWORLD_VSTREAM_COLD_ID) }, - { USB_DEVICE(USB_VID_EMPIA_ID, USB_PID_KWORLD_VSTREAM_WARM_ID) }, - { USB_DEVICE(USB_VID_DIBCOM_ID, USB_PID_DIBCOM_MOD3000_COLD_ID) }, - { USB_DEVICE(USB_VID_DIBCOM_ID, USB_PID_DIBCOM_MOD3000_WARM_ID) }, - { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC_ID, USB_PID_ULTIMA_TVBOX_COLD_ID) }, - { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC_ID, USB_PID_ULTIMA_TVBOX_WARM_ID) }, - { USB_DEVICE(USB_VID_COMPRO_ID, USB_PID_COMPRO_DVBU2000_COLD_ID) }, - { USB_DEVICE(USB_VID_COMPRO_ID, USB_PID_COMPRO_DVBU2000_WARM_ID) }, - { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD_ID) }, - { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM_ID) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_COLD)}, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_WARM)}, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, + { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, + { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, + { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, + { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, + { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, + { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, + { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, + { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, + { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, + { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_COLD) }, + { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_WARM) }, + { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, + { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_COLD) }, + { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_WARM) }, + +/* + * activate the following define when you have the device and want to compile + * build from build-2.6 in dvb-kernel + */ +// #define CONFIG_DVB_DIBUSB_MISDESIGNED_AN2235 +#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_AN2235 + { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +#endif { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, dibusb_table); -/* CS register start/stop the usb controller cpu */ -#define DIBUSB_CPU_CSREG 0x7F92 - -// 0x10 is the I2C address of the first demodulator on the board -#define DIBUSB_DEMOD_I2C_ADDR_DEFAULT 0x10 #define DIBUSB_I2C_TIMEOUT HZ*5 -#define DIBUSB_MAX_PIDS 16 - -#define DIB3000MB_REG_FIRST_PID ( 153) - -struct usb_dibusb; - -struct dibusb_pid { - u16 reg; - u16 pid; - int active; - struct usb_dibusb *dib; -}; - -#define DIBUSB_TS_NUM_URBS 3 -#define DIBUSB_TS_URB_BUFFER_SIZE 4096 -#define DIBUSB_TS_BUFFER_SIZE (DIBUSB_TS_NUM_URBS * DIBUSB_TS_URB_BUFFER_SIZE) -#define DIBUSB_TS_DEFAULT_SIZE (188*21) - struct usb_dibusb { /* usb */ struct usb_device * udev; @@ -144,14 +260,12 @@ struct dibusb_device * dibdev; int feedcount; - int streaming; - struct urb * buf_urb[DIBUSB_TS_NUM_URBS]; + struct dib3000_xfer_ops xfer_ops; + + struct urb **urb_list; u8 *buffer; dma_addr_t dma_handle; - spinlock_t pid_list_lock; - struct dibusb_pid pid_list[DIBUSB_MAX_PIDS]; - /* I2C */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; @@ -166,16 +280,14 @@ struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; + struct dvb_frontend* fe; + + /* remote control */ + struct input_dev rc_input_dev; + struct work_struct rc_query_work; + int rc_input_event; }; -#define COMMAND_PIPE usb_sndbulkpipe(dib->udev, 0x01) -#define RESULT_PIPE usb_rcvbulkpipe(dib->udev, 0x81) -#define DATA_PIPE usb_rcvbulkpipe(dib->udev, 0x82) -/* - * last endpoint 0x83 only used for chaining the buffers - * of the endpoints in the cypress - */ -#define CHAIN_PIPE_DO_NOT_USE usb_rcvbulkpipe(dib->udev, 0x83) /* types of first byte of each buffer */ @@ -208,17 +320,5 @@ #define DIBUSB_IOCTL_CMD_POWER_MODE 0x00 #define DIBUSB_IOCTL_POWER_SLEEP 0x00 #define DIBUSB_IOCTL_POWER_WAKEUP 0x01 - - -/* - * values from the demodulator which are needed in - * the usb driver as well - */ - -#define DIB3000MB_REG_FIFO ( 145) -#define DIB3000MB_FIFO_INHIBIT ( 1) -#define DIB3000MB_FIFO_ACTIVATE ( 0) - -#define DIB3000MB_ACTIVATE_FILTERING (0x2000) #endif diff -Nru a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile --- a/drivers/media/dvb/dvb-core/Makefile 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/dvb-core/Makefile 2004-12-12 17:40:53 -08:00 @@ -4,6 +4,6 @@ dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ dvb_ca_en50221.o dvb_frontend.o \ - dvb_net.o dvb_ksyms.o dvb_ringbuffer.o + dvb_net.o dvb_ringbuffer.o obj-$(CONFIG_DVB_CORE) += dvb-core.o diff -Nru a/drivers/media/dvb/dvb-core/Makefile.lib b/drivers/media/dvb/dvb-core/Makefile.lib --- a/drivers/media/dvb/dvb-core/Makefile.lib 2004-12-12 17:40:52 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1 +0,0 @@ -obj-$(CONFIG_DVB_CORE) += crc32.o diff -Nru a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c --- a/drivers/media/dvb/dvb-core/dmxdev.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/dvb-core/dmxdev.c 2004-12-12 17:40:53 -08:00 @@ -42,18 +42,12 @@ #define dprintk if (debug) printk -inline struct dmxdev_filter * +static inline struct dmxdev_filter * dvb_dmxdev_file_to_filter(struct file *file) { return (struct dmxdev_filter *) file->private_data; } -inline struct dmxdev_dvr * -dvb_dmxdev_file_to_dvr(struct dmxdev *dmxdev, struct file *file) -{ - return (struct dmxdev_dvr *) file->private_data; -} - static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) { buffer->data=NULL; @@ -846,7 +840,7 @@ } -ssize_t +static ssize_t dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file); @@ -1122,6 +1116,7 @@ return 0; } +EXPORT_SYMBOL(dvb_dmxdev_init); void dvb_dmxdev_release(struct dmxdev *dmxdev) @@ -1138,5 +1133,5 @@ } dmxdev->demux->close(dmxdev->demux); } - +EXPORT_SYMBOL(dvb_dmxdev_release); diff -Nru a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2004-12-12 17:40:52 -08:00 @@ -181,10 +181,12 @@ { int i; - if (hlen < nlen) return NULL; + if (hlen < nlen) + return NULL; for(i=0; i<= hlen - nlen; i++) { - if (!strncmp(haystack+i, needle, nlen)) return haystack+i; + if (!strncmp(haystack + i, needle, nlen)) + return haystack + i; } return NULL; @@ -211,7 +213,7 @@ } /* poll mode */ - slot_status = ca->pub->poll_slot_status(ca->pub, slot); + slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open); cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1: 0; cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1: 0; @@ -250,7 +252,8 @@ * * @return 0 on success, nonzero on error. */ -static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private* ca, int slot, u8 waitfor, int timeout_hz) +static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, + u8 waitfor, int timeout_hz) { unsigned long timeout; unsigned long start; @@ -263,7 +266,8 @@ while(1) { /* read the status and check for error */ int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); - if (res < 0) return -EIO; + if (res < 0) + return -EIO; /* if we got the flags, it was successful! */ if (res & waitfor) { @@ -311,24 +315,33 @@ ca->slot_info[slot].link_buf_size = 2; /* read the buffer size from the CAM */ - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) return ret; - if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ/10)) != 0) return ret; - if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) return -EIO; - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) return ret; + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) + return ret; + if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0) + return ret; + if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) + return -EIO; + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) + return ret; /* store it, and choose the minimum of our buffer and the CAM's buffer size */ buf_size = (buf[0] << 8) | buf[1]; - if (buf_size > HOST_LINK_BUF_SIZE) buf_size = HOST_LINK_BUF_SIZE; + if (buf_size > HOST_LINK_BUF_SIZE) + buf_size = HOST_LINK_BUF_SIZE; ca->slot_info[slot].link_buf_size = buf_size; buf[0] = buf_size >> 8; buf[1] = buf_size & 0xff; dprintk("Chosen link buffer size of %i\n", buf_size); /* write the buffer size to the CAM */ - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) return ret; - if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ/10)) != 0) return ret; - if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) return -EIO; - if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) return ret; + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) + return ret; + if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0) + return ret; + if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) + return -EIO; + if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) + return ret; /* success */ return 0; @@ -355,7 +368,8 @@ int _address = *address; /* grab the next tuple length and type */ - if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) return _tupleType; + if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) + return _tupleType; if (_tupleType == 0xff) { dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType); *address += 2; @@ -363,7 +377,8 @@ *tupleLength = 0; return 0; } - if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address+2)) < 0) return _tupleLength; + if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0) + return _tupleLength; _address += 4; dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength); @@ -371,7 +386,9 @@ /* read in the whole tuple */ for(i=0; i< _tupleLength; i++) { tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i*2)); - dprintk(" 0x%02x: 0x%02x %c\n", i, tuple[i] & 0xff, ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); + dprintk(" 0x%02x: 0x%02x %c\n", + i, tuple[i] & 0xff, + ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); } _address += (_tupleLength*2); @@ -409,40 +426,58 @@ // CISTPL_DEVICE_0A - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; - if (tupleType != 0x1D) return -EINVAL; + if ((status = + dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x1D) + return -EINVAL; // CISTPL_DEVICE_0C - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; - if (tupleType != 0x1C) return -EINVAL; + if ((status = + dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x1C) + return -EINVAL; // CISTPL_VERS_1 - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; - if (tupleType != 0x15) return -EINVAL; + if ((status = + dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x15) + return -EINVAL; // CISTPL_MANFID - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; - if (tupleType != 0x20) return -EINVAL; - if (tupleLength != 4) return -EINVAL; + if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, + &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x20) + return -EINVAL; + if (tupleLength != 4) + return -EINVAL; manfid = (tuple[1] << 8) | tuple[0]; devid = (tuple[3] << 8) | tuple[2]; // CISTPL_CONFIG - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; - if (tupleType != 0x1A) return -EINVAL; - if (tupleLength < 3) return -EINVAL; + if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, + &tupleLength, tuple)) < 0) + return status; + if (tupleType != 0x1A) + return -EINVAL; + if (tupleLength < 3) + return -EINVAL; /* extract the configbase */ rasz = tuple[0] & 3; - if (tupleLength < (3 + rasz + 14)) return -EINVAL; + if (tupleLength < (3 + rasz + 14)) + return -EINVAL; ca->slot_info[slot].config_base = 0; for(i=0; i< rasz+1; i++) { ca->slot_info[slot].config_base |= (tuple[2+i] << (8*i)); @@ -450,8 +485,10 @@ /* check it contains the correct DVB string */ dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8); - if (dvb_str == NULL) return -EINVAL; - if (tupleLength < ((dvb_str - (char*) tuple) + 12)) return -EINVAL; + if (dvb_str == NULL) + return -EINVAL; + if (tupleLength < ((dvb_str - (char *) tuple) + 12)) + return -EINVAL; /* is it a version we support? */ if (strncmp(dvb_str + 8, "1.00", 4)) { @@ -462,20 +499,25 @@ /* process the CFTABLE_ENTRY tuples, and any after those */ while((!end_chain) && (address < 0x1000)) { - if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) return status; + if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, + &tupleLength, tuple)) < 0) + return status; switch(tupleType) { case 0x1B: // CISTPL_CFTABLE_ENTRY - if (tupleLength < (2+11+17)) break; + if (tupleLength < (2 + 11 + 17)) + break; /* if we've already parsed one, just use it */ - if (got_cftableentry) break; + if (got_cftableentry) + break; /* get the config option */ ca->slot_info[slot].config_option = tuple[0] & 0x3f; /* OK, check it contains the correct strings */ if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) || - (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) break; + (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) + break; got_cftableentry = 1; break; @@ -488,17 +530,17 @@ break; default: /* Unknown tuple type - just skip this tuple and move to the next one */ - dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, tupleLength); + dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, + tupleLength); break; } } - if ((address > 0x1000) || (!got_cftableentry)) return -EINVAL; + if ((address > 0x1000) || (!got_cftableentry)) + return -EINVAL; dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", - manfid, devid, - ca->slot_info[slot].config_base, - ca->slot_info[slot].config_option); + manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); // success! return 0; @@ -518,7 +560,9 @@ dprintk ("%s\n", __FUNCTION__); /* set the config option */ - ca->pub->write_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); + ca->pub->write_attribute_mem(ca->pub, slot, + ca->slot_info[slot].config_base, + ca->slot_info[slot].config_option); /* check it */ configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base); @@ -558,6 +602,11 @@ int buf_free; down_read(&ca->slot_info[slot].sem); + if (ca->slot_info[slot].rx_buffer.data == NULL) { + up_read(&ca->slot_info[slot].sem); + status = -EIO; + goto exit; + } buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); up_read(&ca->slot_info[slot].sem); @@ -568,7 +617,8 @@ } /* check if there is data available */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; if (!(status & STATUSREG_DA)) { /* no data */ status = 0; @@ -576,28 +626,33 @@ } /* read the amount of data */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) goto exit; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) + goto exit; bytes_read = status << 8; - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) goto exit; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) + goto exit; bytes_read |= status; /* check it will fit */ if (ebuf == NULL) { if (bytes_read > ca->slot_info[slot].link_buf_size) { - printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size!\n", ca->dvbdev->adapter->num); + printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", + ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; goto exit; } if (bytes_read < 2) { - printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", ca->dvbdev->adapter->num); + printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; goto exit; } } else { if (bytes_read > ecount) { - printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", ca->dvbdev->adapter->num); + printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", + ca->dvbdev->adapter->num); status = -EIO; goto exit; } @@ -606,14 +661,16 @@ /* fill the buffer */ for(i=0; i < bytes_read; i++) { /* read byte and check */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) goto exit; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) + goto exit; /* OK, store it in the buffer */ buf[i] = status; } /* check for read error (RE should now be 0) */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; if (status & STATUSREG_RE) { ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; @@ -623,13 +680,19 @@ /* OK, add it to the receive buffer, or copy into external buffer if supplied */ if (ebuf == NULL) { down_read(&ca->slot_info[slot].sem); + if (ca->slot_info[slot].rx_buffer.data == NULL) { + up_read(&ca->slot_info[slot].sem); + status = -EIO; + goto exit; + } dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); up_read(&ca->slot_info[slot].sem); } else { memcpy(ebuf, buf, bytes_read); } - dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, buf[0], (buf[1] & 0x80) == 0, bytes_read); + dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, + buf[0], (buf[1] & 0x80) == 0, bytes_read); /* wake up readers when a last_fragment is received */ if ((buf[1] & 0x80) == 0x00) { @@ -664,20 +727,25 @@ // sanity check - if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL; + if (bytes_write > ca->slot_info[slot].link_buf_size) + return -EINVAL; /* check if interface is actually waiting for us to read from it, or if a read is in progress */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exitnowrite; if (status & (STATUSREG_DA|STATUSREG_RE)) { status = -EAGAIN; goto exitnowrite; } /* OK, set HC bit */ - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_HC)) != 0) goto exit; + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, + IRQEN | CMDREG_HC)) != 0) + goto exit; /* check if interface is still free */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; if (!(status & STATUSREG_FR)) { /* it wasn't free => try again later */ status = -EAGAIN; @@ -685,16 +753,21 @@ } /* send the amount of data */ - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) goto exit; - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, bytes_write & 0xff)) != 0) goto exit; + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) + goto exit; + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, + bytes_write & 0xff)) != 0) + goto exit; /* send the buffer */ for(i=0; i < bytes_write; i++) { - if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) goto exit; + if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) + goto exit; } /* check for write error (WE should now be 0) */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit; + if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) + goto exit; if (status & STATUSREG_WE) { ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; @@ -702,7 +775,8 @@ } status = bytes_write; - dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, buf[0], (buf[1] & 0x80) == 0, bytes_write); + dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, + buf[0], (buf[1] & 0x80) == 0, bytes_write); exit: ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); @@ -710,6 +784,7 @@ exitnowrite: return status; } +EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); @@ -730,7 +805,8 @@ down_write(&ca->slot_info[slot].sem); ca->pub->slot_shutdown(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - if (ca->slot_info[slot].rx_buffer.data) vfree(ca->slot_info[slot].rx_buffer.data); + if (ca->slot_info[slot].rx_buffer.data) + vfree(ca->slot_info[slot].rx_buffer.data); ca->slot_info[slot].rx_buffer.data = NULL; up_write(&ca->slot_info[slot].sem); @@ -743,6 +819,7 @@ /* success */ return 0; } +EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); /** @@ -771,6 +848,7 @@ atomic_inc(&ca->slot_info[slot].camchange_count); dvb_ca_en50221_thread_wakeup(ca); } +EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); /** @@ -815,7 +893,8 @@ break; case DVB_CA_SLOTSTATE_RUNNING: - if (ca->open) dvb_ca_en50221_read_data(ca, slot, NULL, 0); + if (ca->open) + dvb_ca_en50221_read_data(ca, slot, NULL, 0); break; } } @@ -851,7 +930,8 @@ ca->wakeup = 0; return 1; } - if (ca->exit) return 1; + if (ca->exit) + return 1; return 0; } @@ -901,7 +981,8 @@ break; } - if (delay < curdelay) curdelay = delay; + if (delay < curdelay) + curdelay = delay; } ca->delay = curdelay; @@ -918,6 +999,7 @@ char name[15]; int slot; int flags; + int status; int pktcount; void* rxbuf; @@ -938,7 +1020,9 @@ while(!ca->exit) { /* sleep for a bit */ if (!ca->wakeup) { - flags = wait_event_interruptible_timeout(ca->thread_queue, dvb_ca_en50221_thread_should_wakeup(ca), ca->delay); + flags = wait_event_interruptible_timeout(ca->thread_queue, + dvb_ca_en50221_thread_should_wakeup(ca), + ca->delay); if ((flags == -ERESTARTSYS) || ca->exit) { /* got signal or quitting */ break; @@ -952,7 +1036,8 @@ // check the cam status + deal with CAMCHANGEs while(dvb_ca_en50221_check_camstatus(ca, slot)) { /* clear down an old CI slot if necessary */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) dvb_ca_en50221_slot_shutdown(ca, slot); + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) + dvb_ca_en50221_slot_shutdown(ca, slot); /* if a CAM is NOW present, initialise it */ if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) { @@ -979,7 +1064,8 @@ case DVB_CA_SLOTSTATE_WAITREADY: if (time_after(jiffies, ca->slot_info[slot].timeout)) { - printk("dvb_ca adaptor %d: PC card did not respond :(\n", ca->dvbdev->adapter->num); + printk("dvb_ca adaptor %d: PC card did not respond :(\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; @@ -988,20 +1074,25 @@ break; case DVB_CA_SLOTSTATE_VALIDATE: - if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { - printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", ca->dvbdev->adapter->num); + if (dvb_ca_en50221_parse_attributes(ca, slot) + != 0) { + printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; } if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { - printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", ca->dvbdev->adapter->num); + printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; } - if (ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS) != 0) { - printk("dvb_ca adapter %d: Unable to reset CAM IF\n", ca->dvbdev->adapter->num); + if (ca->pub->write_cam_control(ca->pub, slot, + CTRLIF_COMMAND, CMDREG_RS) != 0) { + printk("dvb_ca adapter %d: Unable to reset CAM IF\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; @@ -1016,7 +1107,8 @@ case DVB_CA_SLOTSTATE_WAITFR: if (time_after(jiffies, ca->slot_info[slot].timeout)) { - printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", ca->dvbdev->adapter->num); + printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; @@ -1044,7 +1136,9 @@ dvb_ca_en50221_thread_update_delay(ca); break; } + down_write(&ca->slot_info[slot].sem); dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); + up_write(&ca->slot_info[slot].sem); ca->pub->slot_ts_enable(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; @@ -1053,15 +1147,18 @@ break; case DVB_CA_SLOTSTATE_RUNNING: - if (!ca->open) break; + if (!ca->open) + continue; // no need to poll if the CAM supports IRQs - if (ca->slot_info[slot].da_irq_supported) break; + if (ca->slot_info[slot].da_irq_supported) + break; // poll mode pktcount = 0; - while(dvb_ca_en50221_read_data(ca, slot, NULL, 0) > 0) { - if (!ca->open) break; + while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { + if (!ca->open) + break; /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */ if (dvb_ca_en50221_check_camstatus(ca, slot)) { @@ -1105,7 +1202,8 @@ * * @return 0 on success, <0 on error. */ -static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) +static int dvb_ca_en50221_io_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *parg) { struct dvb_device* dvbdev=(struct dvb_device*) file->private_data; struct dvb_ca_private* ca = (struct dvb_ca_private*) dvbdev->priv; @@ -1120,15 +1218,16 @@ if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { dvb_ca_en50221_slot_shutdown(ca, slot); if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) - dvb_ca_en50221_camchange_irq(ca->pub, slot, DVB_CA_EN50221_CAMCHANGE_INSERTED); + dvb_ca_en50221_camchange_irq(ca->pub, + slot, + DVB_CA_EN50221_CAMCHANGE_INSERTED); } } ca->next_read_slot = 0; dvb_ca_en50221_thread_wakeup(ca); break; - case CA_GET_CAP: - { + case CA_GET_CAP: { struct ca_caps *caps = (struct ca_caps*) parg; caps->slot_num=ca->slot_count; @@ -1138,9 +1237,7 @@ break; } - - case CA_GET_SLOT_INFO: - { + case CA_GET_SLOT_INFO: { struct ca_slot_info *info=(struct ca_slot_info *)parg; if ((info->num > ca->slot_count) || (info->num < 0)) @@ -1148,8 +1245,8 @@ info->type = CA_CI_LINK; info->flags = 0; - if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) && - (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { + if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) + && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { info->flags = CA_CI_MODULE_PRESENT; } if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) { @@ -1177,7 +1274,8 @@ * * @return 0 on success, <0 on error. */ -static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { return dvb_usercopy(inode, file, cmd, arg, dvb_ca_en50221_io_do_ioctl); } @@ -1193,7 +1291,8 @@ * * @return Number of bytes read, or <0 on error. */ -static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static ssize_t dvb_ca_en50221_io_write(struct file *file, + const char __user * buf, size_t count, loff_t * ppos) { struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; @@ -1208,35 +1307,48 @@ dprintk ("%s\n", __FUNCTION__); /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ - if (count < 2) return -EINVAL; + if (count < 2) + return -EINVAL; /* extract slot & connection id */ - if (copy_from_user(&slot, buf, 1)) return -EFAULT; - if (copy_from_user(&connection_id, buf+1, 1)) return -EFAULT; + if (copy_from_user(&slot, buf, 1)) + return -EFAULT; + if (copy_from_user(&connection_id, buf + 1, 1)) + return -EFAULT; buf+=2; count-=2; /* check if the slot is actually running */ - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) return -EINVAL; + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) + return -EINVAL; /* fragment the packets & store in the buffer */ while(fragpos < count) { fraglen = ca->slot_info[slot].link_buf_size - 2; - if ((count - fragpos) < fraglen) fraglen = count - fragpos; + if ((count - fragpos) < fraglen) + fraglen = count - fragpos; fragbuf[0] = connection_id; fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00; - if ((status = copy_from_user(fragbuf+2, buf+fragpos, fraglen)) != 0) goto exit; + if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0) + goto exit; timeout = jiffies + HZ/2; written = 0; while(!time_after(jiffies, timeout)) { + /* check the CAM hasn't been removed/reset in the meantime */ + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) { + status = -EIO; + goto exit; + } + status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen+2); if (status == (fraglen+2)) { written = 1; break; } - if (status != -EAGAIN) goto exit; + if (status != -EAGAIN) + goto exit; msleep(1); } @@ -1269,14 +1381,21 @@ slot = ca->next_read_slot; while((slot_count < ca->slot_count) && (!found)) { - if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot; + if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) + goto nextslot; down_read(&ca->slot_info[slot].sem); + if (ca->slot_info[slot].rx_buffer.data == NULL) { + up_read(&ca->slot_info[slot].sem); + return 0; + } + idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); while(idx != -1) { dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0); - if (connection_id == -1) connection_id = hdr[0]; + if (connection_id == -1) + connection_id = hdr[0]; if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { *_slot = slot; found = 1; @@ -1286,7 +1405,8 @@ idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); } - if (!found) up_read(&ca->slot_info[slot].sem); + if (!found) + up_read(&ca->slot_info[slot].sem); nextslot: slot = (slot + 1) % ca->slot_count; @@ -1308,7 +1428,8 @@ * * @return Number of bytes read, or <0 on error. */ -static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, + size_t count, loff_t * ppos) { struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; @@ -1326,19 +1447,24 @@ dprintk ("%s\n", __FUNCTION__); /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ - if (count < 2) return -EINVAL; + if (count < 2) + return -EINVAL; /* wait for some data */ if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { /* if we're in nonblocking mode, exit immediately */ - if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; /* wait for some data */ - status = wait_event_interruptible(ca->wait_queue, dvb_ca_en50221_io_read_condition(ca, &result, &slot)); + status = wait_event_interruptible(ca->wait_queue, + dvb_ca_en50221_io_read_condition + (ca, &result, &slot)); } if ((status < 0) || (result < 0)) { - if (result) return result; + if (result) + return result; return status; } @@ -1352,7 +1478,8 @@ } dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2, 0); - if (connection_id == -1) connection_id = hdr[0]; + if (connection_id == -1) + connection_id = hdr[0]; if (hdr[0] == connection_id) { if (pktlen < count) { if ((pktlen + fraglen - 2) > count) { @@ -1361,25 +1488,29 @@ fraglen -= 2; } - if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2, buf + pktlen, fraglen, 1)) < 0) { + if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2, + buf + pktlen, fraglen, 1)) < 0) { goto exit; } pktlen += fraglen; } - if ((hdr[1] & 0x80) == 0) last_fragment = 1; + if ((hdr[1] & 0x80) == 0) + last_fragment = 1; dispose = 1; } idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); - if (dispose) dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); + if (dispose) + dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); idx = idx2; dispose = 0; } while (!last_fragment); hdr[0] = slot; hdr[1] = connection_id; - if ((status = copy_to_user(buf, hdr, 2)) != 0) goto exit; + if ((status = copy_to_user(buf, hdr, 2)) != 0) + goto exit; status = pktlen; exit: @@ -1405,14 +1536,20 @@ dprintk ("%s\n", __FUNCTION__); + if (!try_module_get(ca->pub->owner)) + return -EIO; + err=dvb_generic_open(inode, file); if (err<0) return err; for(i=0; i< ca->slot_count; i++) { + if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { down_write(&ca->slot_info[i].sem); + if (ca->slot_info[i].rx_buffer.data != NULL) { dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); + } up_write(&ca->slot_info[i].sem); } } @@ -1437,7 +1574,7 @@ { struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_ca_private *ca=(struct dvb_ca_private*) dvbdev->priv; - int err; + int err = 0; dprintk ("%s\n", __FUNCTION__); @@ -1446,8 +1583,9 @@ dvb_ca_en50221_thread_update_delay(ca); err=dvb_generic_release(inode, file); - if (err<0) - return err; + + module_put(ca->pub->owner); + return 0; } @@ -1476,7 +1614,8 @@ } /* if there is something, return now */ - if (mask) return mask; + if (mask) + return mask; /* wait for something to happen */ poll_wait(file, &ca->wait_queue, wait); @@ -1488,6 +1627,8 @@ return mask; } +EXPORT_SYMBOL(dvb_ca_en50221_init); + static struct file_operations dvb_ca_fops = { .owner = THIS_MODULE, @@ -1521,7 +1662,8 @@ * * @return 0 on success, nonzero on failure */ -int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* pubca, int flags, int slot_count) +int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, + struct dvb_ca_en50221 *pubca, int flags, int slot_count) { int ret; struct dvb_ca_private* ca = NULL; @@ -1529,10 +1671,13 @@ dprintk ("%s\n", __FUNCTION__); - if (slot_count < 1) return -EINVAL; + if (slot_count < 1) + return -EINVAL; /* initialise the system data */ - if ((ca = (struct dvb_ca_private*) kmalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { + if ((ca = + (struct dvb_ca_private *) kmalloc(sizeof(struct dvb_ca_private), + GFP_KERNEL)) == NULL) { ret = -ENOMEM; goto error; } @@ -1556,7 +1701,8 @@ /* register the DVB device */ ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); - if (ret) goto error; + if (ret) + goto error; /* now initialise each slot */ for(i=0; i< slot_count; i++) { @@ -1584,13 +1730,16 @@ error: if (ca != NULL) { - if (ca->dvbdev != NULL) dvb_unregister_device(ca->dvbdev); - if (ca->slot_info != NULL) kfree(ca->slot_info); + if (ca->dvbdev != NULL) + dvb_unregister_device(ca->dvbdev); + if (ca->slot_info != NULL) + kfree(ca->slot_info); kfree(ca); } pubca->private = NULL; return ret; } +EXPORT_SYMBOL(dvb_ca_en50221_release); @@ -1610,7 +1759,8 @@ /* shutdown the thread if there was one */ if (ca->thread_pid) { if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) { - printk("dvb_ca_release adapter %d: thread PID %d already died\n", ca->dvbdev->adapter->num, ca->thread_pid); + printk("dvb_ca_release adapter %d: thread PID %d already died\n", + ca->dvbdev->adapter->num, ca->thread_pid); } else { ca->exit = 1; mb(); diff -Nru a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 2004-12-12 17:40:53 -08:00 @@ -42,6 +42,9 @@ /* Structure describing a CA interface */ struct dvb_ca_en50221 { + /* the module owning this structure */ + struct module* owner; + /* NOTE: the read_*, write_* and poll_slot_status functions must use locks as * they may be called from several threads at once */ @@ -62,7 +65,7 @@ * Poll slot status. * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set */ - int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot); + int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open); /* private data, used by caller */ void* data; diff -Nru a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c --- a/drivers/media/dvb/dvb-core/dvb_demux.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_demux.c 2004-12-12 17:40:52 -08:00 @@ -424,7 +424,7 @@ feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); } } - +EXPORT_SYMBOL(dvb_dmx_swfilter_packet); void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count) { @@ -439,6 +439,7 @@ spin_unlock(&demux->lock); } +EXPORT_SYMBOL(dvb_dmx_swfilter_packets); void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) @@ -478,6 +479,7 @@ bailout: spin_unlock(&demux->lock); } +EXPORT_SYMBOL(dvb_dmx_swfilter); void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) { @@ -522,6 +524,7 @@ bailout: spin_unlock(&demux->lock); } +EXPORT_SYMBOL(dvb_dmx_swfilter_204); static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux) @@ -1163,6 +1166,7 @@ up(&dvbdemux->mutex); return 0; } +EXPORT_SYMBOL(dvbdmx_connect_frontend); int dvbdmx_disconnect_frontend(struct dmx_demux *demux) @@ -1176,6 +1180,7 @@ up(&dvbdemux->mutex); return 0; } +EXPORT_SYMBOL(dvbdmx_disconnect_frontend); static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids) @@ -1256,6 +1261,7 @@ return 0; } +EXPORT_SYMBOL(dvb_dmx_init); int dvb_dmx_release(struct dvb_demux *dvbdemux) @@ -1269,3 +1275,5 @@ vfree(dvbdemux->feed); return 0; } +EXPORT_SYMBOL(dvb_dmx_release); + diff -Nru a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c --- a/drivers/media/dvb/dvb-core/dvb_filter.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_filter.c 2004-12-12 17:40:53 -08:00 @@ -3,19 +3,20 @@ #include #include "dvb_filter.h" -unsigned int bitrates[3][16] = +#if 0 +static unsigned int bitrates[3][16] = {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; +#endif -u32 freq[4] = {441, 480, 320, 0}; +static u32 freq[4] = {480, 441, 320, 0}; -unsigned int ac3_bitrates[32] = +static unsigned int ac3_bitrates[32] = {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, 0,0,0,0,0,0,0,0,0,0,0,0,0}; -u32 ac3_freq[4] = {480, 441, 320, 0}; -u32 ac3_frames[3][32] = +static u32 ac3_frames[3][32] = {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, @@ -389,6 +390,7 @@ return 0; } +EXPORT_SYMBOL(dvb_filter_get_ac3info); #if 0 @@ -563,6 +565,7 @@ p2ts->cb=cb; p2ts->priv=priv; } +EXPORT_SYMBOL(dvb_filter_pes2ts_init); int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, int len, int payload_start) @@ -597,4 +600,5 @@ memcpy(buf+5+rest, pes, len); return p2ts->cb(p2ts->priv, buf); } +EXPORT_SYMBOL(dvb_filter_pes2ts); diff -Nru a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c --- a/drivers/media/dvb/dvb-core/dvb_frontend.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c 2004-12-12 17:40:52 -08:00 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ static int dvb_override_frequency_bending; static int dvb_force_auto_inversion; static int dvb_override_tune_delay; +static int dvb_powerdown_on_sleep = 1; static int do_frequency_bending; module_param_named(frontend_debug, dvb_frontend_debug, int, 0644); @@ -57,6 +59,8 @@ MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always"); module_param(dvb_override_tune_delay, int, 0444); MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt"); +module_param(dvb_powerdown_on_sleep, int, 0444); +MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)"); #define dprintk if (dvb_frontend_debug) printk @@ -100,12 +104,10 @@ struct dvb_frontend_data { - struct dvb_frontend_info *info; - struct dvb_frontend frontend; + struct dvb_frontend *frontend; struct dvb_device *dvbdev; struct dvb_frontend_parameters parameters; struct dvb_fe_events events; - struct module *module; struct semaphore sem; struct list_head list_head; wait_queue_head_t wait_queue; @@ -126,53 +128,11 @@ fe_status_t status; }; - -struct dvb_frontend_ioctl_data { - struct list_head list_head; - struct dvb_adapter *adapter; - int (*before_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg); - int (*after_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg); - void *before_after_data; -}; - - -struct dvb_frontend_notifier_data { - struct list_head list_head; - struct dvb_adapter *adapter; - void (*callback) (fe_status_t s, void *data); - void *data; -}; - - static LIST_HEAD(frontend_list); -static LIST_HEAD(frontend_ioctl_list); -static LIST_HEAD(frontend_notifier_list); static DECLARE_MUTEX(frontend_mutex); -static int dvb_frontend_internal_ioctl (struct dvb_frontend *frontend, - unsigned int cmd, void *arg) -{ - int err = -EOPNOTSUPP; - - dprintk ("%s\n", __FUNCTION__); - - if (frontend->before_ioctl) - err = frontend->before_ioctl (frontend, cmd, arg); - - if (err == -EOPNOTSUPP) { - err = frontend->ioctl (frontend, cmd, arg); - - if ((err == -EOPNOTSUPP) && frontend->after_ioctl) - err = frontend->after_ioctl (frontend, cmd, arg); - } - - return err; -} - /** * if 2 tuners are located side by side you can get interferences when @@ -184,8 +144,8 @@ static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive) { struct list_head *entry; - int stepsize = this_fe->info->frequency_stepsize; - int this_fe_adap_num = this_fe->frontend.dvb_adapter->num; + int stepsize = this_fe->frontend->ops->info.frequency_stepsize; + int this_fe_adap_num = this_fe->frontend->dvb->num; int frequency; if (!stepsize || recursive > 10) { @@ -209,7 +169,7 @@ fe = list_entry (entry, struct dvb_frontend_data, list_head); - if (fe->frontend.dvb_adapter->num != this_fe_adap_num) + if (fe->frontend->dvb->num != this_fe_adap_num) continue; f = fe->parameters.frequency; @@ -237,25 +197,6 @@ up (&frontend_mutex); } - -static void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe, - fe_status_t s) -{ - dprintk ("%s\n", __FUNCTION__); - - if (((s ^ fe->status) & FE_HAS_LOCK) && (s & FE_HAS_LOCK)) - msleep (fe->info->notifier_delay); - - fe->status = s; - - /** - * now tell the Demux about the TS status changes... - */ - if (fe->frontend.notifier_callback) - fe->frontend.notifier_callback(fe->status, fe->frontend.notifier_data); -} - - static void dvb_frontend_add_event (struct dvb_frontend_data *fe, fe_status_t status) { struct dvb_fe_events *events = &fe->events; @@ -280,15 +221,13 @@ sizeof (struct dvb_frontend_parameters)); if (status & FE_HAS_LOCK) - dvb_frontend_internal_ioctl (&fe->frontend, - FE_GET_FRONTEND, - &e->parameters); + if (fe->frontend->ops->get_frontend) fe->frontend->ops->get_frontend(fe->frontend, &e->parameters); + events->eventw = wp; up (&events->sem); e->status = status; - dvb_call_frontend_notifiers (fe, status); wake_up_interruptible (&events->wait_queue); } @@ -339,13 +278,11 @@ static void dvb_frontend_init (struct dvb_frontend_data *fe) { - struct dvb_frontend *frontend = &fe->frontend; - dprintk ("DVB: initialising frontend %i (%s)...\n", - frontend->dvb_adapter->num, - fe->info->name); + fe->frontend->dvb->num, + fe->frontend->ops->info.name); - dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL); + if (fe->frontend->ops->init) fe->frontend->ops->init(fe->frontend); } static void update_delay (int *quality, int *delay, int min_delay, int locked) @@ -380,7 +317,7 @@ u32 original_frequency = fe->parameters.frequency; /* are we using autoinversion? */ - autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && + autoinversion = ((!(fe->frontend->ops->info.caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO)); /* setup parameters correctly */ @@ -453,7 +390,7 @@ /* set the frontend itself */ fe->parameters.frequency += fe->lnb_drift + fe->bending; if (autoinversion) fe->parameters.inversion = fe->inversion; - dvb_frontend_internal_ioctl (&fe->frontend, FE_SET_FRONTEND, &fe->parameters); + if (fe->frontend->ops->set_frontend) fe->frontend->ops->set_frontend(fe->frontend, &fe->parameters); fe->parameters.frequency = original_frequency; fe->parameters.inversion = original_inversion; @@ -489,6 +426,9 @@ wake_up_interruptible(&fe->wait_queue); } +/* + * FIXME: use linux/kthread.h + */ static int dvb_frontend_thread (void *data) { struct dvb_frontend_data *fe = (struct dvb_frontend_data *) data; @@ -501,14 +441,14 @@ dprintk ("%s\n", __FUNCTION__); snprintf (name, sizeof(name), "kdvb-fe-%i", - fe->frontend.dvb_adapter->num); + fe->frontend->dvb->num); lock_kernel (); daemonize (name); sigfillset (¤t->blocked); unlock_kernel (); - dvb_call_frontend_notifiers (fe, 0); + fe->status = 0; dvb_frontend_init (fe); fe->wakeup = 0; @@ -516,11 +456,14 @@ up (&fe->sem); /* is locked when we enter the thread... */ timeout = wait_event_interruptible_timeout(fe->wait_queue,0 != dvb_frontend_should_wakeup (fe), delay); - if (-ERESTARTSYS == timeout || 0 != dvb_frontend_is_exiting (fe)) { + if (0 != dvb_frontend_is_exiting (fe)) { /* got signal or quitting */ break; } + if (current->flags & PF_FREEZE) + refrigerator(PF_FREEZE); + if (down_interruptible (&fe->sem)) break; @@ -535,9 +478,10 @@ if (fe->state & FESTATE_RETUNE) { s = 0; } else { - dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s); + if (fe->frontend->ops->read_status) fe->frontend->ops->read_status(fe->frontend, &s); if (s != fe->status) { dvb_frontend_add_event (fe, s); + fe->status = s; } } /* if we're not tuned, and we have a lock, move to the TUNED state */ @@ -546,7 +490,7 @@ fe->state = FESTATE_TUNED; /* if we're tuned, then we have determined the correct inversion */ - if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && + if ((!(fe->frontend->ops->info.caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO)) { fe->parameters.inversion = fe->inversion; } @@ -572,7 +516,7 @@ /* don't actually do anything if we're in the LOSTLOCK state, * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ if ((fe->state & FESTATE_LOSTLOCK) && - (fe->info->caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) { + (fe->frontend->ops->info.caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) { update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); continue; } @@ -630,8 +574,11 @@ } }; - if (dvb_shutdown_timeout) - dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); + if (dvb_shutdown_timeout) { + if (dvb_powerdown_on_sleep) + if (fe->frontend->ops->set_voltage) fe->frontend->ops->set_voltage(fe->frontend, SEC_VOLTAGE_OFF); + if (fe->frontend->ops->sleep) fe->frontend->ops->sleep(fe->frontend); + } fe->thread_pid = 0; mb(); @@ -720,12 +667,11 @@ { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend_data *fe = dvbdev->priv; - struct dvb_frontend_tune_settings fetunesettings; - int err = 0; + int err = -EOPNOTSUPP; dprintk ("%s\n", __FUNCTION__); - if (!fe || !fe->frontend.ioctl || fe->exit) + if (!fe || fe->exit) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY && @@ -737,18 +683,103 @@ return -ERESTARTSYS; switch (cmd) { + case FE_GET_INFO: { + struct dvb_frontend_info* info = (struct dvb_frontend_info*) parg; + memcpy(info, &fe->frontend->ops->info, sizeof(struct dvb_frontend_info)); + + /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't + * do it, it is done for it. */ + info->caps |= FE_CAN_INVERSION_AUTO; + err = 0; + break; + } + + case FE_READ_STATUS: + if (fe->frontend->ops->read_status) + err = fe->frontend->ops->read_status(fe->frontend, (fe_status_t*) parg); + break; + + case FE_READ_BER: + if (fe->frontend->ops->read_ber) + err = fe->frontend->ops->read_ber(fe->frontend, (__u32*) parg); + break; + + case FE_READ_SIGNAL_STRENGTH: + if (fe->frontend->ops->read_signal_strength) + err = fe->frontend->ops->read_signal_strength(fe->frontend, (__u16*) parg); + break; + + case FE_READ_SNR: + if (fe->frontend->ops->read_snr) + err = fe->frontend->ops->read_snr(fe->frontend, (__u16*) parg); + break; + + case FE_READ_UNCORRECTED_BLOCKS: + if (fe->frontend->ops->read_ucblocks) + err = fe->frontend->ops->read_ucblocks(fe->frontend, (__u32*) parg); + break; + + + case FE_DISEQC_RESET_OVERLOAD: + if (fe->frontend->ops->diseqc_reset_overload) { + err = fe->frontend->ops->diseqc_reset_overload(fe->frontend); + fe->state = FESTATE_DISEQC; + fe->status = 0; + } + break; + case FE_DISEQC_SEND_MASTER_CMD: + if (fe->frontend->ops->diseqc_send_master_cmd) { + err = fe->frontend->ops->diseqc_send_master_cmd(fe->frontend, (struct dvb_diseqc_master_cmd*) parg); + fe->state = FESTATE_DISEQC; + fe->status = 0; + } + break; + case FE_DISEQC_SEND_BURST: + if (fe->frontend->ops->diseqc_send_burst) { + err = fe->frontend->ops->diseqc_send_burst(fe->frontend, (fe_sec_mini_cmd_t) parg); + fe->state = FESTATE_DISEQC; + fe->status = 0; + } + break; + case FE_SET_TONE: + if (fe->frontend->ops->set_tone) { + err = fe->frontend->ops->set_tone(fe->frontend, (fe_sec_tone_mode_t) parg); + fe->state = FESTATE_DISEQC; + fe->status = 0; + } + break; + case FE_SET_VOLTAGE: - if (fe->status) - dvb_call_frontend_notifiers (fe, 0); - dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg); + if (fe->frontend->ops->set_voltage) { + err = fe->frontend->ops->set_voltage(fe->frontend, (fe_sec_voltage_t) parg); fe->state = FESTATE_DISEQC; + fe->status = 0; + } break; - case FE_SET_FRONTEND: - fe->state = FESTATE_RETUNE; + case FE_DISHNETWORK_SEND_LEGACY_CMD: + if (fe->frontend->ops->dishnetwork_send_legacy_command) { + err = fe->frontend->ops->dishnetwork_send_legacy_command(fe->frontend, (unsigned int) parg); + fe->state = FESTATE_DISEQC; + fe->status = 0; + } + break; + + case FE_DISEQC_RECV_SLAVE_REPLY: + if (fe->frontend->ops->diseqc_recv_slave_reply) + err = fe->frontend->ops->diseqc_recv_slave_reply(fe->frontend, (struct dvb_diseqc_slave_reply*) parg); + break; + + case FE_ENABLE_HIGH_LNB_VOLTAGE: + if (fe->frontend->ops->enable_high_lnb_voltage); + err = fe->frontend->ops->enable_high_lnb_voltage(fe->frontend, (int) parg); + break; + + case FE_SET_FRONTEND: { + struct dvb_frontend_tune_settings fetunesettings; memcpy (&fe->parameters, parg, sizeof (struct dvb_frontend_parameters)); @@ -762,7 +793,7 @@ fe->parameters.inversion = INVERSION_AUTO; fetunesettings.parameters.inversion = INVERSION_AUTO; } - if (fe->info->type == FE_OFDM) { + if (fe->frontend->ops->info.type == FE_OFDM) { /* without hierachical coding code_rate_LP is irrelevant, * so we tolerate the otherwise invalid FEC_NONE setting */ if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE && @@ -771,14 +802,13 @@ } /* get frontend-specific tuning settings */ - if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS, - &fetunesettings) == 0) { + if (fe->frontend->ops->get_tune_settings && (fe->frontend->ops->get_tune_settings(fe->frontend, &fetunesettings) == 0)) { fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; fe->max_drift = fetunesettings.max_drift; fe->step_size = fetunesettings.step_size; } else { /* default values */ - switch(fe->info->type) { + switch(fe->frontend->ops->info.type) { case FE_QPSK: fe->min_delay = HZ/20; fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000; @@ -793,8 +823,8 @@ case FE_OFDM: fe->min_delay = HZ/20; - fe->step_size = fe->info->frequency_stepsize * 2; - fe->max_drift = (fe->info->frequency_stepsize * 2) + 1; + fe->step_size = fe->frontend->ops->info.frequency_stepsize * 2; + fe->max_drift = (fe->frontend->ops->info.frequency_stepsize * 2) + 1; break; case FE_ATSC: printk("dvb-core: FE_ATSC not handled yet.\n"); @@ -805,32 +835,27 @@ fe->min_delay = (dvb_override_tune_delay * HZ) / 1000; } + fe->state = FESTATE_RETUNE; dvb_frontend_wakeup(fe); dvb_frontend_add_event (fe, 0); + fe->status = 0; + err = 0; break; + } case FE_GET_EVENT: err = dvb_frontend_get_event (fe, parg, file->f_flags); break; + case FE_GET_FRONTEND: - memcpy (parg, &fe->parameters, - sizeof (struct dvb_frontend_parameters)); - /* fall-through... */ - default: - err = dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg); + if (fe->frontend->ops->get_frontend) { + memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters)); + err = fe->frontend->ops->get_frontend(fe->frontend, (struct dvb_frontend_parameters*) parg); + } + break; }; up (&fe->sem); - if (err < 0) - return err; - - /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't - * do it, it is done for it. */ - if ((cmd == FE_GET_INFO) && (err == 0)) { - struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg; - tmp->caps |= FE_CAN_INVERSION_AUTO; - } - return err; } @@ -871,11 +896,6 @@ fe->events.eventr = fe->events.eventw = 0; } - if (!ret && fe->module) { - if (!try_module_get(fe->module)) - return -EINVAL; - } - return ret; } @@ -884,206 +904,13 @@ { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend_data *fe = dvbdev->priv; - int ret = 0; dprintk ("%s\n", __FUNCTION__); if ((file->f_flags & O_ACCMODE) != O_RDONLY) fe->release_jiffies = jiffies; - ret = dvb_generic_release (inode, file); - - if (!ret && fe->module) - module_put(fe->module); - - return ret; -} - - - -int -dvb_add_frontend_ioctls (struct dvb_adapter *adapter, - int (*before_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - int (*after_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - void *before_after_data) -{ - struct dvb_frontend_ioctl_data *ioctl; - struct list_head *entry; - - dprintk ("%s\n", __FUNCTION__); - - if (down_interruptible (&frontend_mutex)) - return -ERESTARTSYS; - - ioctl = kmalloc (sizeof(struct dvb_frontend_ioctl_data), GFP_KERNEL); - - if (!ioctl) { - up (&frontend_mutex); - return -ENOMEM; - } - - ioctl->adapter = adapter; - ioctl->before_ioctl = before_ioctl; - ioctl->after_ioctl = after_ioctl; - ioctl->before_after_data = before_after_data; - - list_add_tail (&ioctl->list_head, &frontend_ioctl_list); - - list_for_each (entry, &frontend_list) { - struct dvb_frontend_data *fe; - - fe = list_entry (entry, struct dvb_frontend_data, list_head); - - if (fe->frontend.dvb_adapter == adapter && - fe->frontend.before_ioctl == NULL && - fe->frontend.after_ioctl == NULL) - { - fe->frontend.before_ioctl = before_ioctl; - fe->frontend.after_ioctl = after_ioctl; - fe->frontend.before_after_data = before_after_data; - } - } - - up (&frontend_mutex); - - return 0; -} - - -void -dvb_remove_frontend_ioctls (struct dvb_adapter *adapter, - int (*before_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - int (*after_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg)) -{ - struct list_head *entry, *n; - - dprintk ("%s\n", __FUNCTION__); - - down (&frontend_mutex); - - list_for_each (entry, &frontend_list) { - struct dvb_frontend_data *fe; - - fe = list_entry (entry, struct dvb_frontend_data, list_head); - - if (fe->frontend.dvb_adapter == adapter && - fe->frontend.before_ioctl == before_ioctl && - fe->frontend.after_ioctl == after_ioctl) - { - fe->frontend.before_ioctl = NULL; - fe->frontend.after_ioctl = NULL; - - } - } - - list_for_each_safe (entry, n, &frontend_ioctl_list) { - struct dvb_frontend_ioctl_data *ioctl; - - ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head); - - if (ioctl->adapter == adapter && - ioctl->before_ioctl == before_ioctl && - ioctl->after_ioctl == after_ioctl) - { - list_del (&ioctl->list_head); - kfree (ioctl); - - break; - } - } - - up (&frontend_mutex); -} - - -int -dvb_add_frontend_notifier (struct dvb_adapter *adapter, - void (*callback) (fe_status_t s, void *data), - void *data) -{ - struct dvb_frontend_notifier_data *notifier; - struct list_head *entry; - - dprintk ("%s\n", __FUNCTION__); - - if (down_interruptible (&frontend_mutex)) - return -ERESTARTSYS; - - notifier = kmalloc (sizeof(struct dvb_frontend_notifier_data), GFP_KERNEL); - - if (!notifier) { - up (&frontend_mutex); - return -ENOMEM; - } - - notifier->adapter = adapter; - notifier->callback = callback; - notifier->data = data; - - list_add_tail (¬ifier->list_head, &frontend_notifier_list); - - list_for_each (entry, &frontend_list) { - struct dvb_frontend_data *fe; - - fe = list_entry (entry, struct dvb_frontend_data, list_head); - - if (fe->frontend.dvb_adapter == adapter && - fe->frontend.notifier_callback == NULL) - { - fe->frontend.notifier_callback = callback; - fe->frontend.notifier_data = data; - } - } - - up (&frontend_mutex); - - return 0; -} - - -void -dvb_remove_frontend_notifier (struct dvb_adapter *adapter, - void (*callback) (fe_status_t s, void *data)) -{ - struct list_head *entry, *n; - - dprintk ("%s\n", __FUNCTION__); - - down (&frontend_mutex); - - list_for_each (entry, &frontend_list) { - struct dvb_frontend_data *fe; - - fe = list_entry (entry, struct dvb_frontend_data, list_head); - - if (fe->frontend.dvb_adapter == adapter && - fe->frontend.notifier_callback == callback) - { - fe->frontend.notifier_callback = NULL; - - } - } - - list_for_each_safe (entry, n, &frontend_notifier_list) { - struct dvb_frontend_notifier_data *notifier; - - notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head); - - if (notifier->adapter == adapter && - notifier->callback == callback) - { - list_del (¬ifier->list_head); - kfree (notifier); - - break; - } - } - - up (&frontend_mutex); + return dvb_generic_release (inode, file); } @@ -1096,16 +923,9 @@ }; - -int -dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - struct dvb_adapter *dvb_adapter, - void *data, - struct dvb_frontend_info *info, - struct module *module) +int dvb_register_frontend(struct dvb_adapter* dvb, + struct dvb_frontend* frontend) { - struct list_head *entry; struct dvb_frontend_data *fe; static const struct dvb_device dvbdev_template = { .users = ~0, @@ -1133,63 +953,30 @@ init_MUTEX (&fe->events.sem); fe->events.eventw = fe->events.eventr = 0; fe->events.overflow = 0; - fe->module = module; - fe->frontend.ioctl = ioctl; - fe->frontend.dvb_adapter = dvb_adapter; - fe->frontend.data = data; - fe->info = info; - fe->inversion = INVERSION_OFF; + fe->frontend = frontend; + fe->frontend->dvb = dvb; - list_for_each (entry, &frontend_ioctl_list) { - struct dvb_frontend_ioctl_data *ioctl; - - ioctl = list_entry (entry, - struct dvb_frontend_ioctl_data, - list_head); - - if (ioctl->adapter == dvb_adapter) { - fe->frontend.before_ioctl = ioctl->before_ioctl; - fe->frontend.after_ioctl = ioctl->after_ioctl; - fe->frontend.before_after_data = ioctl->before_after_data; - break; - } - } - - list_for_each (entry, &frontend_notifier_list) { - struct dvb_frontend_notifier_data *notifier; - - notifier = list_entry (entry, - struct dvb_frontend_notifier_data, - list_head); - - if (notifier->adapter == dvb_adapter) { - fe->frontend.notifier_callback = notifier->callback; - fe->frontend.notifier_data = notifier->data; - break; - } - } + fe->inversion = INVERSION_OFF; list_add_tail (&fe->list_head, &frontend_list); printk ("DVB: registering frontend %i (%s)...\n", - fe->frontend.dvb_adapter->num, - fe->info->name); + fe->frontend->dvb->num, + fe->frontend->ops->info.name); - dvb_register_device (dvb_adapter, &fe->dvbdev, &dvbdev_template, + dvb_register_device (fe->frontend->dvb, &fe->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND); - if ((info->caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2)) + if ((fe->frontend->ops->info.caps & FE_NEEDS_BENDING) || (dvb_override_frequency_bending == 2)) do_frequency_bending = 1; up (&frontend_mutex); - return 0; } +EXPORT_SYMBOL(dvb_register_frontend); -int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - struct dvb_adapter *dvb_adapter) +int dvb_unregister_frontend (struct dvb_frontend* frontend) { struct list_head *entry, *n; @@ -1202,11 +989,16 @@ fe = list_entry (entry, struct dvb_frontend_data, list_head); - if (fe->frontend.ioctl == ioctl && fe->frontend.dvb_adapter == dvb_adapter) { + if (fe->frontend == frontend) { dvb_unregister_device (fe->dvbdev); list_del (entry); up (&frontend_mutex); dvb_frontend_stop (fe); + if (fe->frontend->ops->release) { + fe->frontend->ops->release(fe->frontend); + } else { + printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->frontend->ops->info.name); + } kfree (fe); return 0; } @@ -1215,4 +1007,4 @@ up (&frontend_mutex); return -EINVAL; } - +EXPORT_SYMBOL(dvb_unregister_frontend); diff -Nru a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h --- a/drivers/media/dvb/dvb-core/dvb_frontend.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h 2004-12-12 17:40:53 -08:00 @@ -1,9 +1,12 @@ /* * dvb_frontend.h * - * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH - * overhauled by Holger Waechtler for Convergence GmbH + * Copyright (C) 2001 convergence integrated media GmbH + * Copyright (C) 2004 convergence GmbH * + * Written by Ralph Metzler + * Overhauled by Holger Waechtler + * Kernel I2C stuff by Michael Hunold * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -38,8 +41,8 @@ #include "dvbdev.h" /* FIXME: Move to i2c-id.h */ -#define I2C_DRIVERID_DVBFE_ALPS_TDLB7 I2C_DRIVERID_EXP2 -#define I2C_DRIVERID_DVBFE_ALPS_TDMB7 I2C_DRIVERID_EXP2 +#define I2C_DRIVERID_DVBFE_SP8870 I2C_DRIVERID_EXP2 +#define I2C_DRIVERID_DVBFE_CX22700 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2 @@ -56,22 +59,8 @@ #define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2 #define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2 +#define I2C_DRIVERID_DVBFE_TDA80XX I2C_DRIVERID_EXP2 -/** - * when before_ioctl is registered and returns value 0, ioctl and after_ioctl - * are not executed. - */ - -struct dvb_frontend { - int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg); - int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg); - int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg); - void (*notifier_callback) (fe_status_t s, void *data); - struct dvb_adapter *dvb_adapter; - void *before_after_data; /* can be used by hardware module... */ - void *notifier_data; /* can be used by hardware module... */ - void *data; /* can be used by hardware module... */ -}; struct dvb_frontend_tune_settings { int min_delay_ms; @@ -80,67 +69,47 @@ struct dvb_frontend_parameters parameters; }; +struct dvb_frontend; -/** - * private frontend command ioctl's. - * keep them in sync with the public ones defined in linux/dvb/frontend.h - * - * FE_SLEEP. Ioctl used to put frontend into a low power mode. - * FE_INIT. Ioctl used to initialise the frontend. - * FE_GET_TUNE_SETTINGS. Get the frontend-specific tuning loop settings for the supplied set of parameters. - */ -#define FE_SLEEP _IO('v', 80) -#define FE_INIT _IO('v', 81) -#define FE_GET_TUNE_SETTINGS _IOWR('v', 83, struct dvb_frontend_tune_settings) -#define FE_REGISTER _IO ('v', 84) -#define FE_UNREGISTER _IO ('v', 85) - -extern int -dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - struct dvb_adapter *dvb_adapter, - void *data, - struct dvb_frontend_info *info, - struct module *module); - -extern int -dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - struct dvb_adapter *dvb_adapter); - - -/** - * Add special ioctl code performed before and after the main ioctl - * to all frontend devices on the specified DVB adapter. - * This is necessairy because the 22kHz/13V-18V/DiSEqC stuff depends - * heavily on the hardware around the frontend, the same tuner can create - * these signals on about a million different ways... - * - * Return value: number of frontends where the ioctl's were applied. - */ -extern int -dvb_add_frontend_ioctls (struct dvb_adapter *adapter, - int (*before_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - int (*after_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - void *before_after_data); - - -extern void -dvb_remove_frontend_ioctls (struct dvb_adapter *adapter, - int (*before_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg), - int (*after_ioctl) (struct dvb_frontend *frontend, - unsigned int cmd, void *arg)); - -extern int -dvb_add_frontend_notifier (struct dvb_adapter *adapter, - void (*callback) (fe_status_t s, void *data), - void *data); -extern void -dvb_remove_frontend_notifier (struct dvb_adapter *adapter, - void (*callback) (fe_status_t s, void *data)); +struct dvb_frontend_ops { -#endif + struct dvb_frontend_info info; + + void (*release)(struct dvb_frontend* fe); + int (*init)(struct dvb_frontend* fe); + int (*sleep)(struct dvb_frontend* fe); + + int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); + + int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); + int (*read_ber)(struct dvb_frontend* fe, u32* ber); + int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); + int (*read_snr)(struct dvb_frontend* fe, u16* snr); + int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks); + + int (*diseqc_reset_overload)(struct dvb_frontend* fe); + int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); + int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply); + int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); + int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); + int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg); + int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); +}; + +struct dvb_frontend { + + struct dvb_frontend_ops* ops; + struct dvb_adapter *dvb; + void* demodulator_priv; +}; + +extern int dvb_register_frontend(struct dvb_adapter* dvb, + struct dvb_frontend* fe); + +extern int dvb_unregister_frontend(struct dvb_frontend* fe); + +#endif diff -Nru a/drivers/media/dvb/dvb-core/dvb_ksyms.c b/drivers/media/dvb/dvb-core/dvb_ksyms.c --- a/drivers/media/dvb/dvb-core/dvb_ksyms.c 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,52 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvb_filter.h" -#include "dvb_ca_en50221.h" - -EXPORT_SYMBOL(dvb_dmxdev_init); -EXPORT_SYMBOL(dvb_dmxdev_release); -EXPORT_SYMBOL(dvb_dmx_init); -EXPORT_SYMBOL(dvb_dmx_release); -EXPORT_SYMBOL(dvb_dmx_swfilter_packet); -EXPORT_SYMBOL(dvb_dmx_swfilter_packets); -EXPORT_SYMBOL(dvb_dmx_swfilter); -EXPORT_SYMBOL(dvb_dmx_swfilter_204); -EXPORT_SYMBOL(dvbdmx_connect_frontend); -EXPORT_SYMBOL(dvbdmx_disconnect_frontend); - -EXPORT_SYMBOL(dvb_register_frontend); -EXPORT_SYMBOL(dvb_unregister_frontend); -EXPORT_SYMBOL(dvb_add_frontend_ioctls); -EXPORT_SYMBOL(dvb_remove_frontend_ioctls); -EXPORT_SYMBOL(dvb_add_frontend_notifier); -EXPORT_SYMBOL(dvb_remove_frontend_notifier); - -EXPORT_SYMBOL(dvb_net_init); -EXPORT_SYMBOL(dvb_net_release); - -EXPORT_SYMBOL(dvb_register_adapter); -EXPORT_SYMBOL(dvb_unregister_adapter); -EXPORT_SYMBOL(dvb_register_device); -EXPORT_SYMBOL(dvb_unregister_device); -EXPORT_SYMBOL(dvb_generic_ioctl); -EXPORT_SYMBOL(dvb_generic_open); -EXPORT_SYMBOL(dvb_generic_release); - -EXPORT_SYMBOL(dvb_filter_pes2ts_init); -EXPORT_SYMBOL(dvb_filter_pes2ts); -EXPORT_SYMBOL(dvb_filter_get_ac3info); - -EXPORT_SYMBOL(dvb_ca_en50221_init); -EXPORT_SYMBOL(dvb_ca_en50221_release); -EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); -EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); -EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); diff -Nru a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c --- a/drivers/media/dvb/dvb-core/dvb_net.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_net.c 2004-12-12 17:40:52 -08:00 @@ -30,6 +30,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ +#include #include #include #include @@ -141,7 +142,11 @@ skb->mac.raw=skb->data; skb_pull(skb,dev->hard_header_len); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,8) + eth = skb->mac.ethernet; +#else eth = eth_hdr(skb); +#endif if (*eth->h_dest & 1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) @@ -1193,6 +1198,7 @@ dvb_net_remove_if(dvbnet, i); } } +EXPORT_SYMBOL(dvb_net_release); int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, @@ -1210,4 +1216,4 @@ return 0; } - +EXPORT_SYMBOL(dvb_net_init); diff -Nru a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c --- a/drivers/media/dvb/dvb-core/dvbdev.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dvb-core/dvbdev.c 2004-12-12 17:40:52 -08:00 @@ -132,6 +132,7 @@ dvbdev->users--; return 0; } +EXPORT_SYMBOL(dvb_generic_open); int dvb_generic_release(struct inode *inode, struct file *file) @@ -150,6 +151,7 @@ dvbdev->users++; return 0; } +EXPORT_SYMBOL(dvb_generic_release); int dvb_generic_ioctl(struct inode *inode, struct file *file, @@ -165,6 +167,7 @@ return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); } +EXPORT_SYMBOL(dvb_generic_ioctl); static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) @@ -235,6 +238,7 @@ return 0; } +EXPORT_SYMBOL(dvb_register_device); void dvb_unregister_device(struct dvb_device *dvbdev) @@ -251,6 +255,7 @@ list_del(&dvbdev->list_head); kfree(dvbdev); } +EXPORT_SYMBOL(dvb_unregister_device); static int dvbdev_get_free_adapter_num (void) @@ -309,6 +314,7 @@ return num; } +EXPORT_SYMBOL(dvb_register_adapter); int dvb_unregister_adapter(struct dvb_adapter *adap) @@ -322,6 +328,7 @@ kfree (adap); return 0; } +EXPORT_SYMBOL(dvb_unregister_adapter); /* if the miracle happens and "generic_usercopy()" is included into the kernel, then this can vanish. please don't make the mistake and diff -Nru a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h --- a/drivers/media/dvb/dvb-core/dvbdev.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/dvb-core/dvbdev.h 2004-12-12 17:40:52 -08:00 @@ -49,6 +49,7 @@ struct list_head device_list; const char *name; u8 proposed_mac [6]; + void* priv; struct module *module; }; diff -Nru a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig --- a/drivers/media/dvb/frontends/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/Kconfig 2004-12-12 17:40:52 -08:00 @@ -1,3 +1,6 @@ +menu "Customise DVB Frontends" + depends on DVB_CORE + comment "DVB-S (satellite) frontends" depends on DVB_CORE @@ -7,32 +10,23 @@ help A DVB-S tuner module. Say Y when you want to support this frontend. - Some examples are the Alps BSRU6, the Philips SU1278 and - the LG TDQB-S00x. - - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_CX24110 - tristate "Connexant CX24110 based" + tristate "Conexant CX24110 based" depends on DVB_CORE help A DVB-S tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - -config DVB_GRUNDIG_29504_491 - tristate "Grundig 29504-491 based" +config DVB_TDA8083 + tristate "Philips TDA8083 based" depends on DVB_CORE help A DVB-S tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. +config DVB_TDA80XX + tristate "Philips TDA8044 or TDA8083 based" + depends on DVB_CORE + help + A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_MT312 tristate "Zarlink MT312 based" @@ -40,81 +34,53 @@ help A DVB-S tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_VES1X93 tristate "VLSI VES1893 or VES1993 based" depends on DVB_CORE help A DVB-S tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - comment "DVB-T (terrestrial) frontends" depends on DVB_CORE -config DVB_SP887X - tristate "Microtune sp887x based (i.e. Microtune DTF7072)" +config DVB_SP8870 + tristate "Spase sp8870 based" depends on DVB_CORE help A DVB-T tuner module. Say Y when you want to support this frontend. This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware sp887x" to + "/Documentation/dvb/get_dvb_firmware sp8870" to download/extract it, and then copy it to /usr/lib/hotplug/firmware. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - -config DVB_ALPS_TDLB7 - tristate "Alps TDLB7 based" +config DVB_SP887X + tristate "Spase sp887x based" depends on DVB_CORE help A DVB-T tuner module. Say Y when you want to support this frontend. This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware alps_tdlb7" to + "/Documentation/dvb/get_dvb_firmware sp887x" to download/extract it, and then copy it to /usr/lib/hotplug/firmware. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - -config DVB_ALPS_TDMB7 - tristate "Alps TDMB7 based" +config DVB_CX22700 + tristate "Conexant CX22700 based" depends on DVB_CORE help A DVB-T tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_CX22702 tristate "Conexant cx22702 demodulator (OFDM)" depends on DVB_CORE help A DVB-T tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - -config DVB_GRUNDIG_29504_401 - tristate "Grundig 29504-401 based" +config DVB_L64781 + tristate "LSI L64781" depends on DVB_CORE help A DVB-T tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_TDA1004X tristate "Philips TDA10045H/TDA10046H based" depends on DVB_CORE @@ -126,30 +92,18 @@ "/Documentation/dvb/get_dvb_firmware tda10046" to download/extract them, and then copy them to /usr/lib/hotplug/firmware. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_NXT6000 tristate "NxtWave Communications NXT6000 based" depends on DVB_CORE help A DVB-T tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_MT352 tristate "Zarlink MT352 based" depends on DVB_CORE help A DVB-T tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_DIB3000MB tristate "DiBcom 3000-MB" depends on DVB_CORE @@ -157,14 +111,6 @@ A DVB-T tuner module. Designed for mobile usage. Say Y when you want to support this frontend. - Used on USB-powered devices. You should also say Y to DVB_DIBUSB - (DiBcom USB DVB-T Adapter) to support the actual device, - this is "only" the frontend/tuner. - - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - comment "DVB-C (cable) frontends" depends on DVB_CORE @@ -174,27 +120,22 @@ help A DVB-C tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - config DVB_VES1820 tristate "VLSI VES1820 based" depends on DVB_CORE help A DVB-C tuner module. Say Y when you want to support this frontend. - If you don't know what tuner module is soldered on your - DVB adapter simply enable all supported frontends, the - right one will get autodetected. - -comment "Misc. Frontend Modules" +config DVB_TDA10021 + tristate "Philips TDA10021 based" depends on DVB_CORE + help + A DVB-C tuner module. Say Y when you want to support this frontend. -config DVB_TWINHAN_DST - tristate "Twinhan DST based DVB-S/-T frontend" - depends on DVB_CORE && DVB_BT8XX +config DVB_STV0297 + tristate "ST STV0297 based" + depends on DVB_CORE help - Used in such cards as the VP-1020/1030, Twinhan DST, - VVmer TV@SAT. Say Y when you want to support frontends - using this asic. + A DVB-C tuner module. Say Y when you want to support this frontend. + +endmenu diff -Nru a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile --- a/drivers/media/dvb/frontends/Makefile 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/Makefile 2004-12-12 17:40:52 -08:00 @@ -4,14 +4,13 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -obj-$(CONFIG_DVB_TWINHAN_DST) += dst.o obj-$(CONFIG_DVB_STV0299) += stv0299.o -obj-$(CONFIG_DVB_ALPS_TDLB7) += alps_tdlb7.o -obj-$(CONFIG_DVB_ALPS_TDMB7) += alps_tdmb7.o +obj-$(CONFIG_DVB_SP8870) += sp8870.o +obj-$(CONFIG_DVB_CX22700) += cx22700.o obj-$(CONFIG_DVB_ATMEL_AT76C651) += at76c651.o obj-$(CONFIG_DVB_CX24110) += cx24110.o -obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o -obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o +obj-$(CONFIG_DVB_TDA8083) += tda8083.o +obj-$(CONFIG_DVB_L64781) += l64781.o obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o obj-$(CONFIG_DVB_MT312) += mt312.o obj-$(CONFIG_DVB_VES1820) += ves1820.o @@ -21,4 +20,6 @@ obj-$(CONFIG_DVB_NXT6000) += nxt6000.o obj-$(CONFIG_DVB_MT352) += mt352.o obj-$(CONFIG_DVB_CX22702) += cx22702.o - +obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o +obj-$(CONFIG_DVB_TDA10021) += tda10021.o +obj-$(CONFIG_DVB_STV0297) += stv0297.o diff -Nru a/drivers/media/dvb/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c --- a/drivers/media/dvb/frontends/alps_tdlb7.c 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,746 +0,0 @@ -/* - Driver for Alps TDLB7 Frontend - - Copyright (C) 1999 Juergen Peitz - - 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. - -*/ -/* - * This driver needs external firmware. Please use the command - * "/Documentation/dvb/get_dvb_firmware alps_tdlb7" to - * download/extract it, and then copy it to /usr/lib/hotplug/firmware. - */ -#define SP887X_DEFAULT_FIRMWARE "dvb-fe-tdlb7-2.16.fw" - -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" - -#define FRONTEND_NAME "dvbfe_alps_tdlb7" - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - - -/* firmware size for sp8870 */ -#define SP8870_FIRMWARE_SIZE 16382 - -/* starting point for firmware in file 'Sc_main.mc' */ -#define SP8870_FIRMWARE_OFFSET 0x0A - -static struct dvb_frontend_info tdlb7_info = { - .name = "Alps TDLB7", - .type = FE_OFDM, - .frequency_min = 470000000, - .frequency_max = 860000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | - FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER -}; - -struct tdlb7_state { - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - -static int sp8870_writereg (struct i2c_adapter *i2c, u16 reg, u16 data) -{ - u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; - struct i2c_msg msg = { .addr = 0x71, .flags = 0, .buf = buf, .len = 4 }; - int err; - - if ((err = i2c_transfer (i2c, &msg, 1)) != 1) { - dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); - return -EREMOTEIO; - } - - return 0; -} - -static u16 sp8870_readreg (struct i2c_adapter *i2c, u16 reg) -{ - int ret; - u8 b0 [] = { reg >> 8 , reg & 0xff }; - u8 b1 [] = { 0, 0 }; - struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 }, - { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; - - ret = i2c_transfer (i2c, msg, 2); - - if (ret != 2) { - dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - return -1; - } - - return (b1[0] << 8 | b1[1]); -} - -static int sp5659_write (struct i2c_adapter *i2c, u8 data [4]) -{ - int ret; - - u8 buf_open [] = { 0x206 >> 8, 0x206 & 0xff, 0x001 >> 8, 0x001 & 0xff }; - u8 buf_close [] = { 0x206 >> 8, 0x206 & 0xff, 0x000 >> 8, 0x000 & 0xff }; - - struct i2c_msg msg[3] = { {.addr = 0x71, .flags = 0, .buf = buf_open, .len = 4 }, - {.addr = 0x60, .flags = 0, .buf = data, .len = 4 }, - {.addr = 0x71, .flags = 0, .buf = buf_close, .len = 4 } }; - - ret = i2c_transfer (i2c, &msg[0], 3); - - if (ret != 3) - printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); - - return (ret != 3) ? -EREMOTEIO : 0; -} - -static void sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ - u32 div = (freq + 36200000) / 166666; - u8 buf [4]; - int pwr; - - if (freq <= 782000000) - pwr = 1; - else - pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x85; - buf[3] = pwr << 6; - - /* open i2c gate for PLL message transmission... */ - sp5659_write (i2c, buf); -} - -static int sp8870_firmware_upload (struct i2c_adapter *i2c, const struct firmware *fw) -{ - struct i2c_msg msg; - char *fw_buf = fw->data; - int fw_pos; - u8 tx_buf[255]; - int tx_len; - int err = 0; - - dprintk ("%s: ...\n", __FUNCTION__); - - if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET) - return -EINVAL; - - // system controller stop - sp8870_writereg(i2c, 0x0F00, 0x0000); - - // instruction RAM register hiword - sp8870_writereg(i2c, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF)); - - // instruction RAM MWR - sp8870_writereg(i2c, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16)); - - // do firmware upload - fw_pos = SP8870_FIRMWARE_OFFSET; - while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){ - tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos; - // write register 0xCF0A - tx_buf[0] = 0xCF; - tx_buf[1] = 0x0A; - memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len); - msg.addr = 0x71; - msg.flags = 0; - msg.buf = tx_buf; - msg.len = tx_len + 2; - if ((err = i2c_transfer (i2c, &msg, 1)) != 1) { - printk("%s: firmware upload failed!\n", __FUNCTION__); - printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err); - return err; - } - fw_pos += tx_len; - } - - dprintk ("%s: done!\n", __FUNCTION__); - return 0; -}; - -static void sp8870_microcontroller_stop (struct i2c_adapter *i2c) -{ - sp8870_writereg(i2c, 0x0F08, 0x000); - sp8870_writereg(i2c, 0x0F09, 0x000); - - // microcontroller STOP - sp8870_writereg(i2c, 0x0F00, 0x000); -} - -static void sp8870_microcontroller_start (struct i2c_adapter *i2c) -{ - sp8870_writereg(i2c, 0x0F08, 0x000); - sp8870_writereg(i2c, 0x0F09, 0x000); - - // microcontroller START - sp8870_writereg(i2c, 0x0F00, 0x001); - // not documented but if we don't read 0x0D01 out here - // we don't get a correct data valid signal - sp8870_readreg(i2c, 0x0D01); -} - -static int sp8870_init (struct i2c_adapter *i2c) -{ - dprintk ("%s\n", __FUNCTION__); - - /* enable TS output and interface pins */ - sp8870_writereg(i2c, 0xc18, 0x00d); - - // system controller stop - sp8870_microcontroller_stop(i2c); - - // ADC mode - sp8870_writereg(i2c, 0x0301, 0x0003); - - // Reed Solomon parity bytes passed to output - sp8870_writereg(i2c, 0x0C13, 0x0001); - - // MPEG clock is suppressed if no valid data - sp8870_writereg(i2c, 0x0C14, 0x0001); - - /* bit 0x010: enable data valid signal */ - sp8870_writereg(i2c, 0x0D00, 0x010); - sp8870_writereg(i2c, 0x0D01, 0x000); - - return 0; -} - -static int sp8870_read_status (struct i2c_adapter *i2c, fe_status_t * fe_status) -{ - int status; - int signal; - - *fe_status = 0; - - status = sp8870_readreg (i2c, 0x0200); - if (status < 0) - return -EIO; - - signal = sp8870_readreg (i2c, 0x0303); - if (signal < 0) - return -EIO; - - if (signal > 0x0F) - *fe_status |= FE_HAS_SIGNAL; - if (status & 0x08) - *fe_status |= FE_HAS_SYNC; - if (status & 0x04) - *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI; - - return 0; -} - -static int sp8870_read_ber (struct i2c_adapter *i2c, u32 * ber) -{ - int ret; - u32 tmp; - - *ber = 0; - - ret = sp8870_readreg(i2c, 0xC08); - if (ret < 0) - return -EIO; - - tmp = ret & 0x3F; - - ret = sp8870_readreg(i2c, 0xC07); - if (ret < 0) - return -EIO; - - tmp = ret << 6; - - if (tmp >= 0x3FFF0) - tmp = ~0; - - *ber = tmp; - - return 0; -} - -static int sp8870_read_signal_strength (struct i2c_adapter *i2c, u16 * signal) -{ - int ret; - u16 tmp; - - *signal = 0; - - ret = sp8870_readreg (i2c, 0x306); - if (ret < 0) - return -EIO; - - tmp = ret << 8; - - ret = sp8870_readreg (i2c, 0x303); - if (ret < 0) - return -EIO; - - tmp |= ret; - - if (tmp) - *signal = 0xFFFF - tmp; - - return 0; -} - -static int sp8870_read_snr(struct i2c_adapter *i2c, u32* snr) -{ - *snr = 0; - return -EOPNOTSUPP; -} - -static int sp8870_read_uncorrected_blocks (struct i2c_adapter *i2c, u32* ublocks) -{ - int ret; - - *ublocks = 0; - - ret = sp8870_readreg(i2c, 0xC0C); - if (ret < 0) - return -EIO; - - if (ret == 0xFFFF) - ret = ~0; - - *ublocks = ret; - - return 0; -} - -static int sp8870_read_data_valid_signal(struct i2c_adapter *i2c) -{ - return (sp8870_readreg(i2c, 0x0D02) > 0); -} - -static -int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) -{ - int known_parameters = 1; - - *reg0xc05 = 0x000; - - switch (p->u.ofdm.constellation) { - case QPSK: - break; - case QAM_16: - *reg0xc05 |= (1 << 10); - break; - case QAM_64: - *reg0xc05 |= (2 << 10); - break; - case QAM_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - switch (p->u.ofdm.hierarchy_information) { - case HIERARCHY_NONE: - break; - case HIERARCHY_1: - *reg0xc05 |= (1 << 7); - break; - case HIERARCHY_2: - *reg0xc05 |= (2 << 7); - break; - case HIERARCHY_4: - *reg0xc05 |= (3 << 7); - break; - case HIERARCHY_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - switch (p->u.ofdm.code_rate_HP) { - case FEC_1_2: - break; - case FEC_2_3: - *reg0xc05 |= (1 << 3); - break; - case FEC_3_4: - *reg0xc05 |= (2 << 3); - break; - case FEC_5_6: - *reg0xc05 |= (3 << 3); - break; - case FEC_7_8: - *reg0xc05 |= (4 << 3); - break; - case FEC_AUTO: - known_parameters = 0; - break; - default: - return -EINVAL; - }; - - if (known_parameters) - *reg0xc05 |= (2 << 1); /* use specified parameters */ - else - *reg0xc05 |= (1 << 1); /* enable autoprobing */ - - return 0; -} - -static int sp8870_set_frontend_parameters (struct i2c_adapter *i2c, - struct dvb_frontend_parameters *p) -{ - int err; - u16 reg0xc05; - - if ((err = configure_reg0xc05(p, ®0xc05))) - return err; - - // system controller stop - sp8870_microcontroller_stop(i2c); - - // set tuner parameters - sp5659_set_tv_freq (i2c, p->frequency); - - // sample rate correction bit [23..17] - sp8870_writereg(i2c, 0x0319, 0x000A); - - // sample rate correction bit [16..0] - sp8870_writereg(i2c, 0x031A, 0x0AAB); - - // integer carrier offset - sp8870_writereg(i2c, 0x0309, 0x0400); - - // fractional carrier offset - sp8870_writereg(i2c, 0x030A, 0x0000); - - // filter for 6/7/8 Mhz channel - if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) - sp8870_writereg(i2c, 0x0311, 0x0002); - else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) - sp8870_writereg(i2c, 0x0311, 0x0001); - else - sp8870_writereg(i2c, 0x0311, 0x0000); - - // scan order: 2k first = 0x0000, 8k first = 0x0001 - if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) - sp8870_writereg(i2c, 0x0338, 0x0000); - else - sp8870_writereg(i2c, 0x0338, 0x0001); - - sp8870_writereg(i2c, 0xc05, reg0xc05); - - // read status reg in order to clear pending irqs - sp8870_readreg(i2c, 0x200); - - // system controller start - sp8870_microcontroller_start(i2c); - - return 0; -} - -// number of trials to recover from lockup -#define MAXTRIALS 5 -// maximum checks for data valid signal -#define MAXCHECKS 100 - -// only for debugging: counter for detected lockups -static int lockups = 0; -// only for debugging: counter for channel switches -static int switches = 0; - -static int sp8870_set_frontend (struct i2c_adapter *i2c, struct dvb_frontend_parameters *p) -{ - /* - The firmware of the sp8870 sometimes locks up after setting frontend parameters. - We try to detect this by checking the data valid signal. - If it is not set after MAXCHECKS we try to recover the lockup by setting - the frontend parameters again. - */ - - int err = 0; - int valid = 0; - int trials = 0; - int check_count = 0; - - dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency); - - for (trials = 1; trials <= MAXTRIALS; trials++) { - - if ((err = sp8870_set_frontend_parameters(i2c, p))) - return err; - - for (check_count = 0; check_count < MAXCHECKS; check_count++) { -// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0); - valid = sp8870_read_data_valid_signal(i2c); - if (valid) { - dprintk("%s: delay = %i usec\n", - __FUNCTION__, check_count * 10); - break; - } - udelay(10); - } - if (valid) - break; - } - - if (!valid) { - printk("%s: firmware crash!!!!!!\n", __FUNCTION__); - return -EIO; - } - - if (debug) { - if (valid) { - if (trials > 1) { - printk("%s: firmware lockup!!!\n", __FUNCTION__); - printk("%s: recovered after %i trial(s))\n", __FUNCTION__, trials - 1); - lockups++; - } - } - switches++; - printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups); - } - - return 0; -} - -static int sp8870_sleep(struct i2c_adapter *i2c) -{ - // tristate TS output and disable interface pins - return sp8870_writereg(i2c, 0xC18, 0x000); -} - -static int sp8870_wake_up(struct i2c_adapter *i2c) -{ - // enable TS output and interface pins - return sp8870_writereg(i2c, 0xC18, 0x00D); -} - -static int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct tdlb7_state *state = (struct tdlb7_state *) fe->data; - struct i2c_adapter *i2c = state->i2c; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: - return sp8870_read_status(i2c, (fe_status_t *) arg); - - case FE_READ_BER: - return sp8870_read_ber(i2c, (u32 *) arg); - - case FE_READ_SIGNAL_STRENGTH: - return sp8870_read_signal_strength(i2c, (u16 *) arg); - - case FE_READ_SNR: // not supported by hardware? - return sp8870_read_snr(i2c, (u32 *) arg); - - case FE_READ_UNCORRECTED_BLOCKS: - return sp8870_read_uncorrected_blocks(i2c, (u32 *) arg); - - case FE_SET_FRONTEND: - return sp8870_set_frontend(i2c, (struct dvb_frontend_parameters*) arg); - - case FE_GET_FRONTEND: // FIXME: read known values back from Hardware... - return -EOPNOTSUPP; - - case FE_SLEEP: - return sp8870_sleep(i2c); - - case FE_INIT: - sp8870_wake_up(i2c); - if (fe->data == NULL) { // first time initialisation... - fe->data = (void*) ~0; - sp8870_init (i2c); - } - break; - - case FE_GET_TUNE_SETTINGS: - { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; - fesettings->min_delay_ms = 150; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; - return 0; - } - - default: - return -EOPNOTSUPP; - }; - - return 0; -} - -static struct i2c_client client_template; - -static int attach_adapter(struct i2c_adapter *adapter) -{ - struct i2c_client *client; - struct tdlb7_state *state; - const struct firmware *fw; - int ret; - - u8 b0 [] = { 0x02 , 0x00 }; - u8 b1 [] = { 0, 0 }; - struct i2c_msg msg [] = { { .addr = 0x71, .flags = 0, .buf = b0, .len = 2 }, - { .addr = 0x71, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; - - dprintk ("%s\n", __FUNCTION__); - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - return -ENOMEM; - } - - if (NULL == (state = kmalloc(sizeof(struct tdlb7_state), GFP_KERNEL))) { - kfree(client); - return -ENOMEM; - } - state->i2c = adapter; - - if (i2c_transfer (adapter, msg, 2) != 2) { - kfree(state); - kfree(client); - return -ENODEV; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - i2c_set_clientdata(client, (void*)state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(state); - return ret; - } - - /* request the firmware, this will block until someone uploads it */ - printk("tdlb7: waiting for firmware upload...\n"); - ret = request_firmware(&fw, SP887X_DEFAULT_FIRMWARE, &client->dev); - if (ret) { - printk("tdlb7: no firmware upload (timeout or file not found?)\n"); - goto out; - } - - ret = sp8870_firmware_upload(adapter, fw); - if (ret) { - printk("tdlb7: writing firmware to device failed\n"); - release_firmware(fw); - goto out; - } - - ret = dvb_register_frontend(tdlb7_ioctl, state->dvb, state, - &tdlb7_info, THIS_MODULE); - if (ret) { - printk("tdlb7: registering frontend to dvb-core failed.\n"); - release_firmware(fw); - goto out; - } - - return 0; -out: - i2c_detach_client(client); - kfree(client); - kfree(state); - return ret; -} - -static int detach_client(struct i2c_client *client) -{ - struct tdlb7_state *state = (struct tdlb7_state*)i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - dvb_unregister_frontend (tdlb7_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} - -static int command (struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct tdlb7_state *state = (struct tdlb7_state*)i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_REGISTER: - state->dvb = (struct dvb_adapter*)arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_ALPS_TDLB7, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; - -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_tdlb7(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_tdlb7(void) -{ - if (i2c_del_driver(&driver)) - printk("tdlb7: driver deregistration failed\n"); -} - -module_init(init_tdlb7); -module_exit(exit_tdlb7); - -MODULE_DESCRIPTION("TDLB7 DVB-T Frontend"); -MODULE_AUTHOR("Juergen Peitz"); -MODULE_LICENSE("GPL"); - diff -Nru a/drivers/media/dvb/frontends/alps_tdmb7.c b/drivers/media/dvb/frontends/alps_tdmb7.c --- a/drivers/media/dvb/frontends/alps_tdmb7.c 2004-12-12 17:40:52 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,535 +0,0 @@ -/* - Alps TDMB7 DVB OFDM frontend driver - - Copyright (C) 2001-2002 Convergence Integrated Media GmbH - Holger Waechtler - - 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" - -#define FRONTEND_NAME "dvbfe_alps_tdmb7" - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - - -static struct dvb_frontend_info tdmb7_info = { - .name = "Alps TDMB7", - .type = FE_OFDM, - .frequency_min = 470000000, - .frequency_max = 860000000, - .frequency_stepsize = 166667, -#if 0 - .frequency_tolerance = ???, - .symbol_rate_min = ???, - .symbol_rate_max = ???, - .symbol_rate_tolerance = 500, /* ppm */ - .notifier_delay = 0, -#endif - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_RECOVER -}; - -struct tdmb7_state { - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - -static u8 init_tab [] = { - 0x04, 0x10, - 0x05, 0x09, - 0x06, 0x00, - 0x08, 0x04, - 0x09, 0x00, - 0x0a, 0x01, - 0x15, 0x40, - 0x16, 0x10, - 0x17, 0x87, - 0x18, 0x17, - 0x1a, 0x10, - 0x25, 0x04, - 0x2e, 0x00, - 0x39, 0x00, - 0x3a, 0x04, - 0x45, 0x08, - 0x46, 0x02, - 0x47, 0x05, -}; - -static int cx22700_writereg (struct i2c_adapter *i2c, u8 reg, u8 data) -{ - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = 0x43, .flags = 0, .buf = buf, .len = 2 }; - - dprintk ("%s\n", __FUNCTION__); - - ret = i2c_transfer (i2c, &msg, 1); - - if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", - __FUNCTION__, reg, data, ret); - - return (ret != 1) ? -1 : 0; -} - -static u8 cx22700_readreg (struct i2c_adapter *i2c, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = 0x43, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x43, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - dprintk ("%s\n", __FUNCTION__); - - ret = i2c_transfer (i2c, msg, 2); - - if (ret != 2) - printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - - return b1[0]; -} - -static int pll_write (struct i2c_adapter *i2c, u8 data [4]) -{ - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 }; - int ret; - - cx22700_writereg (i2c, 0x0a, 0x00); /* open i2c bus switch */ - ret = i2c_transfer (i2c, &msg, 1); - cx22700_writereg (i2c, 0x0a, 0x01); /* close i2c bus switch */ - - if (ret != 1) - printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", __FUNCTION__, msg.addr, ret); - - return (ret != 1) ? -1 : 0; -} - - -/** - * set up the downconverter frequency divisor for a - * reference clock comparision frequency of 125 kHz. - */ -static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ - u32 div = (freq + 36166667) / 166667; -#if 1 //ALPS_SETTINGS - u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85, - freq < 592000000 ? 0x40 : 0x80 }; -#else - u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85, - freq < 470000000 ? 0x42 : freq < 862000000 ? 0x41 : 0x81 }; -#endif - - dprintk ("%s: freq == %i, div == %i\n", __FUNCTION__, (int) freq, (int) div); - - return pll_write (i2c, buf); -} - -static int cx22700_init (struct i2c_adapter *i2c) -{ - int i; - - dprintk("cx22700_init: init chip\n"); - - cx22700_writereg (i2c, 0x00, 0x02); /* soft reset */ - cx22700_writereg (i2c, 0x00, 0x00); - - msleep(10); - - for (i=0; icode_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8) - return -EINVAL; - - if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8) - - if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5) - return -EINVAL; - - if (p->guard_interval < GUARD_INTERVAL_1_32 || - p->guard_interval > GUARD_INTERVAL_1_4) - return -EINVAL; - - if (p->transmission_mode != TRANSMISSION_MODE_2K && - p->transmission_mode != TRANSMISSION_MODE_8K) - return -EINVAL; - - if (p->constellation != QPSK && - p->constellation != QAM_16 && - p->constellation != QAM_64) - return -EINVAL; - - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) - return -EINVAL; - - if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ) - return -EINVAL; - - if (p->bandwidth == BANDWIDTH_7_MHZ) - cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 | 0x10)); - else - cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 & ~0x10)); - - val = qam_tab[p->constellation - QPSK]; - val |= p->hierarchy_information - HIERARCHY_NONE; - - cx22700_writereg (i2c, 0x04, val); - - val = fec_tab[p->code_rate_HP - FEC_1_2] << 3; - val |= fec_tab[p->code_rate_LP - FEC_1_2]; - - cx22700_writereg (i2c, 0x05, val); - - val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2; - val |= p->transmission_mode - TRANSMISSION_MODE_2K; - - cx22700_writereg (i2c, 0x06, val); - - cx22700_writereg (i2c, 0x08, 0x04 | 0x02); /* use user tps parameters */ - cx22700_writereg (i2c, 0x08, 0x04); /* restart aquisition */ - - return 0; -} - -static int cx22700_get_tps (struct i2c_adapter *i2c, struct dvb_ofdm_parameters *p) -{ - static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; - static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, - FEC_5_6, FEC_7_8 }; - u8 val; - - dprintk ("%s\n", __FUNCTION__); - - if (!(cx22700_readreg(i2c, 0x07) & 0x20)) /* tps valid? */ - return -EAGAIN; - - val = cx22700_readreg (i2c, 0x01); - - if ((val & 0x7) > 4) - p->hierarchy_information = HIERARCHY_AUTO; - else - p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); - - if (((val >> 3) & 0x3) > 2) - p->constellation = QAM_AUTO; - else - p->constellation = qam_tab[(val >> 3) & 0x3]; - - - val = cx22700_readreg (i2c, 0x02); - - if (((val >> 3) & 0x07) > 4) - p->code_rate_HP = FEC_AUTO; - else - p->code_rate_HP = fec_tab[(val >> 3) & 0x07]; - - if ((val & 0x07) > 4) - p->code_rate_LP = FEC_AUTO; - else - p->code_rate_LP = fec_tab[val & 0x07]; - - - val = cx22700_readreg (i2c, 0x03); - - p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3); - p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1); - - return 0; -} - -static int tdmb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct tdmb7_state *state = fe->data; - struct i2c_adapter *i2c = state->i2c; - - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &tdmb7_info, sizeof(struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: - { - fe_status_t *status = (fe_status_t *) arg; - u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9) - | (cx22700_readreg (i2c, 0x0e) << 1); - u8 sync = cx22700_readreg (i2c, 0x07); - - *status = 0; - - if (rs_ber < 0xff00) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x20) - *status |= FE_HAS_CARRIER; - - if (sync & 0x10) - *status |= FE_HAS_VITERBI; - - if (sync & 0x10) - *status |= FE_HAS_SYNC; - - if (*status == 0x0f) - *status |= FE_HAS_LOCK; - - break; - } - - case FE_READ_BER: - *((u32*) arg) = cx22700_readreg (i2c, 0x0c) & 0x7f; - cx22700_writereg (i2c, 0x0c, 0x00); - break; - - case FE_READ_SIGNAL_STRENGTH: - { - u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9) - | (cx22700_readreg (i2c, 0x0e) << 1); - *((u16*) arg) = ~rs_ber; - break; - } - case FE_READ_SNR: - { - u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9) - | (cx22700_readreg (i2c, 0x0e) << 1); - *((u16*) arg) = ~rs_ber; - break; - } - case FE_READ_UNCORRECTED_BLOCKS: - *((u32*) arg) = cx22700_readreg (i2c, 0x0f); - cx22700_writereg (i2c, 0x0f, 0x00); - break; - - case FE_SET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - cx22700_writereg (i2c, 0x00, 0x02); /* XXX CHECKME: soft reset*/ - cx22700_writereg (i2c, 0x00, 0x00); - - pll_set_tv_freq (i2c, p->frequency); - cx22700_set_inversion (i2c, p->inversion); - cx22700_set_tps (i2c, &p->u.ofdm); - cx22700_writereg (i2c, 0x37, 0x01); /* PAL loop filter off */ - cx22700_writereg (i2c, 0x00, 0x01); /* restart acquire */ - break; - } - - case FE_GET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - u8 reg09 = cx22700_readreg (i2c, 0x09); - - p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22700_get_tps (i2c, &p->u.ofdm); - } - - case FE_INIT: - return cx22700_init (i2c); - - case FE_GET_TUNE_SETTINGS: - { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; - fesettings->min_delay_ms = 150; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; - return 0; - } - - default: - return -EOPNOTSUPP; - }; - - return 0; -} - -static struct i2c_client client_template; - -static int attach_adapter (struct i2c_adapter *adapter) -{ - struct tdmb7_state *state; - struct i2c_client *client; - int ret; - - u8 b0 [] = { 0x7 }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = 0x43, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x43, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - dprintk ("%s\n", __FUNCTION__); - - if (i2c_transfer(adapter, msg, 2) != 2) - return -ENODEV; - - if (NULL == (state = kmalloc(sizeof(struct tdmb7_state), GFP_KERNEL))) - return -ENOMEM; - - state->i2c = adapter; - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(state); - return -ENOMEM; -} - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - i2c_set_clientdata(client, state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(state); - kfree(client); - return ret; - } - - BUG_ON(!state->dvb); - - ret = dvb_register_frontend (tdmb7_ioctl, state->dvb, state, - &tdmb7_info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - kfree(state); - kfree(client); - return ret; - } - - return 0; -} - -static int detach_client (struct i2c_client *client) -{ - struct tdmb7_state *state = i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - dvb_unregister_frontend (tdmb7_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} - -static int command (struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tdmb7_state *state = i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_REGISTER: - state->dvb = arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_ALPS_TDMB7, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; - -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_tdmb7 (void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_tdmb7 (void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "alps_tdmb7: driver deregistration failed.\n"); -} - -module_init (init_tdmb7); -module_exit (exit_tdmb7); - -MODULE_DESCRIPTION("TDMB7 DVB Frontend driver"); -MODULE_AUTHOR("Holger Waechtler"); -MODULE_LICENSE("GPL"); - diff -Nru a/drivers/media/dvb/frontends/at76c651.c b/drivers/media/dvb/frontends/at76c651.c --- a/drivers/media/dvb/frontends/at76c651.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/frontends/at76c651.c 2004-12-12 17:40:53 -08:00 @@ -24,9 +24,6 @@ * AT76C651 * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf * http://www.atmel.com/atmel/acrobat/doc1320.pdf - * - * TUA6010XS - * http://www.infineon.com/cgi/ecrm.dll/ecrm/scripts/public_download.jsp?oid=19512 */ #include @@ -36,48 +33,34 @@ #include #include #include - #include "dvb_frontend.h" +#include "at76c651.h" -#define FRONTEND_NAME "dvbfe_at76c651" -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) +struct at76c651_state { -static int debug; + struct i2c_adapter* i2c; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + struct dvb_frontend_ops ops; + const struct at76c651_config* config; -static struct dvb_frontend_info at76c651_info = { - .name = "Atmel AT76C651B with TUA6010XS", - .type = FE_QAM, - .frequency_min = 48250000, - .frequency_max = 863250000, - .frequency_stepsize = 62500, - /*.frequency_tolerance = */ /* FIXME: 12% of SR */ - .symbol_rate_min = 0, /* FIXME */ - .symbol_rate_max = 9360000, /* FIXME */ - .symbol_rate_tolerance = 4000, - .notifier_delay = 0, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | - FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER -}; + struct dvb_frontend frontend; -struct at76c651_state { + /* revision of the chip */ u8 revision; + + /* last QAM value set */ u8 qam; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; }; +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "at76c651: " args); \ + } while (0) + + #if ! defined(__powerpc__) static __inline__ int __ilog2(unsigned long x) { @@ -93,14 +76,14 @@ } #endif -static int at76c651_writereg(struct i2c_adapter *i2c, u8 reg, u8 data) +static int at76c651_writereg(struct at76c651_state* state, u8 reg, u8 data) { int ret; u8 buf[] = { reg, data }; struct i2c_msg msg = - { .addr = 0x1a >> 1, .flags = 0, .buf = buf, .len = 2 }; + { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - ret = i2c_transfer(i2c, &msg, 1); + ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) dprintk("%s: writereg error " @@ -112,16 +95,16 @@ return (ret != 1) ? -EREMOTEIO : 0; } -static u8 at76c651_readreg(struct i2c_adapter *i2c, u8 reg) +static u8 at76c651_readreg(struct at76c651_state* state, u8 reg) { int ret; u8 val; struct i2c_msg msg[] = { - { .addr = 0x1a >> 1, .flags = 0, .buf = ®, .len = 1 }, - { .addr = 0x1a >> 1, .flags = I2C_M_RD, .buf = &val, .len = 1 } + { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = &val, .len = 1 } }; - ret = i2c_transfer(i2c, msg, 2); + ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); @@ -129,112 +112,64 @@ return val; } -static int at76c651_reset(struct i2c_adapter *i2c) +static int at76c651_reset(struct at76c651_state* state) { - return at76c651_writereg(i2c, 0x07, 0x01); + return at76c651_writereg(state, 0x07, 0x01); } -static void at76c651_disable_interrupts(struct i2c_adapter *i2c) +static void at76c651_disable_interrupts(struct at76c651_state* state) { - at76c651_writereg(i2c, 0x0b, 0x00); + at76c651_writereg(state, 0x0b, 0x00); } static int at76c651_set_auto_config(struct at76c651_state *state) { - struct i2c_adapter *i2c = state->i2c; - /* * Autoconfig */ - at76c651_writereg(i2c, 0x06, 0x01); + at76c651_writereg(state, 0x06, 0x01); /* * Performance optimizations, should be done after autoconfig */ - at76c651_writereg(i2c, 0x10, 0x06); - at76c651_writereg(i2c, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10); - at76c651_writereg(i2c, 0x15, 0x28); - at76c651_writereg(i2c, 0x20, 0x09); - at76c651_writereg(i2c, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90); - at76c651_writereg(i2c, 0x30, 0x90); + at76c651_writereg(state, 0x10, 0x06); + at76c651_writereg(state, 0x11, ((state->qam == 5) || (state->qam == 7)) ? 0x12 : 0x10); + at76c651_writereg(state, 0x15, 0x28); + at76c651_writereg(state, 0x20, 0x09); + at76c651_writereg(state, 0x24, ((state->qam == 5) || (state->qam == 7)) ? 0xC0 : 0x90); + at76c651_writereg(state, 0x30, 0x90); if (state->qam == 5) - at76c651_writereg(i2c, 0x35, 0x2A); + at76c651_writereg(state, 0x35, 0x2A); /* * Initialize A/D-converter */ if (state->revision == 0x11) { - at76c651_writereg(i2c, 0x2E, 0x38); - at76c651_writereg(i2c, 0x2F, 0x13); + at76c651_writereg(state, 0x2E, 0x38); + at76c651_writereg(state, 0x2F, 0x13); } - at76c651_disable_interrupts(i2c); + at76c651_disable_interrupts(state); /* * Restart operation */ - at76c651_reset(i2c); + at76c651_reset(state); return 0; } -static void at76c651_set_bbfreq(struct i2c_adapter *i2c) +static void at76c651_set_bbfreq(struct at76c651_state* state) { - at76c651_writereg(i2c, 0x04, 0x3f); - at76c651_writereg(i2c, 0x05, 0xee); + at76c651_writereg(state, 0x04, 0x3f); + at76c651_writereg(state, 0x05, 0xee); } -static int at76c651_pll_write(struct i2c_adapter *i2c, u8 *buf, size_t len) -{ - int ret; - struct i2c_msg msg = - { .addr = 0xc2 >> 1, .flags = 0, .buf = buf, .len = len }; - - at76c651_writereg(i2c, 0x0c, 0xc3); - - ret = i2c_transfer(i2c, &msg, 1); - - at76c651_writereg(i2c, 0x0c, 0xc2); - - if (ret < 0) - return ret; - else if (ret != 1) - return -EREMOTEIO; - - return 0; -} - -static int tua6010_setfreq(struct i2c_adapter *i2c, u32 freq) -{ - u32 div; - u8 buf[4]; - u8 vu, p2, p1, p0; - - if ((freq < 50000000) || (freq > 900000000)) - return -EINVAL; - - div = (freq + 36125000) / 62500; - - if (freq > 400000000) - vu = 1, p2 = 1, p1 = 0, p0 = 1; - else if (freq > 140000000) - vu = 0, p2 = 1, p1 = 1, p0 = 0; - else - vu = 0, p2 = 0, p1 = 1, p0 = 1; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = (div >> 0) & 0xff; - buf[2] = 0x8e; - buf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0; - - return at76c651_pll_write(i2c, buf, 4); -} - -static int at76c651_set_symbol_rate(struct i2c_adapter *i2c, u32 symbol_rate) +static int at76c651_set_symbol_rate(struct at76c651_state* state, u32 symbol_rate) { u8 exponent; u32 mantissa; @@ -251,9 +186,9 @@ exponent = __ilog2((symbol_rate << 4) / 903125); mantissa = ((symbol_rate / 3125) * (1 << (24 - exponent))) / 289; - at76c651_writereg(i2c, 0x00, mantissa >> 13); - at76c651_writereg(i2c, 0x01, mantissa >> 5); - at76c651_writereg(i2c, 0x02, (mantissa << 3) | exponent); + at76c651_writereg(state, 0x00, mantissa >> 13); + at76c651_writereg(state, 0x01, mantissa >> 5); + at76c651_writereg(state, 0x02, (mantissa << 3) | exponent); return 0; } @@ -292,13 +227,12 @@ } - return at76c651_writereg(state->i2c, 0x03, state->qam); + return at76c651_writereg(state, 0x03, state->qam); } -static int at76c651_set_inversion(struct i2c_adapter *i2c, - fe_spectral_inversion_t inversion) +static int at76c651_set_inversion(struct at76c651_state* state, fe_spectral_inversion_t inversion) { - u8 feciqinv = at76c651_readreg(i2c, 0x60); + u8 feciqinv = at76c651_readreg(state, 0x60); switch (inversion) { case INVERSION_OFF: @@ -318,59 +252,63 @@ return -EINVAL; } - return at76c651_writereg(i2c, 0x60, feciqinv); + return at76c651_writereg(state, 0x60, feciqinv); } -static int at76c651_set_parameters(struct at76c651_state *state, + + + + + + + + +static int at76c651_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct i2c_adapter *i2c = state->i2c; int ret; + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - if ((ret = tua6010_setfreq(i2c, p->frequency))) - return ret; + at76c651_writereg(state, 0x0c, 0xc3); + state->config->pll_set(fe, p); + at76c651_writereg(state, 0x0c, 0xc2); - if ((ret = at76c651_set_symbol_rate(i2c, p->u.qam.symbol_rate))) + if ((ret = at76c651_set_symbol_rate(state, p->u.qam.symbol_rate))) return ret; - if ((ret = at76c651_set_inversion(i2c, p->inversion))) + if ((ret = at76c651_set_inversion(state, p->inversion))) return ret; return at76c651_set_auto_config(state); } -static int at76c651_set_defaults(struct at76c651_state *state) +static int at76c651_set_defaults(struct dvb_frontend* fe) { - struct i2c_adapter *i2c = state->i2c; + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - at76c651_set_symbol_rate(i2c, 6900000); + at76c651_set_symbol_rate(state, 6900000); at76c651_set_qam(state, QAM_64); - at76c651_set_bbfreq(i2c); + at76c651_set_bbfreq(state); at76c651_set_auto_config(state); - return 0; + if (state->config->pll_init) { + at76c651_writereg(state, 0x0c, 0xc3); + state->config->pll_init(fe); + at76c651_writereg(state, 0x0c, 0xc2); } -static int at76c651_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct at76c651_state *state = fe->data; - struct i2c_adapter *i2c = state->i2c; - - switch (cmd) { - case FE_GET_INFO: - memcpy(arg, &at76c651_info, sizeof (struct dvb_frontend_info)); - break; + return 0; +} - case FE_READ_STATUS: +static int at76c651_read_status(struct dvb_frontend* fe, fe_status_t* status) { - fe_status_t *status = arg; + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; u8 sync; /* * Bits: FEC, CAR, EQU, TIM, AGC2, AGC1, ADC, PLL (PLL=0) */ - sync = at76c651_readreg(i2c, 0x80); - + sync = at76c651_readreg(state, 0x80); *status = 0; if (sync & (0x04 | 0x10)) /* AGC1 || TIM */ @@ -388,186 +326,138 @@ if ((sync & 0xF0) == 0xF0) /* TIM && EQU && CAR && FEC */ *status |= FE_HAS_LOCK; - break; - + return 0; } - case FE_READ_BER: +static int at76c651_read_ber(struct dvb_frontend* fe, u32* ber) { - u32 *ber = arg; - *ber = (at76c651_readreg(i2c, 0x81) & 0x0F) << 16; - *ber |= at76c651_readreg(i2c, 0x82) << 8; - *ber |= at76c651_readreg(i2c, 0x83); + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + + *ber = (at76c651_readreg(state, 0x81) & 0x0F) << 16; + *ber |= at76c651_readreg(state, 0x82) << 8; + *ber |= at76c651_readreg(state, 0x83); *ber *= 10; - break; - } - case FE_READ_SIGNAL_STRENGTH: - { - u8 gain = ~at76c651_readreg(i2c, 0x91); - *(u16 *) arg = (gain << 8) | gain; - break; + return 0; } - case FE_READ_SNR: - *(u16 *)arg = 0xFFFF - - ((at76c651_readreg(i2c, 0x8F) << 8) | - at76c651_readreg(i2c, 0x90)); - break; - - case FE_READ_UNCORRECTED_BLOCKS: - *(u32 *)arg = at76c651_readreg(i2c, 0x82); - break; - - case FE_SET_FRONTEND: - return at76c651_set_parameters(state, arg); - - case FE_GET_FRONTEND: - break; - - case FE_SLEEP: - break; - - case FE_INIT: - return at76c651_set_defaults(state); - - case FE_GET_TUNE_SETTINGS: - { - struct dvb_frontend_tune_settings *fesettings = arg; - fesettings->min_delay_ms = 50; - fesettings->step_size = 0; - fesettings->max_drift = 0; - break; - } +static int at76c651_read_signal_strength(struct dvb_frontend* fe, u16* strength) + { + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - default: - return -ENOIOCTLCMD; - } + u8 gain = ~at76c651_readreg(state, 0x91); + *strength = (gain << 8) | gain; return 0; } -static struct i2c_client client_template; - -static int attach_adapter(struct i2c_adapter *adapter) +static int at76c651_read_snr(struct dvb_frontend* fe, u16* snr) { - struct at76c651_state *state; - struct i2c_client *client; - int ret; - - if (at76c651_readreg(adapter, 0x0E) != 0x65) - return -ENODEV; + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - if (!(state = kmalloc(sizeof(struct at76c651_state), GFP_KERNEL))) - return -ENOMEM; + *snr = 0xFFFF - + ((at76c651_readreg(state, 0x8F) << 8) | + at76c651_readreg(state, 0x90)); - state->i2c = adapter; - state->revision = at76c651_readreg(adapter, 0x0F) & 0xFE; - - switch (state->revision) { - case 0x10: - at76c651_info.name[14] = 'A'; - break; - case 0x11: - at76c651_info.name[14] = 'B'; - break; - default: - kfree(state); - return -ENODEV; - } - - if (!(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(state); - return -ENOMEM; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = 0x1a >> 1; - i2c_set_clientdata(client, state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(state); - kfree(client); - return ret; - } - - BUG_ON(!state->dvb); - - ret = dvb_register_frontend(at76c651_ioctl, state->dvb, state, - &at76c651_info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - kfree(client); - kfree(state); - return ret; - } return 0; - } +} -static int detach_client(struct i2c_client *client) -{ - struct at76c651_state *state = i2c_get_clientdata(client); +static int at76c651_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) + { + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; - dvb_unregister_frontend(at76c651_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); + *ucblocks = at76c651_readreg(state, 0x82); return 0; } -static int command(struct i2c_client *client, unsigned int cmd, void *arg) +static int at76c651_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *fesettings) { - struct at76c651_state *state = i2c_get_clientdata(client); - - switch (cmd) { - case FE_REGISTER: - state->dvb = arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - + fesettings->min_delay_ms = 50; + fesettings->step_size = 0; + fesettings->max_drift = 0; return 0; -} + } -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_AT76C651, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; +static void at76c651_release(struct dvb_frontend* fe) +{ + struct at76c651_state* state = (struct at76c651_state*) fe->demodulator_priv; + kfree(state); + } -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; +static struct dvb_frontend_ops at76c651_ops; -static int __init at76c651_init(void) +struct dvb_frontend* at76c651_attach(const struct at76c651_config* config, + struct i2c_adapter* i2c) { - return i2c_add_driver(&driver); -} + struct at76c651_state* state = NULL; -static void __exit at76c651_exit(void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "at76c651: driver deregistration failed.\n"); -} + /* allocate memory for the internal state */ + state = (struct at76c651_state*) kmalloc(sizeof(struct at76c651_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->qam = 0; + + /* check if the demod is there */ + if (at76c651_readreg(state, 0x0e) != 0x65) goto error; + + /* finalise state setup */ + state->i2c = i2c; + state->revision = at76c651_readreg(state, 0x0f) & 0xfe; + memcpy(&state->ops, &at76c651_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops at76c651_ops = { + + .info = { + .name = "Atmel AT76C651B DVB-C", + .type = FE_QAM, + .frequency_min = 48250000, + .frequency_max = 863250000, + .frequency_stepsize = 62500, + /*.frequency_tolerance = */ /* FIXME: 12% of SR */ + .symbol_rate_min = 0, /* FIXME */ + .symbol_rate_max = 9360000, /* FIXME */ + .symbol_rate_tolerance = 4000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | + FE_CAN_MUTE_TS | FE_CAN_QAM_256 | FE_CAN_RECOVER + }, + + .release = at76c651_release, + + .init = at76c651_set_defaults, + + .set_frontend = at76c651_set_parameters, + .get_tune_settings = at76c651_get_tune_settings, + + .read_status = at76c651_read_status, + .read_ber = at76c651_read_ber, + .read_signal_strength = at76c651_read_signal_strength, + .read_snr = at76c651_read_snr, + .read_ucblocks = at76c651_read_ucblocks, +}; -module_init(at76c651_init); -module_exit(at76c651_exit); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("at76c651/tua6010xs dvb-c frontend driver"); +MODULE_DESCRIPTION("Atmel AT76C651 DVB-C Demodulator Driver"); MODULE_AUTHOR("Andreas Oberritter "); MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(at76c651_attach); diff -Nru a/drivers/media/dvb/frontends/at76c651.h b/drivers/media/dvb/frontends/at76c651.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/at76c651.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,47 @@ +/* + * at76c651.c + * + * Atmel DVB-C Frontend Driver (at76c651) + * + * Copyright (C) 2001 fnbrd + * & 2002-2004 Andreas Oberritter + * & 2003 Wolfram Joost + * + * 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. + * + * AT76C651 + * http://www.nalanda.nitc.ac.in/industry/datasheets/atmel/acrobat/doc1293.pdf + * http://www.atmel.com/atmel/acrobat/doc1320.pdf + */ + +#ifndef AT76C651_H +#define AT76C651_H + +#include + +struct at76c651_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* at76c651_attach(const struct at76c651_config* config, + struct i2c_adapter* i2c); + +#endif // AT76C651_H diff -Nru a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/cx22700.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,445 @@ +#/* + Conexant cx22700 DVB OFDM demodulator driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + 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 "cx22700.h" + + +struct cx22700_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + const struct cx22700_config* config; + + struct dvb_frontend frontend; +}; + + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "cx22700: " args); \ + } while (0) + +static u8 init_tab [] = { + 0x04, 0x10, + 0x05, 0x09, + 0x06, 0x00, + 0x08, 0x04, + 0x09, 0x00, + 0x0a, 0x01, + 0x15, 0x40, + 0x16, 0x10, + 0x17, 0x87, + 0x18, 0x17, + 0x1a, 0x10, + 0x25, 0x04, + 0x2e, 0x00, + 0x39, 0x00, + 0x3a, 0x04, + 0x45, 0x08, + 0x46, 0x02, + 0x47, 0x05, +}; + + +static int cx22700_writereg (struct cx22700_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + dprintk ("%s\n", __FUNCTION__); + + ret = i2c_transfer (state->i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static int cx22700_readreg (struct cx22700_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + dprintk ("%s\n", __FUNCTION__); + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) return -EIO; + + return b1[0]; +} + +static int cx22700_set_inversion (struct cx22700_state* state, int inversion) +{ + u8 val; + + dprintk ("%s\n", __FUNCTION__); + + switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_ON: + val = cx22700_readreg (state, 0x09); + return cx22700_writereg (state, 0x09, val | 0x01); + case INVERSION_OFF: + val = cx22700_readreg (state, 0x09); + return cx22700_writereg (state, 0x09, val & 0xfe); + default: + return -EINVAL; + } +} + +static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_parameters *p) +{ + static const u8 qam_tab [4] = { 0, 1, 0, 2 }; + static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 }; + u8 val; + + dprintk ("%s\n", __FUNCTION__); + + if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8) + return -EINVAL; + + if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8) + + if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5) + return -EINVAL; + + if (p->guard_interval < GUARD_INTERVAL_1_32 || + p->guard_interval > GUARD_INTERVAL_1_4) + return -EINVAL; + + if (p->transmission_mode != TRANSMISSION_MODE_2K && + p->transmission_mode != TRANSMISSION_MODE_8K) + return -EINVAL; + + if (p->constellation != QPSK && + p->constellation != QAM_16 && + p->constellation != QAM_64) + return -EINVAL; + + if (p->hierarchy_information < HIERARCHY_NONE || + p->hierarchy_information > HIERARCHY_4) + return -EINVAL; + + if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ) + return -EINVAL; + + if (p->bandwidth == BANDWIDTH_7_MHZ) + cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 | 0x10)); + else + cx22700_writereg (state, 0x09, cx22700_readreg (state, 0x09 & ~0x10)); + + val = qam_tab[p->constellation - QPSK]; + val |= p->hierarchy_information - HIERARCHY_NONE; + + cx22700_writereg (state, 0x04, val); + + val = fec_tab[p->code_rate_HP - FEC_1_2] << 3; + val |= fec_tab[p->code_rate_LP - FEC_1_2]; + + cx22700_writereg (state, 0x05, val); + + val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2; + val |= p->transmission_mode - TRANSMISSION_MODE_2K; + + cx22700_writereg (state, 0x06, val); + + cx22700_writereg (state, 0x08, 0x04 | 0x02); /* use user tps parameters */ + cx22700_writereg (state, 0x08, 0x04); /* restart aquisition */ + + return 0; +} + +static int cx22700_get_tps (struct cx22700_state* state, struct dvb_ofdm_parameters *p) +{ + static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; + static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, + FEC_5_6, FEC_7_8 }; + u8 val; + + dprintk ("%s\n", __FUNCTION__); + + if (!(cx22700_readreg(state, 0x07) & 0x20)) /* tps valid? */ + return -EAGAIN; + + val = cx22700_readreg (state, 0x01); + + if ((val & 0x7) > 4) + p->hierarchy_information = HIERARCHY_AUTO; + else + p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); + + if (((val >> 3) & 0x3) > 2) + p->constellation = QAM_AUTO; + else + p->constellation = qam_tab[(val >> 3) & 0x3]; + + val = cx22700_readreg (state, 0x02); + + if (((val >> 3) & 0x07) > 4) + p->code_rate_HP = FEC_AUTO; + else + p->code_rate_HP = fec_tab[(val >> 3) & 0x07]; + + if ((val & 0x07) > 4) + p->code_rate_LP = FEC_AUTO; + else + p->code_rate_LP = fec_tab[val & 0x07]; + + val = cx22700_readreg (state, 0x03); + + p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3); + p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1); + + return 0; +} + + + + + + + + + + + +static int cx22700_init (struct dvb_frontend* fe) + +{ struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + int i; + + dprintk("cx22700_init: init chip\n"); + + cx22700_writereg (state, 0x00, 0x02); /* soft reset */ + cx22700_writereg (state, 0x00, 0x00); + + msleep(10); + + for (i=0; iconfig->pll_init) { + cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */ + state->config->pll_init(fe); + cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */ + } + + return 0; +} + +static int cx22700_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + + u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) + | (cx22700_readreg (state, 0x0e) << 1); + u8 sync = cx22700_readreg (state, 0x07); + + *status = 0; + + if (rs_ber < 0xff00) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x20) + *status |= FE_HAS_CARRIER; + + if (sync & 0x10) + *status |= FE_HAS_VITERBI; + + if (sync & 0x10) + *status |= FE_HAS_SYNC; + + if (*status == 0x0f) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int cx22700_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + + *ber = cx22700_readreg (state, 0x0c) & 0x7f; + cx22700_writereg (state, 0x0c, 0x00); + + return 0; +} + +static int cx22700_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + + u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) + | (cx22700_readreg (state, 0x0e) << 1); + *signal_strength = ~rs_ber; + + return 0; +} + +static int cx22700_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + + u16 rs_ber = (cx22700_readreg (state, 0x0d) << 9) + | (cx22700_readreg (state, 0x0e) << 1); + *snr = ~rs_ber; + + return 0; +} + +static int cx22700_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + + *ucblocks = cx22700_readreg (state, 0x0f); + cx22700_writereg (state, 0x0f, 0x00); + + return 0; +} + +static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + + cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ + cx22700_writereg (state, 0x00, 0x00); + + cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */ + state->config->pll_set(fe, p); + cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */ + cx22700_set_inversion (state, p->inversion); + cx22700_set_tps (state, &p->u.ofdm); + cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */ + cx22700_writereg (state, 0x00, 0x01); /* restart acquire */ + + return 0; +} + +static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + u8 reg09 = cx22700_readreg (state, 0x09); + + p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22700_get_tps (state, &p->u.ofdm); +} + +static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 150; + fesettings->step_size = 166667; + fesettings->max_drift = 166667*2; + return 0; +} + +static void cx22700_release(struct dvb_frontend* fe) +{ + struct cx22700_state* state = (struct cx22700_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops cx22700_ops; + +struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, + struct i2c_adapter* i2c) +{ + struct cx22700_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct cx22700_state*) kmalloc(sizeof(struct cx22700_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops)); + + /* check if the demod is there */ + if (cx22700_readreg(state, 0x07) < 0) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops cx22700_ops = { + + .info = { + .name = "Conexant CX22700 DVB-T", + .type = FE_OFDM, + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_RECOVER + }, + + .release = cx22700_release, + + .init = cx22700_init, + + .set_frontend = cx22700_set_frontend, + .get_frontend = cx22700_get_frontend, + .get_tune_settings = cx22700_get_tune_settings, + + .read_status = cx22700_read_status, + .read_ber = cx22700_read_ber, + .read_signal_strength = cx22700_read_signal_strength, + .read_snr = cx22700_read_snr, + .read_ucblocks = cx22700_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Conexant CX22700 DVB-T Demodulator driver"); +MODULE_AUTHOR("Holger Waechtler"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cx22700_attach); diff -Nru a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/cx22700.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,41 @@ +/* + Conexant CX22700 DVB OFDM demodulator driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + 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 CX22700_H +#define CX22700_H + +#include + +struct cx22700_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, + struct i2c_adapter* i2c); + +#endif // CX22700_H diff -Nru a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c --- a/drivers/media/dvb/frontends/cx22702.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/frontends/cx22702.c 2004-12-12 17:40:53 -08:00 @@ -1,8 +1,8 @@ /* - Conexant 22702 DVB OFDM frontend driver + Conexant 22702 DVB OFDM demodulator driver based on: - Alps TDMB7 DVB OFDM frontend driver + Alps TDMB7 DVB OFDM demodulator driver Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler @@ -31,44 +31,28 @@ #include #include #include - #include "dvb_frontend.h" +#include "cx22702.h" -#define FRONTEND_NAME "dvbfe_cx22702" -#define I2C_EEPROM_SLAVE_ADDR 0x50 +struct cx22702_state { -#define PLLTYPE_DTT7592 1 -#define PLLTYPE_DTT7595 2 -#define PLLTYPE_DTT7579 3 + struct i2c_adapter* i2c; -static int debug = 0; + struct dvb_frontend_ops ops; -#define dprintk if (debug) printk + /* configuration settings */ + const struct cx22702_config* config; -static struct dvb_frontend_info cx22702_info = { - .name = "CX22702 Demod Thomson 759x/7579 PLL", - .type = FE_OFDM, - .frequency_min = 177000000, - .frequency_max = 858000000, - .frequency_stepsize = 166666, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER -}; + struct dvb_frontend frontend; -struct cx22702_state { - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; - struct dvb_frontend_info cx22702_info; - char pll_type; - int pll_addr; - int demod_addr; + /* previous uncorrected block counter */ u8 prevUCBlocks; }; +static int debug = 0; +#define dprintk if (debug) printk + /* Register values to initialise the demod */ static u8 init_tab [] = { 0x00, 0x00, /* Stop aquisition */ @@ -99,15 +83,13 @@ 0xfd, 0x00, }; -static struct i2c_client client_template; - -static int cx22702_writereg (struct i2c_adapter *i2c, int demod_addr, u8 reg, u8 data) +static int cx22702_writereg (struct cx22702_state* state, u8 reg, u8 data) { int ret; u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = demod_addr, .flags = 0, .buf = buf, .len = 2 }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - ret = i2c_transfer(i2c, &msg, 1); + ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", @@ -116,17 +98,17 @@ return (ret != 1) ? -1 : 0; } -static u8 cx22702_readreg (struct i2c_adapter *i2c, int demod_addr, u8 reg) +static u8 cx22702_readreg (struct cx22702_state* state, u8 reg) { int ret; u8 b0 [] = { reg }; u8 b1 [] = { 0 }; struct i2c_msg msg [] = { - { .addr = demod_addr, .flags = 0, .buf = b0, .len = 1 }, - { .addr = demod_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - ret = i2c_transfer(i2c, msg, 2); + ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); @@ -134,232 +116,121 @@ return b1[0]; } -static int pll_readreg(struct i2c_adapter *i2c, int pll_addr, int demod_addr, u8 reg) +static int cx22702_set_inversion (struct cx22702_state *state, int inversion) { - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; + u8 val; - struct i2c_msg msg [] = { - { .addr = pll_addr, .flags = 0, .buf = b0, .len = 1 }, - { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } - }; - - cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) &0xfe); // Enable PLL bus - if (i2c_transfer(i2c, msg, 2) != 2) { - printk ("%s i2c pll request failed\n", __FUNCTION__); - cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus - return -ENODEV; - } - cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus + switch (inversion) { - return b1[0]; -} + case INVERSION_AUTO: + return -EOPNOTSUPP; -static int pll_write (struct i2c_adapter *i2c, int pll_addr, int demod_addr, u8 data [4]) -{ - int ret=0; - struct i2c_msg msg = { .addr = pll_addr, .flags = 0, .buf = data, .len = 4 }; + case INVERSION_ON: + val = cx22702_readreg (state, 0x0C); + return cx22702_writereg (state, 0x0C, val | 0x01); - cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) &0xfe); // Enable PLL bus - ret = i2c_transfer(i2c, &msg, 1); - cx22702_writereg (i2c, demod_addr, 0x0D, cx22702_readreg(i2c,demod_addr,0x0D) | 1); // Disable PLL bus + case INVERSION_OFF: + val = cx22702_readreg (state, 0x0C); + return cx22702_writereg (state, 0x0C, val & 0xfe); - if (ret != 1) - printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", __FUNCTION__, msg.addr, ret); + default: + return -EINVAL; + + } - return (ret != 1) ? -1 : 0; } -static int pll_dtt759x_set_tv_freq (struct i2c_adapter *i2c, struct cx22702_state *state, u32 freq, int bandwidth) +/* Retrieve the demod settings */ +static int cx22702_get_tps (struct cx22702_state *state, struct dvb_ofdm_parameters *p) { - int ret; - - u32 div = (freq + 36166667) / 166666; - - /* dividerhigh, dividerlow, control, bandwidth switch tuner args */ - unsigned char buf [4] = { - (div >> 8) & 0x7f, - div & 0xff, - 0x84, - 0x00 - }; + u8 val; - if(freq < 470000000) { - buf[3] = 0x02; - } else { - buf[3] = 0x08; - } + /* Make sure the TPS regs are valid */ + if (!(cx22702_readreg(state, 0x0A) & 0x20)) + return -EAGAIN; - if(bandwidth == BANDWIDTH_7_MHZ) { - buf[3] |= 0x10; + val = cx22702_readreg (state, 0x01); + switch( (val&0x18)>>3) { + case 0: p->constellation = QPSK; break; + case 1: p->constellation = QAM_16; break; + case 2: p->constellation = QAM_64; break; } - - // Now compensate for the charge pump osc - if(freq <= 264000000) { - buf[2] = buf[2] | 0x30; - } else if (freq <= 735000000) { - buf[2] = buf[2] | 0x38; - } else if (freq <= 835000000) { - buf[2] = buf[2] | 0x70; - } else if (freq <= 896000000) { - buf[2] = buf[2] | 0x78; + switch( val&0x07 ) { + case 0: p->hierarchy_information = HIERARCHY_NONE; break; + case 1: p->hierarchy_information = HIERARCHY_1; break; + case 2: p->hierarchy_information = HIERARCHY_2; break; + case 3: p->hierarchy_information = HIERARCHY_4; break; } - dprintk ("%s: freq == %i, div == 0x%04x\n", __FUNCTION__, (int) freq, (int) div); - - ret= pll_write (i2c, state->pll_addr, state->demod_addr, buf); - if(ret<0) { - dprintk ("%s: first pll_write failed\n",__FUNCTION__); - return ret; - } - /* Set the AGC during search */ - buf[2]=(buf[2] & 0xc7) | 0x18; - buf[3]=0xa0; - ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf); - if(ret<0) { - dprintk ("%s: second pll_write failed\n",__FUNCTION__); - return ret; + val = cx22702_readreg (state, 0x02); + switch( (val&0x38)>>3 ) { + case 0: p->code_rate_HP = FEC_1_2; break; + case 1: p->code_rate_HP = FEC_2_3; break; + case 2: p->code_rate_HP = FEC_3_4; break; + case 3: p->code_rate_HP = FEC_5_6; break; + case 4: p->code_rate_HP = FEC_7_8; break; } - - /* Tuner needs a small amount of time */ - msleep(100); - - /* Set the AGC post-search */ - buf[3]=0x20; - ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf); - if(ret<0) { - dprintk ("%s: third pll_write failed\n",__FUNCTION__); - return ret; + switch( val&0x07 ) { + case 0: p->code_rate_LP = FEC_1_2; break; + case 1: p->code_rate_LP = FEC_2_3; break; + case 2: p->code_rate_LP = FEC_3_4; break; + case 3: p->code_rate_LP = FEC_5_6; break; + case 4: p->code_rate_LP = FEC_7_8; break; } - return ret; + val = cx22702_readreg (state, 0x03); + switch( (val&0x0c)>>2 ) { + case 0: p->guard_interval = GUARD_INTERVAL_1_32; break; + case 1: p->guard_interval = GUARD_INTERVAL_1_16; break; + case 2: p->guard_interval = GUARD_INTERVAL_1_8; break; + case 3: p->guard_interval = GUARD_INTERVAL_1_4; break; } - -static int pll_dtt7579_set_tv_freq (struct i2c_adapter *i2c, struct cx22702_state *state, u32 freq, int bandwidth) -{ - int ret; - - u32 div = (freq + 36166667) / 166666; - - /* dividerhigh, dividerlow */ - unsigned char buf [4] = { - div >> 8, - div & 0xff, - 0x00, - 0x00 - }; - - // FIXME: bandwidth setting unknown - - // Now compensate for the charge pump osc - if(freq <= 506000000) { - buf[2] = 0xb4; - buf[3] = 0x02; - } else if (freq <= 735000000) { - buf[2] = 0xbc; - buf[3] = 0x08; - } else if (freq <= 835000000) { - buf[2] = 0xf4; - buf[3] = 0x08; - } else if (freq <= 896000000) { - buf[2] = 0xfc; - buf[3] = 0x08; - } - - dprintk ("%s: freq == %i, div == 0x%04x\n", __FUNCTION__, (int) freq, (int) div); - - ret= pll_write (i2c, state->pll_addr, state->demod_addr, buf); - if(ret<0) { - dprintk ("%s: first pll_write failed\n",__FUNCTION__); - return ret; - } - - /* Set the AGC to search */ - buf[2]=(buf[2] & 0xdc) | 0x9c; - buf[3]=0xa0; - ret=pll_write (i2c, state->pll_addr, state->demod_addr, buf); - if(ret<0) { - dprintk ("%s: second pll_write failed\n",__FUNCTION__); - return ret; + switch( val&0x03 ) { + case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break; + case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break; } - return ret; - + return 0; } -/* Reset the demod hardware and reset all of the configuration registers - to a default state. */ -static int cx22702_init (struct i2c_adapter *i2c, struct cx22702_state *state) -{ - int i; - - cx22702_writereg (i2c, state->demod_addr, 0x00, 0x02); - msleep(10); - for (i=0; idemod_addr, init_tab[i], init_tab[i+1]); - return 0; -} -static int cx22702_set_inversion (struct i2c_adapter *i2c, struct cx22702_state *state, int inversion) -{ - u8 val; - switch (inversion) { - case INVERSION_AUTO: - return -EOPNOTSUPP; - case INVERSION_ON: - val = cx22702_readreg (i2c, state->demod_addr, 0x0C); - return cx22702_writereg (i2c, state->demod_addr, 0x0C, val | 0x01); - case INVERSION_OFF: - val = cx22702_readreg (i2c, state->demod_addr, 0x0C); - return cx22702_writereg (i2c, state->demod_addr, 0x0C, val & 0xfe); - default: - return -EINVAL; - } -} /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ -static int cx22702_set_tps (struct i2c_adapter *i2c, struct cx22702_state *state, - struct dvb_frontend_parameters *p) +static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { u8 val; + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; /* set PLL */ - switch(state->pll_type) { - case PLLTYPE_DTT7592: - case PLLTYPE_DTT7595: - pll_dtt759x_set_tv_freq (i2c, state, p->frequency, p->u.ofdm.bandwidth); - break; - - case PLLTYPE_DTT7579: - pll_dtt7579_set_tv_freq (i2c, state, p->frequency, p->u.ofdm.bandwidth); - break; - } + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + state->config->pll_set(fe, p); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); /* set inversion */ - cx22702_set_inversion (i2c, state, p->inversion); + cx22702_set_inversion (state, p->inversion); /* set bandwidth */ switch(p->u.ofdm.bandwidth) { case BANDWIDTH_6_MHZ: - cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xcf) | 0x20 ); + cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20 ); break; case BANDWIDTH_7_MHZ: - cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xcf) | 0x10 ); + cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10 ); break; case BANDWIDTH_8_MHZ: - cx22702_writereg(i2c, state->demod_addr, 0x0C, cx22702_readreg(i2c, state->demod_addr, 0x0C) &0xcf ); + cx22702_writereg(state, 0x0C, cx22702_readreg(state, 0x0C) &0xcf ); break; default: dprintk ("%s: invalid bandwidth\n",__FUNCTION__); @@ -378,12 +249,12 @@ (p->u.ofdm.transmission_mode==TRANSMISSION_MODE_AUTO) ) { /* TPS Source - use hardware driven values */ - cx22702_writereg(i2c, state->demod_addr, 0x06, 0x10); - cx22702_writereg(i2c, state->demod_addr, 0x07, 0x9); - cx22702_writereg(i2c, state->demod_addr, 0x08, 0xC1); - cx22702_writereg(i2c, state->demod_addr, 0x0B, cx22702_readreg(i2c, state->demod_addr, 0x0B) & 0xfc ); - cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xBF) | 0x40 ); - cx22702_writereg(i2c, state->demod_addr, 0x00, 0x01); /* Begin aquisition */ + cx22702_writereg(state, 0x06, 0x10); + cx22702_writereg(state, 0x07, 0x9); + cx22702_writereg(state, 0x08, 0xC1); + cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc ); + cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); + cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ printk("%s: Autodetecting\n",__FUNCTION__); return 0; } @@ -407,7 +278,7 @@ dprintk ("%s: invalid hierarchy\n",__FUNCTION__); return -EINVAL; } - cx22702_writereg (i2c, state->demod_addr, 0x06, val); + cx22702_writereg (state, 0x06, val); val=0; switch(p->u.ofdm.code_rate_HP) { @@ -432,7 +303,7 @@ dprintk ("%s: invalid code_rate_LP\n",__FUNCTION__); return -EINVAL; } - cx22702_writereg (i2c, state->demod_addr, 0x07, val); + cx22702_writereg (state, 0x07, val); val=0; switch(p->u.ofdm.guard_interval) { @@ -451,93 +322,52 @@ dprintk ("%s: invalid transmission_mode\n",__FUNCTION__); return -EINVAL; } - cx22702_writereg (i2c, state->demod_addr, 0x08, val); - cx22702_writereg(i2c, state->demod_addr, 0x0B, (cx22702_readreg(i2c, state->demod_addr, 0x0B) & 0xfc) | 0x02 ); - cx22702_writereg(i2c, state->demod_addr, 0x0C, (cx22702_readreg(i2c, state->demod_addr, 0x0C) & 0xBF) | 0x40 ); + cx22702_writereg(state, 0x08, val); + cx22702_writereg(state, 0x0B, (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02 ); + cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 ); /* Begin channel aquisition */ - cx22702_writereg(i2c, state->demod_addr, 0x00, 0x01); + cx22702_writereg(state, 0x00, 0x01); return 0; } -/* Retrieve the demod settings */ -static int cx22702_get_tps (struct i2c_adapter *i2c, struct cx22702_state *state, - struct dvb_ofdm_parameters *p) -{ - u8 val; - /* Make sure the TPS regs are valid */ - if (!(cx22702_readreg(i2c, state->demod_addr, 0x0A) & 0x20)) - return -EAGAIN; +/* Reset the demod hardware and reset all of the configuration registers + to a default state. */ +static int cx22702_init (struct dvb_frontend* fe) +{ + int i; + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - val = cx22702_readreg (i2c, state->demod_addr, 0x01); - switch( (val&0x18)>>3) { - case 0: p->constellation = QPSK; break; - case 1: p->constellation = QAM_16; break; - case 2: p->constellation = QAM_64; break; - } - switch( val&0x07 ) { - case 0: p->hierarchy_information = HIERARCHY_NONE; break; - case 1: p->hierarchy_information = HIERARCHY_1; break; - case 2: p->hierarchy_information = HIERARCHY_2; break; - case 3: p->hierarchy_information = HIERARCHY_4; break; - } + cx22702_writereg (state, 0x00, 0x02); + msleep(10); - val = cx22702_readreg (i2c, state->demod_addr, 0x02); - switch( (val&0x38)>>3 ) { - case 0: p->code_rate_HP = FEC_1_2; break; - case 1: p->code_rate_HP = FEC_2_3; break; - case 2: p->code_rate_HP = FEC_3_4; break; - case 3: p->code_rate_HP = FEC_5_6; break; - case 4: p->code_rate_HP = FEC_7_8; break; - } - switch( val&0x07 ) { - case 0: p->code_rate_LP = FEC_1_2; break; - case 1: p->code_rate_LP = FEC_2_3; break; - case 2: p->code_rate_LP = FEC_3_4; break; - case 3: p->code_rate_LP = FEC_5_6; break; - case 4: p->code_rate_LP = FEC_7_8; break; - } + for (i=0; idemod_addr, 0x03); - switch( (val&0x0c)>>2 ) { - case 0: p->guard_interval = GUARD_INTERVAL_1_32; break; - case 1: p->guard_interval = GUARD_INTERVAL_1_16; break; - case 2: p->guard_interval = GUARD_INTERVAL_1_8; break; - case 3: p->guard_interval = GUARD_INTERVAL_1_4; break; - } - switch( val&0x03 ) { - case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break; + /* init PLL */ + if (state->config->pll_init) { + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe); + state->config->pll_init(fe); + cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1); } return 0; } -static int cx22702_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int cx22702_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct cx22702_state *state = fe->data; - struct i2c_adapter *i2c = state->i2c; + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; u8 reg0A; u8 reg23; - u8 ucblocks; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &state->cx22702_info, sizeof(struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: - { - fe_status_t *status = (fe_status_t *) arg; *status = 0; - reg0A = cx22702_readreg (i2c, state->demod_addr, 0x0A); - reg23 = cx22702_readreg (i2c, state->demod_addr, 0x23); + reg0A = cx22702_readreg (state, 0x0A); + reg23 = cx22702_readreg (state, 0x23); dprintk ("%s: status demod=0x%02x agc=0x%02x\n" ,__FUNCTION__,reg0A,reg23); @@ -554,347 +384,149 @@ if(reg23 < 0xf0) *status |= FE_HAS_SIGNAL; - break; - - } - - case FE_READ_BER: - if(cx22702_readreg (i2c, state->demod_addr, 0xE4) & 0x02) { - /* Realtime statistics */ - *((u32*) arg) = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7 - | (cx22702_readreg (i2c, state->demod_addr, 0xDF)&0x7F); - } else { - /* Averagtine statistics */ - *((u32*) arg) = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7 - | cx22702_readreg (i2c, state->demod_addr, 0xDF); + return 0; } - break; - case FE_READ_SIGNAL_STRENGTH: +static int cx22702_read_ber(struct dvb_frontend* fe, u32* ber) { - u16 ss = cx22702_readreg (i2c, state->demod_addr, 0x23); - *((u16*) arg) = ss; - break; - } + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - /* We don't have an register for this */ - /* We'll take the inverse of the BER register */ - case FE_READ_SNR: - { - u16 rs_ber=0; - if(cx22702_readreg (i2c, state->demod_addr, 0xE4) & 0x02) { + if(cx22702_readreg (state, 0xE4) & 0x02) { /* Realtime statistics */ - rs_ber = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 7 - | (cx22702_readreg (i2c, state->demod_addr, 0xDF)& 0x7F); + *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 + | (cx22702_readreg (state, 0xDF)&0x7F); } else { - /* Averagine statistics */ - rs_ber = (cx22702_readreg (i2c, state->demod_addr, 0xDE) & 0x7F) << 8 - | cx22702_readreg (i2c, state->demod_addr, 0xDF); - } - *((u16*) arg) = ~rs_ber; - break; + /* Averagtine statistics */ + *ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 + | cx22702_readreg (state, 0xDF); } - case FE_READ_UNCORRECTED_BLOCKS: - /* RS Uncorrectable Packet Count then reset */ - ucblocks = cx22702_readreg (i2c, state->demod_addr, 0xE3); - if (state->prevUCBlocks < ucblocks) *((u32*) arg) = (ucblocks - state->prevUCBlocks); - else *((u32*) arg) = state->prevUCBlocks - ucblocks; - state->prevUCBlocks = ucblocks; - break; - - case FE_SET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - int ret; - - if((ret=cx22702_set_tps (i2c, state, p))<0) { - dprintk ("%s: set_tps failed ret=%d\n",__FUNCTION__,ret); - return ret; - } - break; + return 0; } - case FE_GET_FRONTEND: +static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { - struct dvb_frontend_parameters *p = arg; - u8 reg0C = cx22702_readreg (i2c, state->demod_addr, 0x0C); - - p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; - return cx22702_get_tps (i2c, state, &p->u.ofdm); - } - - case FE_INIT: - return cx22702_init (i2c, state); + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - default: - return -EOPNOTSUPP; - }; + *signal_strength = cx22702_readreg (state, 0x23); return 0; } -/* Validate the eeprom contents, make sure content look ok. - Get the eeprom data. */ -static int cx22702_validate_eeprom(struct i2c_adapter *i2c, int* minfreq, int* pll_type, int* pll_addr, int* demod_addr) -{ - u8 b0 [] = { 0 }; - u8 b1 [128]; - u32 model=0; - u8 tuner=0; - int i,j; - - struct i2c_msg msg [] = { - { .addr = I2C_EEPROM_SLAVE_ADDR, .flags = 0, .buf = b0, .len = 1 }, - { .addr = I2C_EEPROM_SLAVE_ADDR, .flags = I2C_M_RD, .buf = b1, .len = 128 } - }; - - if (i2c_transfer(i2c, msg, 2) != 2) { - printk ("%s i2c eeprom request failed\n", __FUNCTION__); - return -ENODEV; - } - - if(debug) { - dprintk ("i2c eeprom content:\n"); - j=0; - for(i=0;i<128;i++) { - dprintk("%02x ",b1[i]); - if(j++==16) { - dprintk("\n"); - j=0; - } - } - dprintk("\n"); - } +static int cx22702_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - if( (b1[8]!=0x84) || (b1[10]!=0x00) ) { - printk ("%s eeprom content is not valid\n", __FUNCTION__); - return -ENODEV; - } - - /* Make sure we support the board model */ - model = b1[0x1f] << 24 | b1[0x1e] << 16 | b1[0x1d] << 8 | b1[0x1c]; - switch(model) { - case 90002: - case 90500: - case 90501: - dprintk ("%s: Model #%d\n",__FUNCTION__,model); - break; - default: - printk ("%s: Unknown model #%d not supported\n",__FUNCTION__,model); - return -ENODEV; + u16 rs_ber=0; + if(cx22702_readreg (state, 0xE4) & 0x02) { + /* Realtime statistics */ + rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 7 + | (cx22702_readreg (state, 0xDF)& 0x7F); + } else { + /* Averagine statistics */ + rs_ber = (cx22702_readreg (state, 0xDE) & 0x7F) << 8 + | cx22702_readreg (state, 0xDF); } + *snr = ~rs_ber; - /* Make sure we support the tuner */ - tuner = b1[0x2d]; - switch(tuner) { - case 0x4B: - dprintk ("%s: Tuner Thomson DTT 7595\n",__FUNCTION__); - *minfreq = 177000000; - *pll_type = PLLTYPE_DTT7595; - break; - case 0x4C: - dprintk ("%s: Tuner Thomson DTT 7592\n",__FUNCTION__); - *minfreq = 474000000; - *pll_type = PLLTYPE_DTT7592; - break; - default: - printk ("%s: Unknown tuner 0x%02x not supported\n",__FUNCTION__,tuner); - return -ENODEV; - } - *pll_addr = 0x61; - *demod_addr = 0x43; return 0; } - -/* Validate the demod, make sure we understand the hardware */ -static int cx22702_validate_demod(struct i2c_adapter *i2c, int demod_addr) +static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - u8 b0 [] = { 0x1f }; - u8 b1 [] = { 0 }; + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - struct i2c_msg msg [] = { - { .addr = demod_addr, .flags = 0, .buf = b0, .len = 1 }, - { .addr = demod_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 } - }; - - if (i2c_transfer(i2c, msg, 2) != 2) { - printk ("%s i2c demod request failed\n", __FUNCTION__); - return -ENODEV; - } + u8 _ucblocks; - if( (b1[0]!=0x3) ) { - printk ("%s i2c demod type 0x(%02x) not known\n", __FUNCTION__,b1[0]); - return -ENODEV; - } + /* RS Uncorrectable Packet Count then reset */ + _ucblocks = cx22702_readreg (state, 0xE3); + if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks); + else *ucblocks = state->prevUCBlocks - _ucblocks; + state->prevUCBlocks = _ucblocks; return 0; } -/* Validate the tuner PLL, make sure we understand the hardware */ -static int cx22702_validate_pll(struct i2c_adapter *i2c, int pll_addr, int demod_addr) +static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - int result=0; + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; - if( (result=pll_readreg(i2c,pll_addr,demod_addr,0xc2)) < 0) - return result; + u8 reg0C = cx22702_readreg (state, 0x0C); - if( (result >= 0) && (result&0x30) ) - return 0; - - return result; + p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22702_get_tps (state, &p->u.ofdm); } -/* Check we can see the I2c clients */ -static int cx22702_attach_adapter(struct i2c_adapter *adapter) +static void cx22702_release(struct dvb_frontend* fe) { - struct cx22702_state *state; - struct i2c_client *client; - int ret; - int minfreq; - int pll_type; - int pll_addr; - int demod_addr; - - if (0 == (adapter->class & I2C_CLASS_TV_DIGITAL)) { - dprintk("Ignoring adapter 0x%x:%s (no digital tv card).\n", - adapter->id, adapter->name); - return 0; - } - - dprintk("Trying to attach to adapter 0x%x:%s.\n", - adapter->id, adapter->name); - - if (!strcmp(adapter->name, "Conexant DVB-T reference design")) { - printk("cx22702: Detected Conexant DVB-T card - PLL Thomson DTT7579\n"); - pll_type = PLLTYPE_DTT7579; - pll_addr = 0x60; - demod_addr = 0x43; - minfreq = 177000000; // guess - } else { - // default to Hauppauge Nova-T for the moment - printk("cx22702: Detected Hauppauge Nova-T DVB-T - PLL Thomson DTT759x\n"); - ret=cx22702_validate_eeprom(adapter, &minfreq, &pll_type, &pll_addr, &demod_addr); - if(ret < 0) - return ret; - } - - ret=cx22702_validate_demod(adapter, demod_addr); - if(ret < 0) - return ret; - - ret=cx22702_validate_pll(adapter, pll_addr, demod_addr); - if(ret < 0) - return ret; - - if ( !(state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL)) ) - return -ENOMEM; - - memset(state, 0, sizeof(struct cx22702_state)); - state->i2c = adapter; - memcpy(&state->cx22702_info, &cx22702_info, sizeof(struct dvb_frontend_info)); - state->cx22702_info.frequency_min = minfreq; - state->pll_type = pll_type; - state->pll_addr = pll_addr; - state->demod_addr = demod_addr; - - if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) { - kfree(state); - return -ENOMEM; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = state->demod_addr; - i2c_set_clientdata(client, state); - - if ((ret = i2c_attach_client(client))) { - printk("cx22702: attach failed %i\n", ret); - kfree(client); + struct cx22702_state* state = (struct cx22702_state*) fe->demodulator_priv; kfree(state); - return ret; } - return 0; -} -static int cx22702_detach_client(struct i2c_client *client) -{ - struct cx22702_state *state = i2c_get_clientdata(client); - - if (NULL != state->dvb) { - dvb_unregister_frontend (cx22702_ioctl, state->dvb); - state->dvb = NULL; - } - i2c_detach_client(client); - kfree(client); - return 0; -} +static struct dvb_frontend_ops cx22702_ops; -static int command(struct i2c_client *client, unsigned int cmd, void *arg) +struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, + struct i2c_adapter* i2c) { - struct cx22702_state *state = i2c_get_clientdata(client); - int rc; - - switch(cmd) { - case FE_REGISTER: - if (NULL != state->dvb) - break; - state->dvb = arg; - rc = dvb_register_frontend(cx22702_ioctl, state->dvb, state, - &state->cx22702_info, THIS_MODULE); - if (0 != rc) { - printk("cx22702: dvb_register_frontend failed with rc=%d\n",rc); - state->dvb = NULL; - return rc; - } - break; - case FE_UNREGISTER: - if (NULL == state->dvb) - break; - dvb_unregister_frontend (cx22702_ioctl, state->dvb); - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} + struct cx22702_state* state = NULL; -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_CX22702, - .flags = I2C_DF_NOTIFY, - .attach_adapter = cx22702_attach_adapter, - .detach_client = cx22702_detach_client, - .command = command, + /* allocate memory for the internal state */ + state = (struct cx22702_state*) kmalloc(sizeof(struct cx22702_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops)); + state->prevUCBlocks = 0; + + /* check if the demod is there */ + if (cx22702_readreg(state, 0x1f) != 0x3) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops cx22702_ops = { + + .info = { + .name = "Conexant CX22702 DVB-T", + .type = FE_OFDM, + .frequency_min = 177000000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER + }, + + .release = cx22702_release, + + .init = cx22702_init, + + .set_frontend = cx22702_set_tps, + .get_frontend = cx22702_get_frontend, + + .read_status = cx22702_read_status, + .read_ber = cx22702_read_ber, + .read_signal_strength = cx22702_read_signal_strength, + .read_snr = cx22702_read_snr, + .read_ucblocks = cx22702_read_ucblocks, }; -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_cx22702 (void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_cx22702 (void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "cx22702: driver deregistration failed.\n"); -} - -module_init (init_cx22702); -module_exit (exit_cx22702); - -MODULE_PARM(debug,"i"); +module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Enable verbose debug messages"); -MODULE_DESCRIPTION("CX22702 / Thomson DTT 759x / Thomson DTT 7579 PLL DVB Frontend driver"); + +MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); MODULE_AUTHOR("Steven Toth"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(cx22702_attach); diff -Nru a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/cx22702.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,46 @@ +/* + Conexant 22702 DVB OFDM demodulator driver + + based on: + Alps TDMB7 DVB OFDM demodulator driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + Copyright (C) 2004 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 CX22702_H +#define CX22702_H + +#include + +struct cx22702_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, + struct i2c_adapter* i2c); + +#endif // CX22702_H diff -Nru a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c --- a/drivers/media/dvb/frontends/cx24110.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/cx24110.c 2004-12-12 17:40:52 -08:00 @@ -1,6 +1,5 @@ /* cx24110 - Single Chip Satellite Channel Receiver driver module - used on the the Pinnacle PCTV Sat cards Copyright (C) 2002 Peter Hettkamp based on work @@ -23,15 +22,6 @@ */ -/* currently drives the Conexant cx24110 and cx24106 QPSK decoder chips, - connected via i2c to a Conexant Fusion 878 (this uses the standard - linux bttv driver). The tuner chip is supposed to be the Conexant - cx24108 digital satellite tuner, driven through the tuner interface - of the cx24110. SEC is also supplied by the cx24110. - - Oct-2002: Migrate to API V3 (formerly known as NEWSTRUCT) -*/ - #include #include #include @@ -39,44 +29,30 @@ #include #include "dvb_frontend.h" +#include "cx24110.h" -#define FRONTEND_NAME "dvbfe_cx24110" -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) +struct cx24110_state { -static int debug; + struct i2c_adapter* i2c; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + struct dvb_frontend_ops ops; + const struct cx24110_config* config; -static struct dvb_frontend_info cx24110_info = { - .name = "Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1011, /* kHz for QPSK frontends, can be reduced - to 253kHz on the cx24108 tuner */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, -/* .symbol_rate_tolerance = ???,*/ - .notifier_delay = 50, /* 1/20 s */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_RECOVER -}; -/* fixme: are these values correct? especially ..._tolerance and caps */ + struct dvb_frontend frontend; -struct cx24110_state { - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; + u32 lastber; + u32 lastbler; + u32 lastesn0; }; +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "cx24110: " args); \ + } while (0) + static struct {u8 reg; u8 data;} cx24110_regdata[]= /* Comments beginning with @ denote this value should be the default */ @@ -140,15 +116,13 @@ }; -static int cx24110_writereg (struct i2c_adapter *i2c, int reg, int data) +static int cx24110_writereg (struct cx24110_state* state, int reg, int data) { u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 }; -/* fixme (medium): HW allows any i2c address. 0x55 is the default, but the - cx24110 might show up at any address */ + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; int err; - if ((err = i2c_transfer(i2c, &msg, 1)) != 1) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { dprintk ("%s: writereg error (err == %i, reg == 0x%02x," " data == 0x%02x)\n", __FUNCTION__, err, reg, data); return -EREMOTEIO; @@ -158,161 +132,46 @@ } -static u8 cx24110_readreg (struct i2c_adapter *i2c, u8 reg) +static int cx24110_readreg (struct cx24110_state* state, u8 reg) { int ret; u8 b0 [] = { reg }; u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; -/* fixme (medium): address might be different from 0x55 */ - ret = i2c_transfer(i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - - return b1[0]; -} - - -static int cx24108_write (struct i2c_adapter *i2c, u32 data) -{ -/* tuner data is 21 bits long, must be left-aligned in data */ -/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */ -/* FIXME (low): add error handling, avoid infinite loops if HW fails... */ - -dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data); - - cx24110_writereg(i2c,0x6d,0x30); /* auto mode at 62kHz */ - cx24110_writereg(i2c,0x70,0x15); /* auto mode 21 bits */ - /* if the auto tuner writer is still busy, clear it out */ - while (cx24110_readreg(i2c,0x6d)&0x80) - cx24110_writereg(i2c,0x72,0); - /* write the topmost 8 bits */ - cx24110_writereg(i2c,0x72,(data>>24)&0xff); - /* wait for the send to be completed */ - while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80) - ; - /* send another 8 bytes */ - cx24110_writereg(i2c,0x72,(data>>16)&0xff); - while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80) - ; - /* and the topmost 5 bits of this byte */ - cx24110_writereg(i2c,0x72,(data>>8)&0xff); - while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80) - ; - /* now strobe the enable line once */ - cx24110_writereg(i2c,0x6d,0x32); - cx24110_writereg(i2c,0x6d,0x30); - - return 0; -} - - -static int cx24108_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ -/* fixme (low): error handling */ - int i, a, n, pump; - u32 band, pll; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + ret = i2c_transfer(state->i2c, msg, 2); - static const u32 osci[]={ 950000,1019000,1075000,1178000, - 1296000,1432000,1576000,1718000, - 1856000,2036000,2150000}; - static const u32 bandsel[]={0,0x00020000,0x00040000,0x00100800, - 0x00101000,0x00102000,0x00104000, - 0x00108000,0x00110000,0x00120000, - 0x00140000}; - -#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ - dprintk("cx24110 debug: cx24108_set_tv_freq, freq=%d\n",freq); - - if (freq<950000) - freq=950000; /* kHz */ - if (freq>2150000) - freq=2150000; /* satellite IF is 950..2150MHz */ - /* decide which VCO to use for the input frequency */ - for (i=1;(i0) { - cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|rate[fec]); + cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]); /* set nominal Viterbi rate */ - cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|rate[fec]); + cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]); /* set current Viterbi rate */ - cx24110_writereg(i2c,0x1a,g1[fec]); - cx24110_writereg(i2c,0x1b,g2[fec]); + cx24110_writereg(state,0x1a,g1[fec]); + cx24110_writereg(state,0x1b,g2[fec]); /* not sure if this is the right way: I always used AutoAcq mode */ } else return -EOPNOTSUPP; @@ -369,11 +228,11 @@ } -static fe_code_rate_t cx24110_get_fec (struct i2c_adapter *i2c) +static fe_code_rate_t cx24110_get_fec (struct cx24110_state* state) { int i; - i=cx24110_readreg(i2c,0x22)&0x0f; + i=cx24110_readreg(state,0x22)&0x0f; if(!(i&0x08)) { return FEC_1_2 + i - 1; } else { @@ -386,16 +245,13 @@ } -static int cx24110_set_symbolrate (struct i2c_adapter *i2c, u32 srate) +static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) { /* fixme (low): add error handling */ u32 ratio; u32 tmp, fclk, BDRI; static const u32 bands[]={5000000UL,15000000UL,90999000UL/2}; - static const u32 vca[]={0x80f03800,0x81f0f800,0x83f1f800}; - static const u32 vga[]={0x5f8fc000,0x580f0000,0x500c0000}; - static const u8 filtune[]={0xa2,0xcc,0x66}; int i; dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate); @@ -409,22 +265,22 @@ /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz, and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult, R06[3:0] PLLphaseDetGain */ - tmp=cx24110_readreg(i2c,0x07)&0xfc; + tmp=cx24110_readreg(state,0x07)&0xfc; if(srate<90999000UL/4) { /* sample rate 45MHz*/ - cx24110_writereg(i2c,0x07,tmp); - cx24110_writereg(i2c,0x06,0x78); + cx24110_writereg(state,0x07,tmp); + cx24110_writereg(state,0x06,0x78); fclk=90999000UL/2; } else if(srate<60666000UL/2) { /* sample rate 60MHz */ - cx24110_writereg(i2c,0x07,tmp|0x1); - cx24110_writereg(i2c,0x06,0xa5); + cx24110_writereg(state,0x07,tmp|0x1); + cx24110_writereg(state,0x06,0xa5); fclk=60666000UL; } else if(srate<80888000UL/2) { /* sample rate 80MHz */ - cx24110_writereg(i2c,0x07,tmp|0x2); - cx24110_writereg(i2c,0x06,0x87); + cx24110_writereg(state,0x07,tmp|0x2); + cx24110_writereg(state,0x06,0x87); fclk=80888000UL; } else { /* sample rate 90MHz */ - cx24110_writereg(i2c,0x07,tmp|0x3); - cx24110_writereg(i2c,0x06,0x78); + cx24110_writereg(state,0x07,tmp|0x3); + cx24110_writereg(state,0x06,0x78); fclk=90999000UL; }; dprintk("cx24110 debug: fclk %d Hz\n",fclk); @@ -453,64 +309,123 @@ dprintk("fclk = %d\n", fclk); dprintk("ratio= %08x\n", ratio); - cx24110_writereg(i2c, 0x1, (ratio>>16)&0xff); - cx24110_writereg(i2c, 0x2, (ratio>>8)&0xff); - cx24110_writereg(i2c, 0x3, (ratio)&0xff); - - /* please see the cx24108 data sheet, this controls tuner gain - and bandwidth settings depending on the symbol rate */ - cx24108_write(i2c,vga[i]); - cx24108_write(i2c,vca[i]); /* gain is set on tuner chip */ - cx24110_writereg(i2c,0x56,filtune[i]); /* bw is contolled by filtune voltage */ + cx24110_writereg(state, 0x1, (ratio>>16)&0xff); + cx24110_writereg(state, 0x2, (ratio>>8)&0xff); + cx24110_writereg(state, 0x3, (ratio)&0xff); return 0; } -static int cx24110_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage) + + + + + + + + + + +int cx24110_pll_write (struct dvb_frontend* fe, u32 data) { + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + +/* tuner data is 21 bits long, must be left-aligned in data */ +/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */ +/* FIXME (low): add error handling, avoid infinite loops if HW fails... */ + + dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data); + + cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */ + cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */ + + /* if the auto tuner writer is still busy, clear it out */ + while (cx24110_readreg(state,0x6d)&0x80) + cx24110_writereg(state,0x72,0); + + /* write the topmost 8 bits */ + cx24110_writereg(state,0x72,(data>>24)&0xff); + + /* wait for the send to be completed */ + while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) + ; + + /* send another 8 bytes */ + cx24110_writereg(state,0x72,(data>>16)&0xff); + while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) + ; + + /* and the topmost 5 bits of this byte */ + cx24110_writereg(state,0x72,(data>>8)&0xff); + while ((cx24110_readreg(state,0x6d)&0xc0)==0x80) + ; + + /* now strobe the enable line once */ + cx24110_writereg(state,0x6d,0x32); + cx24110_writereg(state,0x6d,0x30); + + return 0; +} + + + +static int cx24110_initfe(struct dvb_frontend* fe) +{ + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; +/* fixme (low): error handling */ + int i; + + dprintk("%s: init chip\n", __FUNCTION__); + + for(i=0;iconfig->pll_init) state->config->pll_init(fe); + + return 0; +} + + +static int cx24110_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + switch (voltage) { case SEC_VOLTAGE_13: - return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0xc0); + return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0xc0); case SEC_VOLTAGE_18: - return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0x40); + return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&0x3b)|0x40); default: return -EINVAL; }; } -static void cx24110_send_diseqc_msg(struct i2c_adapter *i2c, +static int cx24110_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) { int i, rv; + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; for (i = 0; i < cmd->msg_len; i++) - cx24110_writereg(i2c, 0x79 + i, cmd->msg[i]); + cx24110_writereg(state, 0x79 + i, cmd->msg[i]); - rv = cx24110_readreg(i2c, 0x76); + rv = cx24110_readreg(state, 0x76); - cx24110_writereg(i2c, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); - for (i=500; i-- > 0 && !(cx24110_readreg(i2c,0x76)&0x40);) + cx24110_writereg(state, 0x76, ((rv & 0x90) | 0x40) | ((cmd->msg_len-3) & 3)); + for (i=500; i-- > 0 && !(cx24110_readreg(state,0x76)&0x40);) ; /* wait for LNB ready */ -} + return 0; +} -static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int cx24110_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct cx24110_state *state = fe->data; - struct i2c_adapter *i2c = state->i2c; - static int lastber=0, lastbyer=0,lastbler=0, lastesn0=0, sum_bler=0; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &cx24110_info, sizeof(struct dvb_frontend_info)); - break; + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; - case FE_READ_STATUS: - { - fe_status_t *status = arg; - int sync = cx24110_readreg (i2c, 0x55); + int sync = cx24110_readreg (state, 0x55); *status = 0; @@ -520,7 +435,7 @@ if (sync & 0x08) *status |= FE_HAS_CARRIER; - sync = cx24110_readreg (i2c, 0x08); + sync = cx24110_readreg (state, 0x08); if (sync & 0x40) *status |= FE_HAS_VITERBI; @@ -531,87 +446,97 @@ if ((sync & 0x60) == 0x60) *status |= FE_HAS_LOCK; - if(cx24110_readreg(i2c,0x10)&0x40) { - /* the RS error counter has finished one counting window */ - cx24110_writereg(i2c,0x10,0x60); /* select the byer reg */ - lastbyer=cx24110_readreg(i2c,0x12)| - (cx24110_readreg(i2c,0x13)<<8)| - (cx24110_readreg(i2c,0x14)<<16); - cx24110_writereg(i2c,0x10,0x70); /* select the bler reg */ - lastbler=cx24110_readreg(i2c,0x12)| - (cx24110_readreg(i2c,0x13)<<8)| - (cx24110_readreg(i2c,0x14)<<16); - cx24110_writereg(i2c,0x10,0x20); /* start new count window */ - sum_bler += lastbler; - } - if(cx24110_readreg(i2c,0x24)&0x10) { - /* the Viterbi error counter has finished one counting window */ - cx24110_writereg(i2c,0x24,0x04); /* select the ber reg */ - lastber=cx24110_readreg(i2c,0x25)| - (cx24110_readreg(i2c,0x26)<<8); - cx24110_writereg(i2c,0x24,0x04); /* start new count window */ - cx24110_writereg(i2c,0x24,0x14); - } - if(cx24110_readreg(i2c,0x6a)&0x80) { - /* the Es/N0 error counter has finished one counting window */ - lastesn0=cx24110_readreg(i2c,0x69)| - (cx24110_readreg(i2c,0x68)<<8); - cx24110_writereg(i2c,0x6a,0x84); /* start new count window */ - } - break; + return 0; } - case FE_READ_BER: +static int cx24110_read_ber(struct dvb_frontend* fe, u32* ber) { - u32 *ber = (u32 *) arg; + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; - *ber = lastber; /* fixme (maybe): value range is 16 bit. Scale? */ - break; + if(cx24110_readreg(state,0x24)&0x10) { + /* the Viterbi error counter has finished one counting window */ + cx24110_writereg(state,0x24,0x04); /* select the ber reg */ + state->lastber=cx24110_readreg(state,0x25)| + (cx24110_readreg(state,0x26)<<8); + cx24110_writereg(state,0x24,0x04); /* start new count window */ + cx24110_writereg(state,0x24,0x14); } + *ber = state->lastber; - case FE_READ_SIGNAL_STRENGTH: + return 0; + } + +static int cx24110_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) { + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + /* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */ - u8 signal = cx24110_readreg (i2c, 0x27)+128; - *((u16*) arg) = (signal << 8) | signal; - break; + u8 signal = cx24110_readreg (state, 0x27)+128; + *signal_strength = (signal << 8) | signal; + + return 0; } - case FE_READ_SNR: +static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr) { + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */ - *(u16*) arg = lastesn0; - break; + if(cx24110_readreg(state,0x6a)&0x80) { + /* the Es/N0 error counter has finished one counting window */ + state->lastesn0=cx24110_readreg(state,0x69)| + (cx24110_readreg(state,0x68)<<8); + cx24110_writereg(state,0x6a,0x84); /* start new count window */ + } + *snr = state->lastesn0; + + return 0; } - case FE_READ_UNCORRECTED_BLOCKS: +static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - *(u16*) arg = sum_bler&0xffff; - sum_bler=0; - break; + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; + u32 lastbyer; + + if(cx24110_readreg(state,0x10)&0x40) { + /* the RS error counter has finished one counting window */ + cx24110_writereg(state,0x10,0x60); /* select the byer reg */ + lastbyer=cx24110_readreg(state,0x12)| + (cx24110_readreg(state,0x13)<<8)| + (cx24110_readreg(state,0x14)<<16); + cx24110_writereg(state,0x10,0x70); /* select the bler reg */ + state->lastbler=cx24110_readreg(state,0x12)| + (cx24110_readreg(state,0x13)<<8)| + (cx24110_readreg(state,0x14)<<16); + cx24110_writereg(state,0x10,0x20); /* start new count window */ } + *ucblocks = state->lastbler; - case FE_SET_FRONTEND: + return 0; +} + +static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dvb_frontend_parameters *p = arg; + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; - cx24108_set_tv_freq (i2c, p->frequency); - cx24110_set_inversion (i2c, p->inversion); - cx24110_set_fec (i2c, p->u.qpsk.fec_inner); - cx24110_set_symbolrate (i2c, p->u.qpsk.symbol_rate); - cx24110_writereg(i2c,0x04,0x05); /* start aquisition */ - break; + state->config->pll_set(fe, p); + cx24110_set_inversion (state, p->inversion); + cx24110_set_fec (state, p->u.qpsk.fec_inner); + cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); + cx24110_writereg(state,0x04,0x05); /* start aquisition */ + + return 0; } - case FE_GET_FRONTEND: +static int cx24110_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dvb_frontend_parameters *p = arg; + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; s32 afc; unsigned sclk; /* cannot read back tuner settings (freq). Need to have some private storage */ - sclk = cx24110_readreg (i2c, 0x07) & 0x03; + sclk = cx24110_readreg (state, 0x07) & 0x03; /* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz. * Need 64 bit arithmetic. Is thiss possible in the kernel? */ if (sclk==0) sclk=90999000L/2L; @@ -619,152 +544,104 @@ else if (sclk==2) sclk=80888000L; else sclk=90999000L; sclk>>=8; - afc = sclk*(cx24110_readreg (i2c, 0x44)&0x1f)+ - ((sclk*cx24110_readreg (i2c, 0x45))>>8)+ - ((sclk*cx24110_readreg (i2c, 0x46))>>16); + afc = sclk*(cx24110_readreg (state, 0x44)&0x1f)+ + ((sclk*cx24110_readreg (state, 0x45))>>8)+ + ((sclk*cx24110_readreg (state, 0x46))>>16); p->frequency += afc; - p->inversion = (cx24110_readreg (i2c, 0x22) & 0x10) ? + p->inversion = (cx24110_readreg (state, 0x22) & 0x10) ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = cx24110_get_fec (i2c); - break; - } - - case FE_SLEEP: -/* cannot do this from the FE end. How to communicate this to the place where it can be done? */ - break; - case FE_INIT: - return cx24110_initfe(i2c); - - case FE_SET_TONE: - return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0)); - case FE_SET_VOLTAGE: - return cx24110_set_voltage (i2c, (fe_sec_voltage_t) arg); - - case FE_DISEQC_SEND_MASTER_CMD: - // FIXME Status? - cx24110_send_diseqc_msg(i2c, (struct dvb_diseqc_master_cmd*) arg); - return 0; - - default: - return -EOPNOTSUPP; - }; + p->u.qpsk.fec_inner = cx24110_get_fec (state); return 0; } -static struct i2c_client client_template; - -static int attach_adapter (struct i2c_adapter *adapter) +static int cx24110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - struct cx24110_state *state; - struct i2c_client *client; - int ret = 0; - u8 sig; - - dprintk("Trying to attach to adapter 0x%x:%s.\n", - adapter->id, adapter->name); - - sig = cx24110_readreg (adapter, 0x00); - if ( sig != 0x5a && sig != 0x69 ) - return -ENODEV; + struct cx24110_state *state = (struct cx24110_state*) fe->demodulator_priv; - if ( !(state = kmalloc(sizeof(struct cx24110_state), GFP_KERNEL)) ) - return -ENOMEM; - - memset(state, 0, sizeof(struct cx24110_state)); - state->i2c = adapter; - - if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) { - kfree(state); - return -ENOMEM; + return cx24110_writereg(state,0x76,(cx24110_readreg(state,0x76)&~0x10)|(((tone==SEC_TONE_ON))?0x10:0)); } - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = 0x55; - i2c_set_clientdata(client, state); - - if ((ret = i2c_attach_client(client))) { - kfree(client); - kfree(state); - return ret; -} - - BUG_ON(!state->dvb); - - if ((ret = dvb_register_frontend(cx24110_ioctl, state->dvb, state, - &cx24110_info, THIS_MODULE))) { - i2c_detach_client(client); - kfree(client); +static void cx24110_release(struct dvb_frontend* fe) +{ + struct cx24110_state* state = (struct cx24110_state*) fe->demodulator_priv; kfree(state); - return ret; -} - - return 0; } -static int detach_client (struct i2c_client *client) -{ - struct cx24110_state *state = i2c_get_clientdata(client); - - dvb_unregister_frontend(cx24110_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} +static struct dvb_frontend_ops cx24110_ops; -static int command(struct i2c_client *client, unsigned int cmd, void *arg) +struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, + struct i2c_adapter* i2c) { - struct cx24110_state *state = i2c_get_clientdata(client); - - switch(cmd) { - case FE_REGISTER: - state->dvb = arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_CX24110, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; + struct cx24110_state* state = NULL; + int ret; -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + /* allocate memory for the internal state */ + state = (struct cx24110_state*) kmalloc(sizeof(struct cx24110_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops)); + state->lastber = 0; + state->lastbler = 0; + state->lastesn0 = 0; + + /* check if the demod is there */ + ret = cx24110_readreg(state, 0x00); + if ((ret != 0x5a) && (ret != 0x69)) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops cx24110_ops = { + + .info = { + .name = "Conexant CX24110 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1011, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_RECOVER + }, + + .release = cx24110_release, + + .init = cx24110_initfe, + .set_frontend = cx24110_set_frontend, + .get_frontend = cx24110_get_frontend, + .read_status = cx24110_read_status, + .read_ber = cx24110_read_ber, + .read_signal_strength = cx24110_read_signal_strength, + .read_snr = cx24110_read_snr, + .read_ucblocks = cx24110_read_ucblocks, + + .diseqc_send_master_cmd = cx24110_send_diseqc_msg, + .set_tone = cx24110_set_tone, + .set_voltage = cx24110_set_voltage, }; -static int __init cx24110_init(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit cx24110_exit(void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "cx24110: driver deregistration failed.\n"); -} - -module_init(cx24110_init); -module_exit(cx24110_exit); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("DVB Frontend driver module for the Conexant cx24108/cx24110 chipset"); +MODULE_DESCRIPTION("Conexant CX24110 DVB-S Demodulator driver"); MODULE_AUTHOR("Peter Hettkamp"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(cx24110_attach); +EXPORT_SYMBOL(cx24110_pll_write); diff -Nru a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/cx24110.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,45 @@ +/* + cx24110 - Single Chip Satellite Channel Receiver driver module + + Copyright (C) 2002 Peter Hettkamp based on + work + Copyright (C) 1999 Convergence Integrated Media GmbH + + 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 CX24110_H +#define CX24110_H + +#include + +struct cx24110_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, + struct i2c_adapter* i2c); + +extern int cx24110_pll_write(struct dvb_frontend* fe, u32 data); + +#endif // CX24110_H diff -Nru a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/dib3000-common.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,104 @@ +/* + * .h-files for the common use of the frontend drivers made by DiBcom + * DiBcom 3000-MB/MC/P + * + * DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DibCom, which has + * + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * 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. + * + * Acknowledgements + * + * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver + * sources, on which this driver (and the dvb-dibusb) are based. + * + * see Documentation/dvb/README.dibusb for more information + * + */ + +#ifndef DIB3000_COMMON_H +#define DIB3000_COMMON_H + + +/* info and err, taken from usb.h, if there is anything available like by default, + * please change ! + */ +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg) + +/* a PID for the pid_filter list, when in use */ +struct dib3000_pid +{ + u16 pid; + int active; +}; + +/* mask for enabling a specific pid for the pid_filter */ +#define DIB3000_ACTIVATE_PID_FILTERING (0x2000) + +/* common values for tuning */ +#define DIB3000_ALPHA_0 ( 0) +#define DIB3000_ALPHA_1 ( 1) +#define DIB3000_ALPHA_2 ( 2) +#define DIB3000_ALPHA_4 ( 4) + +#define DIB3000_CONSTELLATION_QPSK ( 0) +#define DIB3000_CONSTELLATION_16QAM ( 1) +#define DIB3000_CONSTELLATION_64QAM ( 2) + +#define DIB3000_GUARD_TIME_1_32 ( 0) +#define DIB3000_GUARD_TIME_1_16 ( 1) +#define DIB3000_GUARD_TIME_1_8 ( 2) +#define DIB3000_GUARD_TIME_1_4 ( 3) + +#define DIB3000_TRANSMISSION_MODE_2K ( 0) +#define DIB3000_TRANSMISSION_MODE_8K ( 1) + +#define DIB3000_SELECT_LP ( 0) +#define DIB3000_SELECT_HP ( 1) + +#define DIB3000_FEC_1_2 ( 1) +#define DIB3000_FEC_2_3 ( 2) +#define DIB3000_FEC_3_4 ( 3) +#define DIB3000_FEC_5_6 ( 5) +#define DIB3000_FEC_7_8 ( 7) + +#define DIB3000_HRCH_OFF ( 0) +#define DIB3000_HRCH_ON ( 1) + +#define DIB3000_DDS_INVERSION_OFF ( 0) +#define DIB3000_DDS_INVERSION_ON ( 1) + +#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 7)) +#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 7) | (1 << 7))) + +/* for auto search */ +static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */ + { /* fft */ + { /* gua */ + { 0, 1 }, /* 0 0 { 0,1 } */ + { 3, 9 }, /* 0 1 { 0,1 } */ + }, + { + { 2, 5 }, /* 1 0 { 0,1 } */ + { 6, 11 }, /* 1 1 { 0,1 } */ + } + }; + +#define DIB3000_REG_MANUFACTOR_ID ( 1025) +#define DIB3000_I2C_ID_DIBCOM (0x01b3) + +#define DIB3000_REG_DEVICE_ID ( 1026) +#define DIB3000MB_DEVICE_ID (0x3000) +#define DIB3000MC_DEVICE_ID (0x3001) +#define DIB3000P_DEVICE_ID (0x3002) + +#endif // DIB3000_COMMON_H diff -Nru a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/dib3000.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,53 @@ +/* + * public header file of the frontend drivers for mobile DVB-T demodulators + * DiBcom 3000-MB and DiBcom 3000-MC/P (http://www.dibcom.fr/) + * + * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DibCom, which has + * + * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) + * + * 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. + * + * Acknowledgements + * + * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver + * sources, on which this driver (and the dvb-dibusb) are based. + * + * see Documentation/dvb/README.dibusb for more information + * + */ + +#ifndef DIB3000_H +#define DIB3000_H + +#include + +struct dib3000_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* The i2c address of the PLL */ + u8 pll_addr; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend *fe); + int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params); +}; + +struct dib3000_xfer_ops +{ + /* pid and transfer handling is done in the demodulator */ + int (*pid_filter)(struct dvb_frontend *fe, int onoff); + int (*fifo_ctrl)(struct dvb_frontend *fe, int onoff); + int (*pid_ctrl)(struct dvb_frontend *fe, int pid, int onoff); +}; + +extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, + struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops); + +#endif // DIB3000_H diff -Nru a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c --- a/drivers/media/dvb/frontends/dib3000mb.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/dib3000mb.c 2004-12-12 17:40:52 -08:00 @@ -17,8 +17,6 @@ * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver * sources, on which this driver (and the dvb-dibusb) are based. * - * - * * see Documentation/dvb/README.dibusb for more information * */ @@ -32,8 +30,26 @@ #include #include "dvb_frontend.h" +#include "dib3000-common.h" +#include "dib3000mb_priv.h" +#include "dib3000.h" + +struct dib3000mb_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct dib3000_config* config; + + spinlock_t pid_list_lock; + struct dib3000_pid pid_list[DIB3000MB_NUM_PIDS]; + int feedcount; + + struct dvb_frontend frontend; +}; -#include "dib3000mb.h" /* debug */ @@ -56,34 +72,13 @@ /* Version information */ #define DRIVER_VERSION "0.1" -#define DRIVER_DESC "DiBcom 3000-MB DVB-T frontend" +#define DRIVER_DESC "DiBcom 3000-MB DVB-T demodulator driver" #define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" -struct dib3000mb_state { - struct i2c_client *i2c; - struct dvb_adapter *dvb; - u16 manufactor_id; - u16 device_id; -}; - -static struct dvb_frontend_info dib3000mb_info = { - .name = "DiBcom 3000-MB DVB-T", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; - -#define rd(reg) dib3000mb_read_reg(state->i2c,reg) -#define wr(reg,val) if (dib3000mb_write_reg(state->i2c,reg,val)) \ +/* handy shortcuts */ +#define rd(reg) dib3000mb_read_reg(state,reg) +#define wr(reg,val) if (dib3000mb_write_reg(state,reg,val)) \ { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; } #define wr_foreach(a,v) { int i; \ deb_alot("sizeof: %d %d\n",sizeof(a),sizeof(v));\ @@ -91,228 +86,53 @@ wr(a[i],v[i]); \ } -static u16 dib3000mb_read_reg(struct i2c_client *i2c, u16 reg) +static int dib3000mb_read_reg(struct dib3000mb_state *state, u16 reg) { u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff }; u8 rb[2]; struct i2c_msg msg[] = { - { .addr = i2c->addr, .flags = 0, .buf = wb, .len = 2 }, - { .addr = i2c->addr, .flags = I2C_M_RD, .buf = rb, .len = 2 }, + { .addr = state->config->demod_address, .flags = 0, .buf = wb, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 }, }; deb_alot("reading from i2c bus (reg: %d)\n",reg); - if (i2c_transfer(i2c->adapter,msg,2) != 2) + if (i2c_transfer(state->i2c, msg, 2) != 2) deb_alot("i2c read error\n"); return (rb[0] << 8) | rb[1]; } -static int dib3000mb_write_reg(struct i2c_client *i2c,u16 reg, u16 val) +static int dib3000mb_write_reg(struct dib3000mb_state *state, u16 reg, u16 val) { u8 b[] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff, }; - struct i2c_msg msg[] = { { .addr = i2c->addr, .flags = 0, .buf = b, .len = 4 } }; + struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 4 } }; deb_alot("writing to i2c bus (reg: %d, val: %d)\n",reg,val); - return i2c_transfer(i2c->adapter,msg,1) != 1 ? -EREMOTEIO : 0 ; + return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0; } -static int dib3000mb_tuner_thomson_cable_eu(struct dib3000mb_state *state, - u32 freq) -{ - u32 tfreq = (freq + 36125000) / 62500; - unsigned int addr; - int vu,p0,p1,p2; - - if (freq > 403250000) - vu = 1, p2 = 1, p1 = 0, p0 = 1; - else if (freq > 115750000) - vu = 0, p2 = 1, p1 = 1, p0 = 0; - else if (freq > 44250000) - vu = 0, p2 = 0, p1 = 1, p0 = 1; - else - return -EINVAL; - /* TODO better solution for i2c->addr handling */ - addr = state->i2c->addr; - state->i2c->addr = DIB3000MB_TUNER_ADDR_DEFAULT; - wr(tfreq & 0x7fff,(0x8e << 8) + ((vu << 7) | (p2 << 2) | (p1 << 1) | p0) ); - state->i2c->addr = addr; - - return 0; -} - -static int dib3000mb_get_frontend(struct dib3000mb_state *state, - struct dvb_frontend_parameters *fep) -{ - struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; - fe_code_rate_t *cr; - u16 tps_val; - int inv_test1,inv_test2; - u32 dds_val, threshold = 0x800000; - - if (!rd(DIB3000MB_REG_TPS_LOCK)) - return 0; - - dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB); - if (dds_val & threshold) - inv_test1 = 0; - else if (dds_val == threshold) - inv_test1 = 1; - else - inv_test1 = 2; - - dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB); - if (dds_val & threshold) - inv_test2 = 0; - else if (dds_val == threshold) - inv_test2 = 1; - else - inv_test2 = 2; - - fep->inversion = - ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) - || - ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)); - - deb_getf("inversion %d %d, %d\n",inv_test2,inv_test1, fep->inversion); - - switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { - case DIB3000MB_QAM_QPSK: - deb_getf("QPSK "); - ofdm->constellation = QPSK; - break; - case DIB3000MB_QAM_QAM16: - deb_getf("QAM16 "); - ofdm->constellation = QAM_16; - break; - case DIB3000MB_QAM_QAM64: - deb_getf("QAM64 "); - ofdm->constellation = QAM_64; - break; - default: - err("Unexpected constellation returned by TPS (%d)",tps_val); - break; - } - deb_getf("TPS: %d\n",tps_val); - - if (rd(DIB3000MB_REG_TPS_HRCH)) { - deb_getf("HRCH ON\n"); - tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP); - cr = &ofdm->code_rate_LP; - ofdm->code_rate_HP = FEC_NONE; - - switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { - case DIB3000MB_VIT_ALPHA_OFF: - deb_getf("HIERARCHY_NONE "); - ofdm->hierarchy_information = HIERARCHY_NONE; - break; - case DIB3000MB_VIT_ALPHA_1: - deb_getf("HIERARCHY_1 "); - ofdm->hierarchy_information = HIERARCHY_1; - break; - case DIB3000MB_VIT_ALPHA_2: - deb_getf("HIERARCHY_2 "); - ofdm->hierarchy_information = HIERARCHY_2; - break; - case DIB3000MB_VIT_ALPHA_4: - deb_getf("HIERARCHY_4 "); - ofdm->hierarchy_information = HIERARCHY_4; - break; - default: - err("Unexpected ALPHA value returned by TPS (%d)",tps_val); - } - deb_getf("TPS: %d\n",tps_val); - } else { - deb_getf("HRCH OFF\n"); - tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP); - cr = &ofdm->code_rate_HP; - ofdm->code_rate_LP = FEC_NONE; - ofdm->hierarchy_information = HIERARCHY_NONE; - } - - switch (tps_val) { - case DIB3000MB_FEC_1_2: - deb_getf("FEC_1_2 "); - *cr = FEC_1_2; - break; - case DIB3000MB_FEC_2_3: - deb_getf("FEC_2_3 "); - *cr = FEC_2_3; - break; - case DIB3000MB_FEC_3_4: - deb_getf("FEC_3_4 "); - *cr = FEC_3_4; - break; - case DIB3000MB_FEC_5_6: - deb_getf("FEC_5_6 "); - *cr = FEC_4_5; - break; - case DIB3000MB_FEC_7_8: - deb_getf("FEC_7_8 "); - *cr = FEC_7_8; - break; - default: - err("Unexpected FEC returned by TPS (%d)",tps_val); - break; - } - deb_getf("TPS: %d\n",tps_val); - - switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { - case DIB3000MB_GUARD_TIME_1_32: - deb_getf("GUARD_INTERVAL_1_32 "); - ofdm->guard_interval = GUARD_INTERVAL_1_32; - break; - case DIB3000MB_GUARD_TIME_1_16: - deb_getf("GUARD_INTERVAL_1_16 "); - ofdm->guard_interval = GUARD_INTERVAL_1_16; - break; - case DIB3000MB_GUARD_TIME_1_8: - deb_getf("GUARD_INTERVAL_1_8 "); - ofdm->guard_interval = GUARD_INTERVAL_1_8; - break; - case DIB3000MB_GUARD_TIME_1_4: - deb_getf("GUARD_INTERVAL_1_4 "); - ofdm->guard_interval = GUARD_INTERVAL_1_4; - break; - default: - err("Unexpected Guard Time returned by TPS (%d)",tps_val); - break; - } - deb_getf("TPS: %d\n",tps_val); - - switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { - case DIB3000MB_FFT_2K: - deb_getf("TRANSMISSION_MODE_2K "); - ofdm->transmission_mode = TRANSMISSION_MODE_2K; - break; - case DIB3000MB_FFT_8K: - deb_getf("TRANSMISSION_MODE_8K "); - ofdm->transmission_mode = TRANSMISSION_MODE_8K; - break; - default: - err("unexpected transmission mode return by TPS (%d)",tps_val); - } - deb_getf("TPS: %d\n",tps_val); - return 0; -} - -static int dib3000mb_set_frontend(struct dib3000mb_state *state, +static int dib3000mb_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep, int tuner); -static int dib3000mb_fe_read_search_status(struct dib3000mb_state *state) +static int dib3000mb_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep); + +static int dib3000mb_fe_read_search_status(struct dvb_frontend* fe) { u16 irq; struct dvb_frontend_parameters fep; + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; irq = rd(DIB3000MB_REG_AS_IRQ_PENDING); if (irq & 0x02) { if (rd(DIB3000MB_REG_LOCK2_VALUE) & 0x01) { - if (dib3000mb_get_frontend(state,&fep) == 0) { + if (dib3000mb_get_frontend(fe, &fep) == 0) { deb_setf("reading tuning data from frontend succeeded.\n"); - return dib3000mb_set_frontend(state,&fep,0) == 0; + return dib3000mb_set_frontend(fe, &fep, 0) == 0; } else { deb_setf("reading tuning data failed -> tuning failed.\n"); return 0; @@ -329,22 +149,20 @@ return -1; } -static int dib3000mb_set_frontend(struct dib3000mb_state *state, +static int dib3000mb_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep, int tuner) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t fe_cr = FEC_NONE; int search_state,seq; if (tuner) { wr(DIB3000MB_REG_TUNER, - DIB3000MB_ACTIVATE_TUNER_XFER( DIB3000MB_TUNER_ADDR_DEFAULT ) ); - dib3000mb_tuner_thomson_cable_eu(state,fep->frequency); - - /* wait for tuner */ - msleep(1); + DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr)); + state->config->pll_set(fe, fep); wr(DIB3000MB_REG_TUNER, - DIB3000MB_DEACTIVATE_TUNER_XFER( DIB3000MB_TUNER_ADDR_DEFAULT ) ); + DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr)); deb_setf("bandwidth: "); switch (ofdm->bandwidth) { @@ -376,15 +194,14 @@ switch (ofdm->transmission_mode) { case TRANSMISSION_MODE_2K: deb_setf("2k\n"); - wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_2K); + wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K); break; case TRANSMISSION_MODE_8K: deb_setf("8k\n"); - wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_8K); + wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K); break; case TRANSMISSION_MODE_AUTO: deb_setf("auto\n"); - wr(DIB3000MB_REG_FFT,DIB3000MB_FFT_AUTO); break; default: return -EINVAL; @@ -394,40 +211,39 @@ switch (ofdm->guard_interval) { case GUARD_INTERVAL_1_32: deb_setf("1_32\n"); - wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_32); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32); break; case GUARD_INTERVAL_1_16: deb_setf("1_16\n"); - wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_16); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16); break; case GUARD_INTERVAL_1_8: deb_setf("1_8\n"); - wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_8); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8); break; case GUARD_INTERVAL_1_4: deb_setf("1_4\n"); - wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_1_4); + wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4); break; case GUARD_INTERVAL_AUTO: deb_setf("auto\n"); - wr(DIB3000MB_REG_GUARD_TIME,DIB3000MB_GUARD_TIME_AUTO); break; default: return -EINVAL; } - deb_setf("invsersion: "); + deb_setf("inversion: "); switch (fep->inversion) { - case INVERSION_AUTO: - deb_setf("auto\n"); - break; case INVERSION_OFF: - deb_setf("on\n"); - wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_OFF); + deb_setf("off\n"); + wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF); + break; + case INVERSION_AUTO: + deb_setf("auto "); break; case INVERSION_ON: deb_setf("on\n"); - wr(DIB3000MB_REG_DDS_INV,DIB3000MB_DDS_INV_ON); + wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON); break; default: return -EINVAL; @@ -437,15 +253,15 @@ switch (ofdm->constellation) { case QPSK: deb_setf("qpsk\n"); - wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QPSK); + wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK); break; case QAM_16: deb_setf("qam16\n"); - wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM16); + wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM); break; case QAM_64: deb_setf("qam64\n"); - wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_QAM64); + wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM); break; case QAM_AUTO: break; @@ -456,22 +272,21 @@ switch (ofdm->hierarchy_information) { case HIERARCHY_NONE: deb_setf("none "); - /* fall through alpha is 1, even when HIERARCHY is NONE */ + /* fall through */ case HIERARCHY_1: deb_setf("alpha=1\n"); - wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_1); + wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1); break; case HIERARCHY_2: deb_setf("alpha=2\n"); - wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_2); + wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2); break; case HIERARCHY_4: deb_setf("alpha=4\n"); - wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_4); + wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4); break; case HIERARCHY_AUTO: deb_setf("alpha=auto\n"); - wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_AUTO); break; default: return -EINVAL; @@ -480,39 +295,40 @@ deb_setf("hierarchy: "); if (ofdm->hierarchy_information == HIERARCHY_NONE) { deb_setf("none\n"); - wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_OFF); - wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_HP); + wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF); + wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP); fe_cr = ofdm->code_rate_HP; } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) { deb_setf("on\n"); - wr(DIB3000MB_REG_VIT_HRCH,DIB3000MB_VIT_HRCH_ON); - wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_LP); + wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON); + wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP); fe_cr = ofdm->code_rate_LP; } deb_setf("fec: "); switch (fe_cr) { case FEC_1_2: deb_setf("1_2\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_1_2); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2); break; case FEC_2_3: deb_setf("2_3\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_2_3); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3); break; case FEC_3_4: deb_setf("3_4\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_3_4); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4); break; case FEC_5_6: deb_setf("5_6\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_5_6); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6); break; case FEC_7_8: deb_setf("7_8\n"); - wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_7_8); + wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8); break; case FEC_NONE: deb_setf("none "); + break; case FEC_AUTO: deb_setf("auto\n"); break; @@ -520,7 +336,7 @@ return -EINVAL; } - seq = dib3000mb_seq + seq = dib3000_seq [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO] [ofdm->guard_interval == GUARD_INTERVAL_AUTO] [fep->inversion == INVERSION_AUTO]; @@ -564,6 +380,7 @@ ofdm->hierarchy_information == HIERARCHY_AUTO || fe_cr == FEC_AUTO || fep->inversion == INVERSION_AUTO) { + int as_count=0; deb_setf("autosearch enabled.\n"); @@ -572,20 +389,22 @@ wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_AUTO_SEARCH); wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF); - while ((search_state = dib3000mb_fe_read_search_status(state)) < 0); - deb_info("search_state after autosearch %d\n",search_state); - return search_state ? 0 : -EINVAL; + while ((search_state = dib3000mb_fe_read_search_status(fe)) < 0 && as_count++ < 100) + msleep(1); + + deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count); } else { wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_CTRL); wr(DIB3000MB_REG_RESTART,DIB3000MB_RESTART_OFF); - msleep(70); } + return 0; } - -static int dib3000mb_fe_init(struct dib3000mb_state *state,int mobile_mode) +static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; + wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_UP); wr(DIB3000MB_REG_RESTART, DIB3000MB_RESTART_AGC); @@ -597,9 +416,6 @@ wr(DIB3000MB_REG_ELECT_OUT_MODE,DIB3000MB_ELECT_OUT_MODE_ON); - wr(DIB3000MB_REG_QAM,DIB3000MB_QAM_RESERVED); - wr(DIB3000MB_REG_VIT_ALPHA,DIB3000MB_VIT_ALPHA_AUTO); - wr(DIB3000MB_REG_DDS_FREQ_MSB,DIB3000MB_DDS_FREQ_MSB); wr(DIB3000MB_REG_DDS_FREQ_LSB,DIB3000MB_DDS_FREQ_LSB); @@ -621,7 +437,7 @@ wr(DIB3000MB_REG_LOCK0_MASK,DIB3000MB_LOCK0_DEFAULT); wr(DIB3000MB_REG_LOCK1_MASK,DIB3000MB_LOCK1_SEARCH_4); wr(DIB3000MB_REG_LOCK2_MASK,DIB3000MB_LOCK2_DEFAULT); - wr(DIB3000MB_REG_SEQ,dib3000mb_seq[1][1][1]); + wr(DIB3000MB_REG_SEQ, dib3000_seq[1][1][1]); wr_foreach(dib3000mb_reg_bandwidth,dib3000mb_bandwidth_8mhz); @@ -639,8 +455,6 @@ wr(DIB3000MB_REG_UNK_108,DIB3000MB_UNK_108); wr(DIB3000MB_REG_UNK_122,DIB3000MB_UNK_122); wr(DIB3000MB_REG_MOBILE_MODE_QAM,DIB3000MB_MOBILE_MODE_QAM_OFF); - wr(DIB3000MB_REG_VIT_CODE_RATE,DIB3000MB_FEC_1_2); - wr(DIB3000MB_REG_VIT_HP,DIB3000MB_VIT_HP); wr(DIB3000MB_REG_BERLEN,DIB3000MB_BERLEN_DEFAULT); wr_foreach(dib3000mb_reg_filter_coeffs,dib3000mb_filter_coeffs); @@ -653,17 +467,186 @@ wr(DIB3000MB_REG_FIFO_142,DIB3000MB_FIFO_142); wr(DIB3000MB_REG_MPEG2_OUT_MODE,DIB3000MB_MPEG2_OUT_MODE_188); - wr(DIB3000MB_REG_FIFO_144,DIB3000MB_FIFO_144); + wr(DIB3000MB_REG_PID_PARSE, DIB3000MB_PID_PARSE_ACTIVATE); wr(DIB3000MB_REG_FIFO,DIB3000MB_FIFO_INHIBIT); wr(DIB3000MB_REG_FIFO_146,DIB3000MB_FIFO_146); wr(DIB3000MB_REG_FIFO_147,DIB3000MB_FIFO_147); wr(DIB3000MB_REG_DATA_IN_DIVERSITY,DIB3000MB_DATA_DIVERSITY_IN_OFF); + + if (state->config->pll_init) { + wr(DIB3000MB_REG_TUNER, + DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr)); + state->config->pll_init(fe); + wr(DIB3000MB_REG_TUNER, + DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr)); + } + return 0; } -static int dib3000mb_read_status(struct dib3000mb_state *state,fe_status_t *stat) +static int dib3000mb_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; + struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; + fe_code_rate_t *cr; + u16 tps_val; + int inv_test1,inv_test2; + u32 dds_val, threshold = 0x800000; + + if (!rd(DIB3000MB_REG_TPS_LOCK)) + return 0; + + dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB); + if (dds_val & threshold) + inv_test1 = 0; + else if (dds_val == threshold) + inv_test1 = 1; + else + inv_test1 = 2; + + dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB); + if (dds_val & threshold) + inv_test2 = 0; + else if (dds_val == threshold) + inv_test2 = 1; + else + inv_test2 = 2; + + fep->inversion = + ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) || + ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)); + + deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); + + switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { + case DIB3000_CONSTELLATION_QPSK: + deb_getf("QPSK "); + ofdm->constellation = QPSK; + break; + case DIB3000_CONSTELLATION_16QAM: + deb_getf("QAM16 "); + ofdm->constellation = QAM_16; + break; + case DIB3000_CONSTELLATION_64QAM: + deb_getf("QAM64 "); + ofdm->constellation = QAM_64; + break; + default: + err("Unexpected constellation returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + + if (rd(DIB3000MB_REG_TPS_HRCH)) { + deb_getf("HRCH ON\n"); + tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_LP); + cr = &ofdm->code_rate_LP; + ofdm->code_rate_HP = FEC_NONE; + + switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { + case DIB3000_ALPHA_0: + deb_getf("HIERARCHY_NONE "); + ofdm->hierarchy_information = HIERARCHY_NONE; + break; + case DIB3000_ALPHA_1: + deb_getf("HIERARCHY_1 "); + ofdm->hierarchy_information = HIERARCHY_1; + break; + case DIB3000_ALPHA_2: + deb_getf("HIERARCHY_2 "); + ofdm->hierarchy_information = HIERARCHY_2; + break; + case DIB3000_ALPHA_4: + deb_getf("HIERARCHY_4 "); + ofdm->hierarchy_information = HIERARCHY_4; + break; + default: + err("Unexpected ALPHA value returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + } else { + deb_getf("HRCH OFF\n"); + tps_val = rd(DIB3000MB_REG_TPS_CODE_RATE_HP); + cr = &ofdm->code_rate_HP; + ofdm->code_rate_LP = FEC_NONE; + ofdm->hierarchy_information = HIERARCHY_NONE; + } + + switch (tps_val) { + case DIB3000_FEC_1_2: + deb_getf("FEC_1_2 "); + *cr = FEC_1_2; + break; + case DIB3000_FEC_2_3: + deb_getf("FEC_2_3 "); + *cr = FEC_2_3; + break; + case DIB3000_FEC_3_4: + deb_getf("FEC_3_4 "); + *cr = FEC_3_4; + break; + case DIB3000_FEC_5_6: + deb_getf("FEC_5_6 "); + *cr = FEC_4_5; + break; + case DIB3000_FEC_7_8: + deb_getf("FEC_7_8 "); + *cr = FEC_7_8; + break; + default: + err("Unexpected FEC returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n",tps_val); + + switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { + case DIB3000_GUARD_TIME_1_32: + deb_getf("GUARD_INTERVAL_1_32 "); + ofdm->guard_interval = GUARD_INTERVAL_1_32; + break; + case DIB3000_GUARD_TIME_1_16: + deb_getf("GUARD_INTERVAL_1_16 "); + ofdm->guard_interval = GUARD_INTERVAL_1_16; + break; + case DIB3000_GUARD_TIME_1_8: + deb_getf("GUARD_INTERVAL_1_8 "); + ofdm->guard_interval = GUARD_INTERVAL_1_8; + break; + case DIB3000_GUARD_TIME_1_4: + deb_getf("GUARD_INTERVAL_1_4 "); + ofdm->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + err("Unexpected Guard Time returned by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + + switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { + case DIB3000_TRANSMISSION_MODE_2K: + deb_getf("TRANSMISSION_MODE_2K "); + ofdm->transmission_mode = TRANSMISSION_MODE_2K; + break; + case DIB3000_TRANSMISSION_MODE_8K: + deb_getf("TRANSMISSION_MODE_8K "); + ofdm->transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + err("unexpected transmission mode return by TPS (%d)", tps_val); + break; + } + deb_getf("TPS: %d\n", tps_val); + + return 0; +} + +static int dib3000mb_read_status(struct dvb_frontend* fe, fe_status_t *stat) +{ + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; + *stat = 0; if (rd(DIB3000MB_REG_AGC_LOCK)) @@ -699,8 +682,10 @@ return 0; } -static int dib3000mb_read_ber(struct dib3000mb_state *state,u32 *ber) +static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; + *ber = ((rd(DIB3000MB_REG_BER_MSB) << 16) | rd(DIB3000MB_REG_BER_LSB) ); return 0; } @@ -714,8 +699,10 @@ #define DIB3000MB_AGC_REF_dBm -14 #define DIB3000MB_GAIN_SLOPE_dBm 100 #define DIB3000MB_GAIN_DELTA_dBm -2 -static int dib3000mb_read_signal_strength(struct dib3000mb_state *state, u16 *strength) +static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; + /* TODO log10 u16 sigpow = rd(DIB3000MB_REG_SIGNAL_POWER), n_agc_power = rd(DIB3000MB_REG_AGC_POWER), @@ -748,8 +735,9 @@ * If SNR is above 20dB, BER should be always 0. * choose 0dB as the minimum */ -static int dib3000mb_read_snr(struct dib3000mb_state *state,u16 *snr) +static int dib3000mb_read_snr(struct dvb_frontend* fe, u16 *snr) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; short sigpow = rd(DIB3000MB_REG_SIGNAL_POWER); int icipow = ((rd(DIB3000MB_REG_NOISE_POWER_MSB) & 0xff) << 16) | rd(DIB3000MB_REG_NOISE_POWER_LSB); @@ -763,24 +751,27 @@ *snr = (u16) ((snr_dBm / 35) * 0xffff); */ - *snr = (sigpow<<8) / (icipow > 0 ? icipow : 1); + *snr = (sigpow << 8) / ((icipow > 0) ? icipow : 1); return 0; } -static int dib3000mb_read_unc_blocks(struct dib3000mb_state *state,u32 *unc) +static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; + *unc = rd(DIB3000MB_REG_UNC); return 0; } -static int dib3000mb_sleep(struct dib3000mb_state *state) +static int dib3000mb_sleep(struct dvb_frontend* fe) { + struct dib3000mb_state* state = (struct dib3000mb_state*) fe->demodulator_priv; + wr(DIB3000MB_REG_POWER_CONTROL,DIB3000MB_POWER_DOWN); return 0; } -static int dib3000mb_fe_get_tune_settings(struct dib3000mb_state *state, - struct dvb_frontend_tune_settings *tune) +static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 800; tune->step_size = 166667; @@ -789,205 +780,176 @@ return 0; } -static int dib3000mb_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int dib3000mb_fe_init_nonmobile(struct dvb_frontend* fe) { - struct dib3000mb_state *state = fe->data; - switch (cmd) { - case FE_GET_INFO: - deb_info("FE_GET_INFO\n"); - memcpy(arg, &dib3000mb_info, sizeof(struct dvb_frontend_info)); - return 0; - break; - - case FE_READ_STATUS: - deb_info("FE_READ_STATUS\n"); - return dib3000mb_read_status(state,(fe_status_t *)arg); - break; - - case FE_READ_BER: - deb_info("FE_READ_BER\n"); - return dib3000mb_read_ber(state,(u32 *)arg); - break; - - case FE_READ_SIGNAL_STRENGTH: - deb_info("FE_READ_SIG_STRENGTH\n"); - return dib3000mb_read_signal_strength(state,(u16 *) arg); - break; - - case FE_READ_SNR: - deb_info("FE_READ_SNR\n"); - return dib3000mb_read_snr(state,(u16 *) arg); - break; - - case FE_READ_UNCORRECTED_BLOCKS: - deb_info("FE_READ_UNCORRECTED_BLOCKS\n"); - return dib3000mb_read_unc_blocks(state,(u32 *) arg); - break; - - case FE_SET_FRONTEND: - deb_info("FE_SET_FRONTEND\n"); - return dib3000mb_set_frontend(state,(struct dvb_frontend_parameters *) arg,1); - break; - - case FE_GET_FRONTEND: - deb_info("FE_GET_FRONTEND\n"); - return dib3000mb_get_frontend(state,(struct dvb_frontend_parameters *) arg); - break; + return dib3000mb_fe_init(fe, 0); +} - case FE_SLEEP: - deb_info("FE_SLEEP\n"); - return dib3000mb_sleep(state); - break; +static int dib3000mb_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) +{ + return dib3000mb_set_frontend(fe, fep, 1); +} - case FE_INIT: - deb_info("FE_INIT\n"); - return dib3000mb_fe_init(state,0); - break; +static void dib3000mb_release(struct dvb_frontend* fe) +{ + struct dib3000mb_state *state = (struct dib3000mb_state*) fe->demodulator_priv; + kfree(state); +} - case FE_GET_TUNE_SETTINGS: - deb_info("GET_TUNE_SETTINGS"); - return dib3000mb_fe_get_tune_settings(state, (struct - dvb_frontend_tune_settings *) arg); +/* pid filter and transfer stuff */ +/* fetch a pid from pid_list */ +static int dib3000_get_pid_index(struct dib3000_pid pid_list[], + int num_pids, int pid, spinlock_t *pid_list_lock,int onoff) +{ + int i,ret = -1; + unsigned long flags; + + spin_lock_irqsave(pid_list_lock,flags); + for (i=0; i < num_pids; i++) + if (onoff) { + if (!pid_list[i].active) { + pid_list[i].pid = pid; + pid_list[i].active = 1; + ret = i; break; - case FE_SET_TONE: - case FE_SET_VOLTAGE: - default: - return -EOPNOTSUPP; + } + } else { + if (pid_list[i].active && pid_list[i].pid == pid) { + pid_list[i].pid = 0; + pid_list[i].active = 0; + ret = i; break; } - return 0; } -static struct i2c_client client_template; + spin_unlock_irqrestore(pid_list_lock,flags); + return ret; +} -static int dib3000mb_attach_adapter(struct i2c_adapter *adapter) +static int dib3000mb_pid_control(struct dvb_frontend *fe,int pid,int onoff) { - struct i2c_client *client; - struct dib3000mb_state *state; - int ret = -ENOMEM; + struct dib3000mb_state *state = fe->demodulator_priv; + int index = dib3000_get_pid_index(state->pid_list, DIB3000MB_NUM_PIDS, pid, &state->pid_list_lock,onoff); + pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); - deb_info("i2c probe with adapter '%s'.\n",adapter->name); + deb_info("setting pid 0x%x on index %d\n",pid,index); - if ((state = kmalloc(sizeof(struct dib3000mb_state),GFP_KERNEL)) == NULL) + if (index >= 0) { + wr(index+DIB3000MB_REG_FIRST_PID,pid); + } else { + err("no more pids for filtering."); return -ENOMEM; + } + return 0; +} +static int dib3000mb_fifo_control(struct dvb_frontend *fe, int onoff) +{ + struct dib3000mb_state *state = (struct dib3000mb_state*) fe->demodulator_priv; - if ((client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL) - goto i2c_kmalloc_err; - - memcpy(client, &client_template, sizeof(struct i2c_client)); - - client->adapter = adapter; - client->addr = 0x10; - state->i2c = client; - - i2c_set_clientdata(client,state); - - state->manufactor_id = dib3000mb_read_reg(client, DIB3000MB_REG_MANUFACTOR_ID); - if (state->manufactor_id != 0x01b3) { - ret = -ENODEV; - goto probe_err; + if (onoff) { + wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_ACTIVATE); + } else { + wr(DIB3000MB_REG_FIFO, DIB3000MB_FIFO_INHIBIT); } - - state->device_id = dib3000mb_read_reg(client,DIB3000MB_REG_DEVICE_ID); - if (state->device_id != 0x3000) { - ret = -ENODEV; - goto probe_err; + return 0; } - info("found a DiBCom (0x%04x) 3000-MB DVB-T frontend (ver: %x).", - state->manufactor_id, state->device_id); - - if ((ret = i2c_attach_client(client))) - goto i2c_attach_err; - - if (state->dvb == NULL) - goto i2c_attach_err; - - if ((ret = dvb_register_frontend(dib3000mb_ioctl, state->dvb, state, - &dib3000mb_info, THIS_MODULE))) - goto dvb_fe_err; - - - goto success; -dvb_fe_err: - i2c_detach_client(client); -i2c_attach_err: -probe_err: - kfree(client); -i2c_kmalloc_err: - kfree(state); - return ret; -success: +static int dib3000mb_pid_filter(struct dvb_frontend *fe, int onoff) +{ + //struct dib3000mb_state *state = fe->demodulator_priv; + /* switch it off and on */ return 0; -} + } +static struct dvb_frontend_ops dib3000mb_ops; -static int dib3000mb_detach_client(struct i2c_client *client) +struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, + struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops) { - struct dib3000mb_state *state = i2c_get_clientdata(client); + struct dib3000mb_state* state = NULL; + int i; - deb_info("i2c detach\n"); + /* allocate memory for the internal state */ + state = (struct dib3000mb_state*) kmalloc(sizeof(struct dib3000mb_state), GFP_KERNEL); + if (state == NULL) + goto error; - dvb_unregister_frontend(dib3000mb_ioctl, state->dvb); - i2c_detach_client(client); - kfree(client); - kfree(state); + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops)); - return 0; -} + /* check for the correct demod */ + if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) + goto error; -static int dib3000mb_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct dib3000mb_state *state = i2c_get_clientdata(client); - deb_info("i2c command.\n"); - switch(cmd) { - case FE_REGISTER: - state->dvb = arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } + if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID) + goto error; - return 0; + /* initialize the id_list */ + deb_info("initializing %d pids for the pid_list.\n",DIB3000MB_NUM_PIDS); + state->pid_list_lock = SPIN_LOCK_UNLOCKED; + memset(state->pid_list,0,DIB3000MB_NUM_PIDS*(sizeof(struct dib3000_pid))); + for (i=0; i < DIB3000MB_NUM_PIDS; i++) { + state->pid_list[i].pid = 0; + state->pid_list[i].active = 0; } + state->feedcount = 0; -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "dib3000mb", - .id = I2C_DRIVERID_DVBFE_DIB3000MB, - .flags = I2C_DF_NOTIFY, - .attach_adapter = dib3000mb_attach_adapter, - .detach_client = dib3000mb_detach_client, - .command = dib3000mb_command, -}; + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; -static struct i2c_client client_template = { - .name = "dib3000mb", - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; + /* set the xfer operations */ + xfer_ops->pid_filter = dib3000mb_pid_filter; + xfer_ops->fifo_ctrl = dib3000mb_fifo_control; + xfer_ops->pid_ctrl = dib3000mb_pid_control; -/* module stuff */ -static int __init dib3000mb_init(void) -{ - deb_info("debugging level: %d\n",debug); - return i2c_add_driver(&driver); -} + return &state->frontend; -static void __exit dib3000mb_exit(void) -{ - i2c_del_driver(&driver); -} +error: + if (state) + kfree(state); + return NULL; + } -module_init (dib3000mb_init); -module_exit (dib3000mb_exit); +static struct dvb_frontend_ops dib3000mb_ops = { + + .info = { + .name = "DiBcom 3000-MB DVB-T", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib3000mb_release, + + .init = dib3000mb_fe_init_nonmobile, + .sleep = dib3000mb_sleep, + + .set_frontend = dib3000mb_set_frontend_and_tuner, + .get_frontend = dib3000mb_get_frontend, + .get_tune_settings = dib3000mb_fe_get_tune_settings, + + .read_status = dib3000mb_read_status, + .read_ber = dib3000mb_read_ber, + .read_signal_strength = dib3000mb_read_signal_strength, + .read_snr = dib3000mb_read_snr, + .read_ucblocks = dib3000mb_read_unc_blocks, +}; MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(dib3000mb_attach); diff -Nru a/drivers/media/dvb/frontends/dib3000mb.h b/drivers/media/dvb/frontends/dib3000mb.h --- a/drivers/media/dvb/frontends/dib3000mb.h 2004-12-12 17:40:52 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,657 +0,0 @@ -/* - * dib3000mb.h - * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.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, version 2. - * - * - * - * for more information see dib3000mb.c . - */ - -#ifndef __DIB3000MB_H_INCLUDED__ -#define __DIB3000MB_H_INCLUDED__ - -/* info and err, taken from usb.h, if there is anything available like by default, - * please change ! - */ -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg) - -/* register addresses and some of their default values */ - -/* restart subsystems */ -#define DIB3000MB_REG_RESTART ( 0) - -#define DIB3000MB_RESTART_OFF ( 0) -#define DIB3000MB_RESTART_AUTO_SEARCH (1 << 1) -#define DIB3000MB_RESTART_CTRL (1 << 2) -#define DIB3000MB_RESTART_AGC (1 << 3) - -/* FFT size */ -#define DIB3000MB_REG_FFT ( 1) -#define DIB3000MB_FFT_2K ( 0) -#define DIB3000MB_FFT_8K ( 1) -#define DIB3000MB_FFT_AUTO ( 1) - -/* Guard time */ -#define DIB3000MB_REG_GUARD_TIME ( 2) -#define DIB3000MB_GUARD_TIME_1_32 ( 0) -#define DIB3000MB_GUARD_TIME_1_16 ( 1) -#define DIB3000MB_GUARD_TIME_1_8 ( 2) -#define DIB3000MB_GUARD_TIME_1_4 ( 3) -#define DIB3000MB_GUARD_TIME_AUTO ( 0) - -/* QAM */ -#define DIB3000MB_REG_QAM ( 3) -#define DIB3000MB_QAM_QPSK ( 0) -#define DIB3000MB_QAM_QAM16 ( 1) -#define DIB3000MB_QAM_QAM64 ( 2) -#define DIB3000MB_QAM_RESERVED ( 3) - -/* Alpha coefficient high priority Viterbi algorithm */ -#define DIB3000MB_REG_VIT_ALPHA ( 4) -#define DIB3000MB_VIT_ALPHA_OFF ( 0) -#define DIB3000MB_VIT_ALPHA_1 ( 1) -#define DIB3000MB_VIT_ALPHA_2 ( 2) -#define DIB3000MB_VIT_ALPHA_4 ( 4) -#define DIB3000MB_VIT_ALPHA_AUTO ( 7) - -/* spectrum inversion */ -#define DIB3000MB_REG_DDS_INV ( 5) -#define DIB3000MB_DDS_INV_OFF ( 0) -#define DIB3000MB_DDS_INV_ON ( 1) - -/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */ -#define DIB3000MB_REG_DDS_FREQ_MSB ( 6) -#define DIB3000MB_REG_DDS_FREQ_LSB ( 7) -#define DIB3000MB_DDS_FREQ_MSB ( 178) -#define DIB3000MB_DDS_FREQ_LSB ( 8990) - -/* timing frequency (carrier spacing) */ -#define DIB3000MB_REG_TIMING_FREQ_MSB ( 8) -#define DIB3000MB_REG_TIMING_FREQ_LSB ( 9) - -static u16 dib3000mb_reg_timing_freq[] = { - DIB3000MB_REG_TIMING_FREQ_MSB, DIB3000MB_REG_TIMING_FREQ_LSB -}; -static u16 dib3000mb_timing_freq[][2] = { - { 126 , 48873 }, /* 6 MHz */ - { 147 , 57019 }, /* 7 MHz */ - { 168 , 65164 }, /* 8 MHz */ -}; - -/* impulse noise parameter */ -#define DIB3000MB_REG_IMPNOISE_10 ( 10) -#define DIB3000MB_REG_IMPNOISE_11 ( 11) -#define DIB3000MB_REG_IMPNOISE_12 ( 12) -#define DIB3000MB_REG_IMPNOISE_13 ( 13) -#define DIB3000MB_REG_IMPNOISE_14 ( 14) -#define DIB3000MB_REG_IMPNOISE_15 ( 15) -/* 36 ??? */ -#define DIB3000MB_REG_IMPNOISE_36 ( 36) - -enum dib3000mb_impulse_noise_type { - DIB3000MB_IMPNOISE_OFF, - DIB3000MB_IMPNOISE_MOBILE, - DIB3000MB_IMPNOISE_FIXED, - DIB3000MB_IMPNOISE_DEFAULT -}; - -static u16 dib3000mb_reg_impulse_noise[] = { - DIB3000MB_REG_IMPNOISE_10, DIB3000MB_REG_IMPNOISE_11, - DIB3000MB_REG_IMPNOISE_12, DIB3000MB_REG_IMPNOISE_15, - DIB3000MB_REG_IMPNOISE_36 -}; - -static u16 dib3000mb_impulse_noise_values[][5] = { - { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */ - { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */ - { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */ - { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */ -}; - -/* - * Dual Automatic-Gain-Control - * - gains RF in tuner (AGC1) - * - gains IF after filtering (AGC2) - */ - -/* also from 16 to 18 */ -#define DIB3000MB_REG_AGC_GAIN_19 ( 19) -#define DIB3000MB_REG_AGC_GAIN_20 ( 20) -#define DIB3000MB_REG_AGC_GAIN_21 ( 21) -#define DIB3000MB_REG_AGC_GAIN_22 ( 22) -#define DIB3000MB_REG_AGC_GAIN_23 ( 23) -#define DIB3000MB_REG_AGC_GAIN_24 ( 24) -#define DIB3000MB_REG_AGC_GAIN_25 ( 25) -#define DIB3000MB_REG_AGC_GAIN_26 ( 26) -#define DIB3000MB_REG_AGC_GAIN_27 ( 27) -#define DIB3000MB_REG_AGC_GAIN_28 ( 28) -#define DIB3000MB_REG_AGC_GAIN_29 ( 29) -#define DIB3000MB_REG_AGC_GAIN_30 ( 30) -#define DIB3000MB_REG_AGC_GAIN_31 ( 31) -#define DIB3000MB_REG_AGC_GAIN_32 ( 32) - -static u16 dib3000mb_reg_agc_gain[] = { - DIB3000MB_REG_AGC_GAIN_19, DIB3000MB_REG_AGC_GAIN_20, DIB3000MB_REG_AGC_GAIN_21, - DIB3000MB_REG_AGC_GAIN_22, DIB3000MB_REG_AGC_GAIN_23, DIB3000MB_REG_AGC_GAIN_24, - DIB3000MB_REG_AGC_GAIN_25, DIB3000MB_REG_AGC_GAIN_26, DIB3000MB_REG_AGC_GAIN_27, - DIB3000MB_REG_AGC_GAIN_28, DIB3000MB_REG_AGC_GAIN_29, DIB3000MB_REG_AGC_GAIN_30, - DIB3000MB_REG_AGC_GAIN_31, DIB3000MB_REG_AGC_GAIN_32 }; - -static u16 dib3000mb_default_agc_gain[] = - { 0x0001, 52429, 623, 128, 166, 195, 61, /* RF ??? */ - 0x0001, 53766, 38011, 0, 90, 33, 23 }; /* IF ??? */ - -/* phase noise */ -#define DIB3000MB_REG_PHASE_NOISE_33 ( 33) -#define DIB3000MB_REG_PHASE_NOISE_34 ( 34) -#define DIB3000MB_REG_PHASE_NOISE_35 ( 35) -#define DIB3000MB_REG_PHASE_NOISE_36 ( 36) -#define DIB3000MB_REG_PHASE_NOISE_37 ( 37) -#define DIB3000MB_REG_PHASE_NOISE_38 ( 38) - -/* DIB3000MB_REG_PHASE_NOISE_36 is set when setting the impulse noise */ -static u16 dib3000mb_reg_phase_noise[] = { - DIB3000MB_REG_PHASE_NOISE_33, DIB3000MB_REG_PHASE_NOISE_34, DIB3000MB_REG_PHASE_NOISE_35, - DIB3000MB_REG_PHASE_NOISE_37, DIB3000MB_REG_PHASE_NOISE_38 -}; - -static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 }; - -/* lock duration */ -#define DIB3000MB_REG_LOCK_DURATION_39 ( 39) -#define DIB3000MB_REG_LOCK_DURATION_40 ( 40) - -static u16 dib3000mb_reg_lock_duration[] = { - DIB3000MB_REG_LOCK_DURATION_39, DIB3000MB_REG_LOCK_DURATION_40 -}; - -static u16 dib3000mb_default_lock_duration[] = { 135, 135 }; - -/* AGC loop bandwidth */ - -#define DIB3000MB_REG_AGC_BW_43 ( 43) -#define DIB3000MB_REG_AGC_BW_44 ( 44) -#define DIB3000MB_REG_AGC_BW_45 ( 45) -#define DIB3000MB_REG_AGC_BW_46 ( 46) -#define DIB3000MB_REG_AGC_BW_47 ( 47) -#define DIB3000MB_REG_AGC_BW_48 ( 48) -#define DIB3000MB_REG_AGC_BW_49 ( 49) -#define DIB3000MB_REG_AGC_BW_50 ( 50) - -static u16 dib3000mb_reg_agc_bandwidth[] = { - DIB3000MB_REG_AGC_BW_43, DIB3000MB_REG_AGC_BW_44, DIB3000MB_REG_AGC_BW_45, - DIB3000MB_REG_AGC_BW_46, DIB3000MB_REG_AGC_BW_47, DIB3000MB_REG_AGC_BW_48, - DIB3000MB_REG_AGC_BW_49, DIB3000MB_REG_AGC_BW_50 -}; - -static u16 dib3000mb_agc_bandwidth_low[] = - { 2088, 10, 2088, 10, 3448, 5, 3448, 5 }; -static u16 dib3000mb_agc_bandwidth_high[] = - { 2349, 5, 2349, 5, 2586, 2, 2586, 2 }; - -/* - * lock0 definition (coff_lock) - */ -#define DIB3000MB_REG_LOCK0_MASK ( 51) -#define DIB3000MB_LOCK0_DEFAULT ( 4) - -/* - * lock1 definition (cpil_lock) - * for auto search - * which values hide behind the lock masks - */ -#define DIB3000MB_REG_LOCK1_MASK ( 52) -#define DIB3000MB_LOCK1_SEARCH_4 (0x0004) -#define DIB3000MB_LOCK1_SEARCH_2048 (0x0800) -#define DIB3000MB_LOCK1_DEFAULT (0x0001) - -/* - * lock2 definition (fec_lock) */ -#define DIB3000MB_REG_LOCK2_MASK ( 53) -#define DIB3000MB_LOCK2_DEFAULT (0x0080) - -/* - * SEQ ? what was that again ... :) - * changes when, inversion, guard time and fft is - * either automatically detected or not - */ -#define DIB3000MB_REG_SEQ ( 54) - -/* all values have been set manually */ -static u16 dib3000mb_seq[2][2][2] = /* fft,gua, inv */ - { /* fft */ - { /* gua */ - { 0, 1 }, /* 0 0 { 0,1 } */ - { 3, 9 }, /* 0 1 { 0,1 } */ - }, - { - { 2, 5 }, /* 1 0 { 0,1 } */ - { 6, 11 }, /* 1 1 { 0,1 } */ - } - }; - -/* bandwidth */ -#define DIB3000MB_REG_BW_55 ( 55) -#define DIB3000MB_REG_BW_56 ( 56) -#define DIB3000MB_REG_BW_57 ( 57) -#define DIB3000MB_REG_BW_58 ( 58) -#define DIB3000MB_REG_BW_59 ( 59) -#define DIB3000MB_REG_BW_60 ( 60) -#define DIB3000MB_REG_BW_61 ( 61) -#define DIB3000MB_REG_BW_62 ( 62) -#define DIB3000MB_REG_BW_63 ( 63) -#define DIB3000MB_REG_BW_64 ( 64) -#define DIB3000MB_REG_BW_65 ( 65) -#define DIB3000MB_REG_BW_66 ( 66) -#define DIB3000MB_REG_BW_67 ( 67) - -static u16 dib3000mb_reg_bandwidth[] = { - DIB3000MB_REG_BW_55, DIB3000MB_REG_BW_56, DIB3000MB_REG_BW_57, - DIB3000MB_REG_BW_58, DIB3000MB_REG_BW_59, DIB3000MB_REG_BW_60, - DIB3000MB_REG_BW_61, DIB3000MB_REG_BW_62, DIB3000MB_REG_BW_63, - DIB3000MB_REG_BW_64, DIB3000MB_REG_BW_65, DIB3000MB_REG_BW_66, - DIB3000MB_REG_BW_67 -}; - -static u16 dib3000mb_bandwidth_6mhz[] = - { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 }; - -static u16 dib3000mb_bandwidth_7mhz[] = - { 0, 28, 64421, 96, 39973, 483, 3255, 0, 1000, 0, 1010, 1, 45264 }; - -static u16 dib3000mb_bandwidth_8mhz[] = - { 0, 25, 23600, 84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 }; - -#define DIB3000MB_REG_UNK_68 ( 68) -#define DIB3000MB_UNK_68 ( 0) - -#define DIB3000MB_REG_UNK_69 ( 69) -#define DIB3000MB_UNK_69 ( 0) - -#define DIB3000MB_REG_UNK_71 ( 71) -#define DIB3000MB_UNK_71 ( 0) - -#define DIB3000MB_REG_UNK_77 ( 77) -#define DIB3000MB_UNK_77 ( 6) - -#define DIB3000MB_REG_UNK_78 ( 78) -#define DIB3000MB_UNK_78 (0x0080) - -/* isi */ -#define DIB3000MB_REG_ISI ( 79) -#define DIB3000MB_ISI_ACTIVATE ( 0) -#define DIB3000MB_ISI_INHIBIT ( 1) - -/* sync impovement */ -#define DIB3000MB_REG_SYNC_IMPROVEMENT ( 84) -#define DIB3000MB_SYNC_IMPROVE_2K_1_8 ( 3) -#define DIB3000MB_SYNC_IMPROVE_DEFAULT ( 0) - -/* phase noise compensation inhibition */ -#define DIB3000MB_REG_PHASE_NOISE ( 87) -#define DIB3000MB_PHASE_NOISE_DEFAULT ( 0) - -#define DIB3000MB_REG_UNK_92 ( 92) -#define DIB3000MB_UNK_92 (0x0080) - -#define DIB3000MB_REG_UNK_96 ( 96) -#define DIB3000MB_UNK_96 (0x0010) - -#define DIB3000MB_REG_UNK_97 ( 97) -#define DIB3000MB_UNK_97 (0x0009) - -/* mobile mode ??? */ -#define DIB3000MB_REG_MOBILE_MODE ( 101) -#define DIB3000MB_MOBILE_MODE_ON ( 1) -#define DIB3000MB_MOBILE_MODE_OFF ( 0) - -#define DIB3000MB_REG_UNK_106 ( 106) -#define DIB3000MB_UNK_106 (0x0080) - -#define DIB3000MB_REG_UNK_107 ( 107) -#define DIB3000MB_UNK_107 (0x0080) - -#define DIB3000MB_REG_UNK_108 ( 108) -#define DIB3000MB_UNK_108 (0x0080) - -/* fft */ -#define DIB3000MB_REG_UNK_121 ( 121) -#define DIB3000MB_UNK_121_2K ( 7) -#define DIB3000MB_UNK_121_DEFAULT ( 5) - -#define DIB3000MB_REG_UNK_122 ( 122) -#define DIB3000MB_UNK_122 ( 2867) - -/* QAM for mobile mode */ -#define DIB3000MB_REG_MOBILE_MODE_QAM ( 126) -#define DIB3000MB_MOBILE_MODE_QAM_64 ( 3) -#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16 ( 1) -#define DIB3000MB_MOBILE_MODE_QAM_OFF ( 0) - -/* - * data diversity when having more than one chip on-board - * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY - */ -#define DIB3000MB_REG_DATA_IN_DIVERSITY ( 127) -#define DIB3000MB_DATA_DIVERSITY_IN_OFF ( 0) -#define DIB3000MB_DATA_DIVERSITY_IN_ON ( 2) - -/* vit hrch */ -#define DIB3000MB_REG_VIT_HRCH ( 128) -#define DIB3000MB_VIT_HRCH_ON ( 1) -#define DIB3000MB_VIT_HRCH_OFF ( 0) - -/* vit code rate */ -#define DIB3000MB_REG_VIT_CODE_RATE ( 129) - -/* forward error correction code rates */ -#define DIB3000MB_FEC_1_2 ( 1) -#define DIB3000MB_FEC_2_3 ( 2) -#define DIB3000MB_FEC_3_4 ( 3) -#define DIB3000MB_FEC_5_6 ( 5) -#define DIB3000MB_FEC_7_8 ( 7) - -/* vit select hp */ -#define DIB3000MB_REG_VIT_HP ( 130) -#define DIB3000MB_VIT_LP ( 0) -#define DIB3000MB_VIT_HP ( 1) - -/* time frame for Bit-Error-Rate calculation */ -#define DIB3000MB_REG_BERLEN ( 135) -#define DIB3000MB_BERLEN_LONG ( 0) -#define DIB3000MB_BERLEN_DEFAULT ( 1) -#define DIB3000MB_BERLEN_MEDIUM ( 2) -#define DIB3000MB_BERLEN_SHORT ( 3) - -/* 142 - 152 FIFO parameters - * which is what ? - */ - -#define DIB3000MB_REG_FIFO_142 ( 142) -#define DIB3000MB_FIFO_142 ( 0) - -/* MPEG2 TS output mode */ -#define DIB3000MB_REG_MPEG2_OUT_MODE ( 143) -#define DIB3000MB_MPEG2_OUT_MODE_204 ( 0) -#define DIB3000MB_MPEG2_OUT_MODE_188 ( 1) - -#define DIB3000MB_REG_FIFO_144 ( 144) -#define DIB3000MB_FIFO_144 ( 1) - -#define DIB3000MB_REG_FIFO ( 145) -#define DIB3000MB_FIFO_INHIBIT ( 1) -#define DIB3000MB_FIFO_ACTIVATE ( 0) - -#define DIB3000MB_REG_FIFO_146 ( 146) -#define DIB3000MB_FIFO_146 ( 3) - -#define DIB3000MB_REG_FIFO_147 ( 147) -#define DIB3000MB_FIFO_147 (0x0100) - -/* - * pidfilter - * it is not a hardware pidfilter but a filter which drops all pids - * except the ones set. Necessary because of the limited USB1.1 bandwidth. - */ -#define DIB3000MB_REG_FILTER_PID_0 ( 153) -#define DIB3000MB_REG_FILTER_PID_1 ( 154) -#define DIB3000MB_REG_FILTER_PID_2 ( 155) -#define DIB3000MB_REG_FILTER_PID_3 ( 156) -#define DIB3000MB_REG_FILTER_PID_4 ( 157) -#define DIB3000MB_REG_FILTER_PID_5 ( 158) -#define DIB3000MB_REG_FILTER_PID_6 ( 159) -#define DIB3000MB_REG_FILTER_PID_7 ( 160) -#define DIB3000MB_REG_FILTER_PID_8 ( 161) -#define DIB3000MB_REG_FILTER_PID_9 ( 162) -#define DIB3000MB_REG_FILTER_PID_10 ( 163) -#define DIB3000MB_REG_FILTER_PID_11 ( 164) -#define DIB3000MB_REG_FILTER_PID_12 ( 165) -#define DIB3000MB_REG_FILTER_PID_13 ( 166) -#define DIB3000MB_REG_FILTER_PID_14 ( 167) -#define DIB3000MB_REG_FILTER_PID_15 ( 168) - -#define DIB3000MB_ACTIVATE_FILTERING (0x2000) - -/* - * output mode - * USB devices have to use 'slave'-mode - * see also DIB3000MB_REG_ELECT_OUT_MODE - */ -#define DIB3000MB_REG_OUTPUT_MODE ( 169) -#define DIB3000MB_OUTPUT_MODE_GATED_CLK ( 0) -#define DIB3000MB_OUTPUT_MODE_CONT_CLK ( 1) -#define DIB3000MB_OUTPUT_MODE_SERIAL ( 2) -#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY ( 5) -#define DIB3000MB_OUTPUT_MODE_SLAVE ( 6) - -/* irq event mask */ -#define DIB3000MB_REG_IRQ_EVENT_MASK ( 170) -#define DIB3000MB_IRQ_EVENT_MASK ( 0) - -/* filter coefficients */ -#define DIB3000MB_REG_FILTER_COEF_171 ( 171) -#define DIB3000MB_REG_FILTER_COEF_172 ( 172) -#define DIB3000MB_REG_FILTER_COEF_173 ( 173) -#define DIB3000MB_REG_FILTER_COEF_174 ( 174) -#define DIB3000MB_REG_FILTER_COEF_175 ( 175) -#define DIB3000MB_REG_FILTER_COEF_176 ( 176) -#define DIB3000MB_REG_FILTER_COEF_177 ( 177) -#define DIB3000MB_REG_FILTER_COEF_178 ( 178) -#define DIB3000MB_REG_FILTER_COEF_179 ( 179) -#define DIB3000MB_REG_FILTER_COEF_180 ( 180) -#define DIB3000MB_REG_FILTER_COEF_181 ( 181) -#define DIB3000MB_REG_FILTER_COEF_182 ( 182) -#define DIB3000MB_REG_FILTER_COEF_183 ( 183) -#define DIB3000MB_REG_FILTER_COEF_184 ( 184) -#define DIB3000MB_REG_FILTER_COEF_185 ( 185) -#define DIB3000MB_REG_FILTER_COEF_186 ( 186) -#define DIB3000MB_REG_FILTER_COEF_187 ( 187) -#define DIB3000MB_REG_FILTER_COEF_188 ( 188) -#define DIB3000MB_REG_FILTER_COEF_189 ( 189) -#define DIB3000MB_REG_FILTER_COEF_190 ( 190) -#define DIB3000MB_REG_FILTER_COEF_191 ( 191) -#define DIB3000MB_REG_FILTER_COEF_192 ( 192) -#define DIB3000MB_REG_FILTER_COEF_193 ( 193) -#define DIB3000MB_REG_FILTER_COEF_194 ( 194) - -static u16 dib3000mb_reg_filter_coeffs[] = { - DIB3000MB_REG_FILTER_COEF_171, DIB3000MB_REG_FILTER_COEF_172, DIB3000MB_REG_FILTER_COEF_173, - DIB3000MB_REG_FILTER_COEF_174, DIB3000MB_REG_FILTER_COEF_175, DIB3000MB_REG_FILTER_COEF_176, - DIB3000MB_REG_FILTER_COEF_177, DIB3000MB_REG_FILTER_COEF_178, DIB3000MB_REG_FILTER_COEF_179, - DIB3000MB_REG_FILTER_COEF_180, DIB3000MB_REG_FILTER_COEF_181, DIB3000MB_REG_FILTER_COEF_182, - DIB3000MB_REG_FILTER_COEF_183, DIB3000MB_REG_FILTER_COEF_184, DIB3000MB_REG_FILTER_COEF_185, - DIB3000MB_REG_FILTER_COEF_186, DIB3000MB_REG_FILTER_COEF_188, - DIB3000MB_REG_FILTER_COEF_189, DIB3000MB_REG_FILTER_COEF_190, DIB3000MB_REG_FILTER_COEF_191, - DIB3000MB_REG_FILTER_COEF_192, DIB3000MB_REG_FILTER_COEF_194 -}; - -static u16 dib3000mb_filter_coeffs[] = { - 226, 160, 29, - 979, 998, 19, - 22, 1019, 1006, - 1022, 12, 6, - 1017, 1017, 3, - 6, 1019, - 1021, 2, 3, - 1, 0, -}; - -/* - * mobile algorithm (when you are moving with your device) - * but not faster than 90 km/h - */ -#define DIB3000MB_REG_MOBILE_ALGO ( 195) -#define DIB3000MB_MOBILE_ALGO_ON ( 0) -#define DIB3000MB_MOBILE_ALGO_OFF ( 1) - -/* multiple demodulators algorithm */ -#define DIB3000MB_REG_MULTI_DEMOD_MSB ( 206) -#define DIB3000MB_REG_MULTI_DEMOD_LSB ( 207) - -/* terminator, no more demods */ -#define DIB3000MB_MULTI_DEMOD_MSB ( 32767) -#define DIB3000MB_MULTI_DEMOD_LSB ( 4095) - -/* bring the device into a known */ -#define DIB3000MB_REG_RESET_DEVICE ( 1024) -#define DIB3000MB_RESET_DEVICE (0x812c) -#define DIB3000MB_RESET_DEVICE_RST ( 0) - -/* identification registers, manufactor an the device */ -#define DIB3000MB_REG_MANUFACTOR_ID ( 1025) -#define DIB3000MB_MANUFACTOR_ID_DIBCOM (0x01B3) - -#define DIB3000MB_REG_DEVICE_ID ( 1026) -#define DIB3000MB_DEVICE_ID (0x3000) - -/* hardware clock configuration */ -#define DIB3000MB_REG_CLOCK ( 1027) -#define DIB3000MB_CLOCK_DEFAULT (0x9000) -#define DIB3000MB_CLOCK_DIVERSITY (0x92b0) - -/* power down config */ -#define DIB3000MB_REG_POWER_CONTROL ( 1028) -#define DIB3000MB_POWER_DOWN ( 1) -#define DIB3000MB_POWER_UP ( 0) - -/* electrical output mode */ -#define DIB3000MB_REG_ELECT_OUT_MODE ( 1029) -#define DIB3000MB_ELECT_OUT_MODE_OFF ( 0) -#define DIB3000MB_ELECT_OUT_MODE_ON ( 1) - -/* set the tuner i2c address */ -#define DIB3000MB_REG_TUNER ( 1089) -#define DIB3000MB_TUNER_ADDR_DEFAULT ( 194) -#define DIB3000MB_ACTIVATE_TUNER_XFER(a) (0xffff & (a << 7)) -#define DIB3000MB_DEACTIVATE_TUNER_XFER(a) (0xffff & ((a << 7) + 0x80)) - -/* monitoring registers (read only) */ - -/* agc loop locked (size: 1) */ -#define DIB3000MB_REG_AGC_LOCK ( 324) - -/* agc power (size: 16) */ -#define DIB3000MB_REG_AGC_POWER ( 325) - -/* agc1 value (16) */ -#define DIB3000MB_REG_AGC1_VALUE ( 326) - -/* agc2 value (16) */ -#define DIB3000MB_REG_AGC2_VALUE ( 327) - -/* total RF power (16), can be used for signal strength */ -#define DIB3000MB_REG_RF_POWER ( 328) - -/* dds_frequency with offset (24) */ -#define DIB3000MB_REG_DDS_VALUE_MSB ( 339) -#define DIB3000MB_REG_DDS_VALUE_LSB ( 340) - -/* timing offset signed (24) */ -#define DIB3000MB_REG_TIMING_OFFSET_MSB ( 341) -#define DIB3000MB_REG_TIMING_OFFSET_LSB ( 342) - -/* fft start position (13) */ -#define DIB3000MB_REG_FFT_WINDOW_POS ( 353) - -/* carriers locked (1) */ -#define DIB3000MB_REG_CARRIER_LOCK ( 355) - -/* noise power (24) */ -#define DIB3000MB_REG_NOISE_POWER_MSB ( 372) -#define DIB3000MB_REG_NOISE_POWER_LSB ( 373) - -#define DIB3000MB_REG_MOBILE_NOISE_MSB ( 374) -#define DIB3000MB_REG_MOBILE_NOISE_LSB ( 375) - -/* - * signal power (16), this and the above can be - * used to calculate the signal/noise - ratio - */ -#define DIB3000MB_REG_SIGNAL_POWER ( 380) - -/* mer (24) */ -#define DIB3000MB_REG_MER_MSB ( 381) -#define DIB3000MB_REG_MER_LSB ( 382) - -/* - * Transmission Parameter Signalling (TPS) - * the following registers can be used to get TPS-information. - * The values are according to the DVB-T standard. - */ - -/* TPS locked (1) */ -#define DIB3000MB_REG_TPS_LOCK ( 394) - -/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */ -#define DIB3000MB_REG_TPS_QAM ( 398) - -/* hierarchy from TPS (1) */ -#define DIB3000MB_REG_TPS_HRCH ( 399) - -/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */ -#define DIB3000MB_REG_TPS_VIT_ALPHA ( 400) - -/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */ -#define DIB3000MB_REG_TPS_CODE_RATE_HP ( 401) - -/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */ -#define DIB3000MB_REG_TPS_CODE_RATE_LP ( 402) - -/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */ -#define DIB3000MB_REG_TPS_GUARD_TIME ( 403) - -/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */ -#define DIB3000MB_REG_TPS_FFT ( 404) - -/* cell id from TPS (16) */ -#define DIB3000MB_REG_TPS_CELL_ID ( 406) - -/* TPS (68) */ -#define DIB3000MB_REG_TPS_1 ( 408) -#define DIB3000MB_REG_TPS_2 ( 409) -#define DIB3000MB_REG_TPS_3 ( 410) -#define DIB3000MB_REG_TPS_4 ( 411) -#define DIB3000MB_REG_TPS_5 ( 412) - -/* bit error rate (before RS correction) (21) */ -#define DIB3000MB_REG_BER_MSB ( 414) -#define DIB3000MB_REG_BER_LSB ( 415) - -/* packet error rate (uncorrected TS packets) (16) */ -#define DIB3000MB_REG_PACKET_ERROR_RATE ( 417) - -/* uncorrected packet count (16) */ -#define DIB3000MB_REG_UNC ( 420) - -/* viterbi locked (1) */ -#define DIB3000MB_REG_VIT_LCK ( 421) - -/* viterbi inidcator (16) */ -#define DIB3000MB_REG_VIT_INDICATOR ( 422) - -/* transport stream sync lock (1) */ -#define DIB3000MB_REG_TS_SYNC_LOCK ( 423) - -/* transport stream RS lock (1) */ -#define DIB3000MB_REG_TS_RS_LOCK ( 424) - -/* lock mask 0 value (1) */ -#define DIB3000MB_REG_LOCK0_VALUE ( 425) - -/* lock mask 1 value (1) */ -#define DIB3000MB_REG_LOCK1_VALUE ( 426) - -/* lock mask 2 value (1) */ -#define DIB3000MB_REG_LOCK2_VALUE ( 427) - -/* interrupt pending for auto search */ -#define DIB3000MB_REG_AS_IRQ_PENDING ( 434) - -#endif diff -Nru a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/dib3000mb_priv.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,467 @@ +/* + * dib3000mb_priv.h + * + * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.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, version 2. + * + * for more information see dib3000mb.c . + */ + +#ifndef __DIB3000MB_PRIV_H_INCLUDED__ +#define __DIB3000MB_PRIV_H_INCLUDED__ + +/* register addresses and some of their default values */ + +/* restart subsystems */ +#define DIB3000MB_REG_RESTART ( 0) + +#define DIB3000MB_RESTART_OFF ( 0) +#define DIB3000MB_RESTART_AUTO_SEARCH (1 << 1) +#define DIB3000MB_RESTART_CTRL (1 << 2) +#define DIB3000MB_RESTART_AGC (1 << 3) + +/* FFT size */ +#define DIB3000MB_REG_FFT ( 1) + +/* Guard time */ +#define DIB3000MB_REG_GUARD_TIME ( 2) + +/* QAM */ +#define DIB3000MB_REG_QAM ( 3) + +/* Alpha coefficient high priority Viterbi algorithm */ +#define DIB3000MB_REG_VIT_ALPHA ( 4) + +/* spectrum inversion */ +#define DIB3000MB_REG_DDS_INV ( 5) + +/* DDS frequency value (IF position) ad ? values don't match reg_3000mb.txt */ +#define DIB3000MB_REG_DDS_FREQ_MSB ( 6) +#define DIB3000MB_REG_DDS_FREQ_LSB ( 7) +#define DIB3000MB_DDS_FREQ_MSB ( 178) +#define DIB3000MB_DDS_FREQ_LSB ( 8990) + +/* timing frequency (carrier spacing) */ +static u16 dib3000mb_reg_timing_freq[] = { 8,9 }; +static u16 dib3000mb_timing_freq[][2] = { + { 126 , 48873 }, /* 6 MHz */ + { 147 , 57019 }, /* 7 MHz */ + { 168 , 65164 }, /* 8 MHz */ +}; + +/* impulse noise parameter */ +/* 36 ??? */ + +static u16 dib3000mb_reg_impulse_noise[] = { 10,11,12,15,36 }; + +enum dib3000mb_impulse_noise_type { + DIB3000MB_IMPNOISE_OFF, + DIB3000MB_IMPNOISE_MOBILE, + DIB3000MB_IMPNOISE_FIXED, + DIB3000MB_IMPNOISE_DEFAULT +}; + +static u16 dib3000mb_impulse_noise_values[][5] = { + { 0x0000, 0x0004, 0x0014, 0x01ff, 0x0399 }, /* off */ + { 0x0001, 0x0004, 0x0014, 0x01ff, 0x037b }, /* mobile */ + { 0x0001, 0x0004, 0x0020, 0x01bd, 0x0399 }, /* fixed */ + { 0x0000, 0x0002, 0x000a, 0x01ff, 0x0399 }, /* default */ +}; + +/* + * Dual Automatic-Gain-Control + * - gains RF in tuner (AGC1) + * - gains IF after filtering (AGC2) + */ + +/* also from 16 to 18 */ +static u16 dib3000mb_reg_agc_gain[] = { + 19,20,21,22,23,24,25,26,27,28,29,30,31,32 +}; + +static u16 dib3000mb_default_agc_gain[] = + { 0x0001, 52429, 623, 128, 166, 195, 61, /* RF ??? */ + 0x0001, 53766, 38011, 0, 90, 33, 23 }; /* IF ??? */ + +/* phase noise */ +/* 36 is set when setting the impulse noise */ +static u16 dib3000mb_reg_phase_noise[] = { 33,34,35,37,38 }; + +static u16 dib3000mb_default_noise_phase[] = { 2, 544, 0, 5, 4 }; + +/* lock duration */ +static u16 dib3000mb_reg_lock_duration[] = { 39,40 }; +static u16 dib3000mb_default_lock_duration[] = { 135, 135 }; + +/* AGC loop bandwidth */ +static u16 dib3000mb_reg_agc_bandwidth[] = { 43,44,45,46,47,48,49,50 }; + +static u16 dib3000mb_agc_bandwidth_low[] = + { 2088, 10, 2088, 10, 3448, 5, 3448, 5 }; +static u16 dib3000mb_agc_bandwidth_high[] = + { 2349, 5, 2349, 5, 2586, 2, 2586, 2 }; + +/* + * lock0 definition (coff_lock) + */ +#define DIB3000MB_REG_LOCK0_MASK ( 51) +#define DIB3000MB_LOCK0_DEFAULT ( 4) + +/* + * lock1 definition (cpil_lock) + * for auto search + * which values hide behind the lock masks + */ +#define DIB3000MB_REG_LOCK1_MASK ( 52) +#define DIB3000MB_LOCK1_SEARCH_4 (0x0004) +#define DIB3000MB_LOCK1_SEARCH_2048 (0x0800) +#define DIB3000MB_LOCK1_DEFAULT (0x0001) + +/* + * lock2 definition (fec_lock) */ +#define DIB3000MB_REG_LOCK2_MASK ( 53) +#define DIB3000MB_LOCK2_DEFAULT (0x0080) + +/* + * SEQ ? what was that again ... :) + * changes when, inversion, guard time and fft is + * either automatically detected or not + */ +#define DIB3000MB_REG_SEQ ( 54) + +/* bandwidth */ +static u16 dib3000mb_reg_bandwidth[] = { 55,56,57,58,59,60,61,62,63,64,65,66,67 }; +static u16 dib3000mb_bandwidth_6mhz[] = + { 0, 33, 53312, 112, 46635, 563, 36565, 0, 1000, 0, 1010, 1, 45264 }; + +static u16 dib3000mb_bandwidth_7mhz[] = + { 0, 28, 64421, 96, 39973, 483, 3255, 0, 1000, 0, 1010, 1, 45264 }; + +static u16 dib3000mb_bandwidth_8mhz[] = + { 0, 25, 23600, 84, 34976, 422, 43808, 0, 1000, 0, 1010, 1, 45264 }; + +#define DIB3000MB_REG_UNK_68 ( 68) +#define DIB3000MB_UNK_68 ( 0) + +#define DIB3000MB_REG_UNK_69 ( 69) +#define DIB3000MB_UNK_69 ( 0) + +#define DIB3000MB_REG_UNK_71 ( 71) +#define DIB3000MB_UNK_71 ( 0) + +#define DIB3000MB_REG_UNK_77 ( 77) +#define DIB3000MB_UNK_77 ( 6) + +#define DIB3000MB_REG_UNK_78 ( 78) +#define DIB3000MB_UNK_78 (0x0080) + +/* isi */ +#define DIB3000MB_REG_ISI ( 79) +#define DIB3000MB_ISI_ACTIVATE ( 0) +#define DIB3000MB_ISI_INHIBIT ( 1) + +/* sync impovement */ +#define DIB3000MB_REG_SYNC_IMPROVEMENT ( 84) +#define DIB3000MB_SYNC_IMPROVE_2K_1_8 ( 3) +#define DIB3000MB_SYNC_IMPROVE_DEFAULT ( 0) + +/* phase noise compensation inhibition */ +#define DIB3000MB_REG_PHASE_NOISE ( 87) +#define DIB3000MB_PHASE_NOISE_DEFAULT ( 0) + +#define DIB3000MB_REG_UNK_92 ( 92) +#define DIB3000MB_UNK_92 (0x0080) + +#define DIB3000MB_REG_UNK_96 ( 96) +#define DIB3000MB_UNK_96 (0x0010) + +#define DIB3000MB_REG_UNK_97 ( 97) +#define DIB3000MB_UNK_97 (0x0009) + +/* mobile mode ??? */ +#define DIB3000MB_REG_MOBILE_MODE ( 101) +#define DIB3000MB_MOBILE_MODE_ON ( 1) +#define DIB3000MB_MOBILE_MODE_OFF ( 0) + +#define DIB3000MB_REG_UNK_106 ( 106) +#define DIB3000MB_UNK_106 (0x0080) + +#define DIB3000MB_REG_UNK_107 ( 107) +#define DIB3000MB_UNK_107 (0x0080) + +#define DIB3000MB_REG_UNK_108 ( 108) +#define DIB3000MB_UNK_108 (0x0080) + +/* fft */ +#define DIB3000MB_REG_UNK_121 ( 121) +#define DIB3000MB_UNK_121_2K ( 7) +#define DIB3000MB_UNK_121_DEFAULT ( 5) + +#define DIB3000MB_REG_UNK_122 ( 122) +#define DIB3000MB_UNK_122 ( 2867) + +/* QAM for mobile mode */ +#define DIB3000MB_REG_MOBILE_MODE_QAM ( 126) +#define DIB3000MB_MOBILE_MODE_QAM_64 ( 3) +#define DIB3000MB_MOBILE_MODE_QAM_QPSK_16 ( 1) +#define DIB3000MB_MOBILE_MODE_QAM_OFF ( 0) + +/* + * data diversity when having more than one chip on-board + * see also DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY + */ +#define DIB3000MB_REG_DATA_IN_DIVERSITY ( 127) +#define DIB3000MB_DATA_DIVERSITY_IN_OFF ( 0) +#define DIB3000MB_DATA_DIVERSITY_IN_ON ( 2) + +/* vit hrch */ +#define DIB3000MB_REG_VIT_HRCH ( 128) + +/* vit code rate */ +#define DIB3000MB_REG_VIT_CODE_RATE ( 129) + +/* vit select hp */ +#define DIB3000MB_REG_VIT_HP ( 130) + +/* time frame for Bit-Error-Rate calculation */ +#define DIB3000MB_REG_BERLEN ( 135) +#define DIB3000MB_BERLEN_LONG ( 0) +#define DIB3000MB_BERLEN_DEFAULT ( 1) +#define DIB3000MB_BERLEN_MEDIUM ( 2) +#define DIB3000MB_BERLEN_SHORT ( 3) + +/* 142 - 152 FIFO parameters + * which is what ? + */ + +#define DIB3000MB_REG_FIFO_142 ( 142) +#define DIB3000MB_FIFO_142 ( 0) + +/* MPEG2 TS output mode */ +#define DIB3000MB_REG_MPEG2_OUT_MODE ( 143) +#define DIB3000MB_MPEG2_OUT_MODE_204 ( 0) +#define DIB3000MB_MPEG2_OUT_MODE_188 ( 1) + +#define DIB3000MB_REG_PID_PARSE ( 144) +#define DIB3000MB_PID_PARSE_INHIBIT ( 0) +#define DIB3000MB_PID_PARSE_ACTIVATE ( 1) + +#define DIB3000MB_REG_FIFO ( 145) +#define DIB3000MB_FIFO_INHIBIT ( 1) +#define DIB3000MB_FIFO_ACTIVATE ( 0) + +#define DIB3000MB_REG_FIFO_146 ( 146) +#define DIB3000MB_FIFO_146 ( 3) + +#define DIB3000MB_REG_FIFO_147 ( 147) +#define DIB3000MB_FIFO_147 (0x0100) + +/* + * pidfilter + * it is not a hardware pidfilter but a filter which drops all pids + * except the ones set. Necessary because of the limited USB1.1 bandwidth. + * regs 153-168 + */ + +#define DIB3000MB_REG_FIRST_PID ( 153) +#define DIB3000MB_NUM_PIDS ( 16) + +/* + * output mode + * USB devices have to use 'slave'-mode + * see also DIB3000MB_REG_ELECT_OUT_MODE + */ +#define DIB3000MB_REG_OUTPUT_MODE ( 169) +#define DIB3000MB_OUTPUT_MODE_GATED_CLK ( 0) +#define DIB3000MB_OUTPUT_MODE_CONT_CLK ( 1) +#define DIB3000MB_OUTPUT_MODE_SERIAL ( 2) +#define DIB3000MB_OUTPUT_MODE_DATA_DIVERSITY ( 5) +#define DIB3000MB_OUTPUT_MODE_SLAVE ( 6) + +/* irq event mask */ +#define DIB3000MB_REG_IRQ_EVENT_MASK ( 170) +#define DIB3000MB_IRQ_EVENT_MASK ( 0) + +/* filter coefficients */ +static u16 dib3000mb_reg_filter_coeffs[] = { + 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, + 188, 189, 190, 191, 192, 194 +}; + +static u16 dib3000mb_filter_coeffs[] = { + 226, 160, 29, + 979, 998, 19, + 22, 1019, 1006, + 1022, 12, 6, + 1017, 1017, 3, + 6, 1019, + 1021, 2, 3, + 1, 0, +}; + +/* + * mobile algorithm (when you are moving with your device) + * but not faster than 90 km/h + */ +#define DIB3000MB_REG_MOBILE_ALGO ( 195) +#define DIB3000MB_MOBILE_ALGO_ON ( 0) +#define DIB3000MB_MOBILE_ALGO_OFF ( 1) + +/* multiple demodulators algorithm */ +#define DIB3000MB_REG_MULTI_DEMOD_MSB ( 206) +#define DIB3000MB_REG_MULTI_DEMOD_LSB ( 207) + +/* terminator, no more demods */ +#define DIB3000MB_MULTI_DEMOD_MSB ( 32767) +#define DIB3000MB_MULTI_DEMOD_LSB ( 4095) + +/* bring the device into a known */ +#define DIB3000MB_REG_RESET_DEVICE ( 1024) +#define DIB3000MB_RESET_DEVICE (0x812c) +#define DIB3000MB_RESET_DEVICE_RST ( 0) + +/* hardware clock configuration */ +#define DIB3000MB_REG_CLOCK ( 1027) +#define DIB3000MB_CLOCK_DEFAULT (0x9000) +#define DIB3000MB_CLOCK_DIVERSITY (0x92b0) + +/* power down config */ +#define DIB3000MB_REG_POWER_CONTROL ( 1028) +#define DIB3000MB_POWER_DOWN ( 1) +#define DIB3000MB_POWER_UP ( 0) + +/* electrical output mode */ +#define DIB3000MB_REG_ELECT_OUT_MODE ( 1029) +#define DIB3000MB_ELECT_OUT_MODE_OFF ( 0) +#define DIB3000MB_ELECT_OUT_MODE_ON ( 1) + +/* set the tuner i2c address */ +#define DIB3000MB_REG_TUNER ( 1089) + +/* monitoring registers (read only) */ + +/* agc loop locked (size: 1) */ +#define DIB3000MB_REG_AGC_LOCK ( 324) + +/* agc power (size: 16) */ +#define DIB3000MB_REG_AGC_POWER ( 325) + +/* agc1 value (16) */ +#define DIB3000MB_REG_AGC1_VALUE ( 326) + +/* agc2 value (16) */ +#define DIB3000MB_REG_AGC2_VALUE ( 327) + +/* total RF power (16), can be used for signal strength */ +#define DIB3000MB_REG_RF_POWER ( 328) + +/* dds_frequency with offset (24) */ +#define DIB3000MB_REG_DDS_VALUE_MSB ( 339) +#define DIB3000MB_REG_DDS_VALUE_LSB ( 340) + +/* timing offset signed (24) */ +#define DIB3000MB_REG_TIMING_OFFSET_MSB ( 341) +#define DIB3000MB_REG_TIMING_OFFSET_LSB ( 342) + +/* fft start position (13) */ +#define DIB3000MB_REG_FFT_WINDOW_POS ( 353) + +/* carriers locked (1) */ +#define DIB3000MB_REG_CARRIER_LOCK ( 355) + +/* noise power (24) */ +#define DIB3000MB_REG_NOISE_POWER_MSB ( 372) +#define DIB3000MB_REG_NOISE_POWER_LSB ( 373) + +#define DIB3000MB_REG_MOBILE_NOISE_MSB ( 374) +#define DIB3000MB_REG_MOBILE_NOISE_LSB ( 375) + +/* + * signal power (16), this and the above can be + * used to calculate the signal/noise - ratio + */ +#define DIB3000MB_REG_SIGNAL_POWER ( 380) + +/* mer (24) */ +#define DIB3000MB_REG_MER_MSB ( 381) +#define DIB3000MB_REG_MER_LSB ( 382) + +/* + * Transmission Parameter Signalling (TPS) + * the following registers can be used to get TPS-information. + * The values are according to the DVB-T standard. + */ + +/* TPS locked (1) */ +#define DIB3000MB_REG_TPS_LOCK ( 394) + +/* QAM from TPS (2) (values according to DIB3000MB_REG_QAM) */ +#define DIB3000MB_REG_TPS_QAM ( 398) + +/* hierarchy from TPS (1) */ +#define DIB3000MB_REG_TPS_HRCH ( 399) + +/* alpha from TPS (3) (values according to DIB3000MB_REG_VIT_ALPHA) */ +#define DIB3000MB_REG_TPS_VIT_ALPHA ( 400) + +/* code rate high priority from TPS (3) (values according to DIB3000MB_FEC_*) */ +#define DIB3000MB_REG_TPS_CODE_RATE_HP ( 401) + +/* code rate low priority from TPS (3) if DIB3000MB_REG_TPS_VIT_ALPHA */ +#define DIB3000MB_REG_TPS_CODE_RATE_LP ( 402) + +/* guard time from TPS (2) (values according to DIB3000MB_REG_GUARD_TIME */ +#define DIB3000MB_REG_TPS_GUARD_TIME ( 403) + +/* fft size from TPS (2) (values according to DIB3000MB_REG_FFT) */ +#define DIB3000MB_REG_TPS_FFT ( 404) + +/* cell id from TPS (16) */ +#define DIB3000MB_REG_TPS_CELL_ID ( 406) + +/* TPS (68) */ +#define DIB3000MB_REG_TPS_1 ( 408) +#define DIB3000MB_REG_TPS_2 ( 409) +#define DIB3000MB_REG_TPS_3 ( 410) +#define DIB3000MB_REG_TPS_4 ( 411) +#define DIB3000MB_REG_TPS_5 ( 412) + +/* bit error rate (before RS correction) (21) */ +#define DIB3000MB_REG_BER_MSB ( 414) +#define DIB3000MB_REG_BER_LSB ( 415) + +/* packet error rate (uncorrected TS packets) (16) */ +#define DIB3000MB_REG_PACKET_ERROR_RATE ( 417) + +/* uncorrected packet count (16) */ +#define DIB3000MB_REG_UNC ( 420) + +/* viterbi locked (1) */ +#define DIB3000MB_REG_VIT_LCK ( 421) + +/* viterbi inidcator (16) */ +#define DIB3000MB_REG_VIT_INDICATOR ( 422) + +/* transport stream sync lock (1) */ +#define DIB3000MB_REG_TS_SYNC_LOCK ( 423) + +/* transport stream RS lock (1) */ +#define DIB3000MB_REG_TS_RS_LOCK ( 424) + +/* lock mask 0 value (1) */ +#define DIB3000MB_REG_LOCK0_VALUE ( 425) + +/* lock mask 1 value (1) */ +#define DIB3000MB_REG_LOCK1_VALUE ( 426) + +/* lock mask 2 value (1) */ +#define DIB3000MB_REG_LOCK2_VALUE ( 427) + +/* interrupt pending for auto search */ +#define DIB3000MB_REG_AS_IRQ_PENDING ( 434) + +#endif diff -Nru a/drivers/media/dvb/frontends/dst-bt878.h b/drivers/media/dvb/frontends/dst-bt878.h --- a/drivers/media/dvb/frontends/dst-bt878.h 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,37 +0,0 @@ -/* - * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend - * - * Copyright (C) 2003 Jamie Honan - */ - -struct dst_gpio_enable { - u32 mask; - u32 enable; -}; - -struct dst_gpio_output { - u32 mask; - u32 highvals; -}; - -struct dst_gpio_read { - unsigned long value; -}; - -union dst_gpio_packet { - struct dst_gpio_enable enb; - struct dst_gpio_output outp; - struct dst_gpio_read rd; - int psize; -}; - -#define DST_IG_ENABLE 0 -#define DST_IG_WRITE 1 -#define DST_IG_READ 2 -#define DST_IG_TS 3 - -struct bt878 ; - -int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); - -struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap); diff -Nru a/drivers/media/dvb/frontends/dst.c b/drivers/media/dvb/frontends/dst.c --- a/drivers/media/dvb/frontends/dst.c 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,1256 +0,0 @@ -/* - Frontend-driver for TwinHan DST Frontend - - Copyright (C) 2003 Jamie Honan - - 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 "dvb_frontend.h" -#include "dst-bt878.h" - -unsigned int dst_verbose = 0; -MODULE_PARM(dst_verbose, "i"); -MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)"); -unsigned int dst_debug = 0; -MODULE_PARM(dst_debug, "i"); -MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)"); - -#define dprintk if (dst_debug) printk - -#define DST_I2C_ADDR 0x55 - -#define DST_TYPE_IS_SAT 0 -#define DST_TYPE_IS_TERR 1 -#define DST_TYPE_IS_CABLE 2 - -#define DST_TYPE_HAS_NEWTUNE 1 -#define DST_TYPE_HAS_TS204 2 -#define DST_TYPE_HAS_SYMDIV 4 - -#define HAS_LOCK 1 -#define ATTEMPT_TUNE 2 -#define HAS_POWER 4 - -struct dst_data { - u8 tx_tuna[10]; - u8 rx_tuna[10]; - u8 rxbuffer[10]; - u8 diseq_flags; - u8 dst_type; - u32 type_flags; - u32 frequency; /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - u32 decode_freq; - u8 decode_lock; - u16 decode_strength; - u16 decode_snr; - unsigned long cur_jiff; - u8 k22; - fe_bandwidth_t bandwidth; - - struct bt878 *bt; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - -static struct dvb_frontend_info dst_info_sat = { - .name = "DST SAT", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, -/* . symbol_rate_tolerance = ???,*/ - .notifier_delay = 50, /* 1/20 s */ - .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK -}; - -static struct dvb_frontend_info dst_info_cable = { - .name = "DST CABLE", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, -/* . symbol_rate_tolerance = ???,*/ - .notifier_delay = 50, /* 1/20 s */ - .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO -}; - -static struct dvb_frontend_info dst_info_terr = { - .name = "DST TERR", - .type = FE_OFDM, - .frequency_min = 137000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO -}; - -static void dst_packsize(struct dst_data *dst, int psize) -{ - union dst_gpio_packet bits; - - bits.psize = psize; - bt878_device_control(dst->bt, DST_IG_TS, &bits); -} - -static int dst_gpio_outb(struct dst_data *dst, u32 mask, u32 enbb, u32 outhigh) -{ - union dst_gpio_packet enb; - union dst_gpio_packet bits; - int err; - - enb.enb.mask = mask; - enb.enb.enable = enbb; - if ((err = bt878_device_control(dst->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb); - return -EREMOTEIO; - } - - /* because complete disabling means no output, no need to do output packet */ - if (enbb == 0) - return 0; - - bits.outp.mask = enbb; - bits.outp.highvals = outhigh; - - if ((err = bt878_device_control(dst->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh); - return -EREMOTEIO; - } - return 0; -} - -static int dst_gpio_inb(struct dst_data *dst, u8 * result) -{ - union dst_gpio_packet rd_packet; - int err; - - *result = 0; - - if ((err = bt878_device_control(dst->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err); - return -EREMOTEIO; - } - *result = (u8) rd_packet.rd.value; - return 0; -} - -#define DST_I2C_ENABLE 1 -#define DST_8820 2 - -static int dst_reset8820(struct dst_data *dst) -{ - int retval; - /* pull 8820 gpio pin low, wait, high, wait, then low */ - // dprintk ("%s: reset 8820\n", __FUNCTION__); - retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0); - if (retval < 0) - return retval; - msleep(10); - retval = dst_gpio_outb(dst, DST_8820, DST_8820, DST_8820); - if (retval < 0) - return retval; - /* wait for more feedback on what works here * - msleep(10); - retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0); - if (retval < 0) - return retval; - */ - return 0; -} - -static int dst_i2c_enable(struct dst_data *dst) -{ - int retval; - /* pull I2C enable gpio pin low, wait */ - // dprintk ("%s: i2c enable\n", __FUNCTION__); - retval = dst_gpio_outb(dst, ~0, DST_I2C_ENABLE, 0); - if (retval < 0) - return retval; - // dprintk ("%s: i2c enable delay\n", __FUNCTION__); - msleep(33); - return 0; -} - -static int dst_i2c_disable(struct dst_data *dst) -{ - int retval; - /* release I2C enable gpio pin, wait */ - // dprintk ("%s: i2c disable\n", __FUNCTION__); - retval = dst_gpio_outb(dst, ~0, 0, 0); - if (retval < 0) - return retval; - // dprintk ("%s: i2c disable delay\n", __FUNCTION__); - msleep(33); - return 0; -} - -static int dst_wait_dst_ready(struct dst_data *dst) -{ - u8 reply; - int retval; - int i; - for (i = 0; i < 200; i++) { - retval = dst_gpio_inb(dst, &reply); - if (retval < 0) - return retval; - if ((reply & DST_I2C_ENABLE) == 0) { - dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); - return 1; - } - msleep(5); - } - dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); - return 0; -} - -static int write_dst(struct dst_data *dst, u8 * data, u8 len) -{ - struct i2c_msg msg = { - .addr = DST_I2C_ADDR,.flags = 0,.buf = data,.len = len - }; - int err; - int cnt; - - if (dst_debug && dst_verbose) { - u8 i; - dprintk("%s writing", __FUNCTION__); - for (i = 0; i < len; i++) { - dprintk(" 0x%02x", data[i]); - } - dprintk("\n"); - } - msleep(30); - for (cnt = 0; cnt < 4; cnt++) { - if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) { - dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); - dst_i2c_disable(dst); - msleep(500); - dst_i2c_enable(dst); - msleep(500); - continue; - } else - break; - } - if (cnt >= 4) - return -EREMOTEIO; - return 0; -} - -static int read_dst(struct dst_data *dst, u8 * ret, u8 len) -{ - struct i2c_msg msg = {.addr = DST_I2C_ADDR,.flags = I2C_M_RD,.buf = ret,.len = len }; - int err; - int cnt; - - for (cnt = 0; cnt < 4; cnt++) { - if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) { - dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]); - dst_i2c_disable(dst); - dst_i2c_enable(dst); - continue; - } else - break; - } - if (cnt >= 4) - return -EREMOTEIO; - dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); - if (dst_debug && dst_verbose) { - for (err = 1; err < len; err++) - dprintk(" 0x%x", ret[err]); - if (err > 1) - dprintk("\n"); - } - return 0; -} - -static int dst_set_freq(struct dst_data *dst, u32 freq) -{ - u8 *val; - - dst->frequency = freq; - - // dprintk("%s: set frequency %u\n", __FUNCTION__, freq); - if (dst->dst_type == DST_TYPE_IS_SAT) { - freq = freq / 1000; - if (freq < 950 || freq > 2150) - return -EINVAL; - val = &dst->tx_tuna[0]; - val[2] = (freq >> 8) & 0x7f; - val[3] = (u8) freq; - val[4] = 1; - val[8] &= ~4; - if (freq < 1531) - val[8] |= 4; - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - freq = freq / 1000; - if (freq < 137000 || freq > 858000) - return -EINVAL; - val = &dst->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; - val[5] = 0; - switch (dst->bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; - - case BANDWIDTH_7_MHZ: - case BANDWIDTH_AUTO: - val[6] = 7; - break; - - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; - } - - val[7] = 0; - val[8] = 0; - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - /* guess till will get one */ - freq = freq / 1000; - val = &dst->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; - } else - return -EINVAL; - return 0; -} - -static int dst_set_bandwidth(struct dst_data *dst, fe_bandwidth_t bandwidth) -{ - u8 *val; - - dst->bandwidth = bandwidth; - - if (dst->dst_type != DST_TYPE_IS_TERR) - return 0; - - val = &dst->tx_tuna[0]; - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; - - case BANDWIDTH_7_MHZ: - val[6] = 7; - break; - - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; - - default: - return -EINVAL; - } - return 0; -} - -static int dst_set_inversion(struct dst_data *dst, fe_spectral_inversion_t inversion) -{ - u8 *val; - - dst->inversion = inversion; - - val = &dst->tx_tuna[0]; - - val[8] &= ~0x80; - - switch (inversion) { - case INVERSION_OFF: - break; - case INVERSION_ON: - val[8] |= 0x80; - break; - default: - return -EINVAL; - } - return 0; -} - - -static int dst_set_fec(struct dst_data *dst, fe_code_rate_t fec) -{ - dst->fec = fec; - return 0; -} - -static fe_code_rate_t dst_get_fec(struct dst_data *dst) -{ - return dst->fec; -} - -static int dst_set_symbolrate(struct dst_data *dst, u32 srate) -{ - u8 *val; - u32 symcalc; - u64 sval; - - dst->symbol_rate = srate; - - if (dst->dst_type == DST_TYPE_IS_TERR) { - return 0; - } - // dprintk("%s: set srate %u\n", __FUNCTION__, srate); - srate /= 1000; - val = &dst->tx_tuna[0]; - - if (dst->type_flags & DST_TYPE_HAS_SYMDIV) { - sval = srate; - sval <<= 20; - do_div(sval, 88000); - symcalc = (u32) sval; - // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); - val[5] = (u8) (symcalc >> 12); - val[6] = (u8) (symcalc >> 4); - val[7] = (u8) (symcalc << 4); - } else { - val[5] = (u8) (srate >> 16) & 0x7f; - val[6] = (u8) (srate >> 8); - val[7] = (u8) srate; - } - val[8] &= ~0x20; - if (srate > 8000) - val[8] |= 0x20; - return 0; -} - - -static u8 dst_check_sum(u8 * buf, u32 len) -{ - u32 i; - u8 val = 0; - if (!len) - return 0; - for (i = 0; i < len; i++) { - val += buf[i]; - } - return ((~val) + 1); -} - -typedef struct dst_types { - char *mstr; - int offs; - u8 dst_type; - u32 type_flags; -} DST_TYPES; - -struct dst_types dst_tlist[] = { - {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, - {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, - {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204}, - {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, - {"DST-CI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, - {"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, - {"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, - {"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE}, - {"DCT_CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204}, - {"DTTDIG", 1, DST_TYPE_IS_TERR, 0} -}; - -/* DCTNEW and DCT-CI are guesses */ - -static void dst_type_flags_print(u32 type_flags) -{ - printk("DST type flags :"); - if (type_flags & DST_TYPE_HAS_NEWTUNE) - printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); - if (type_flags & DST_TYPE_HAS_TS204) - printk(" 0x%x ts204", DST_TYPE_HAS_TS204); - if (type_flags & DST_TYPE_HAS_SYMDIV) - printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV); - printk("\n"); -} - -static int dst_type_print(u8 type) -{ - char *otype; - switch (type) { - case DST_TYPE_IS_SAT: - otype = "satellite"; - break; - case DST_TYPE_IS_TERR: - otype = "terrestial TV"; - break; - case DST_TYPE_IS_CABLE: - otype = "terrestial TV"; - break; - default: - printk("%s: invalid dst type %d\n", __FUNCTION__, type); - return -EINVAL; - } - printk("DST type : %s\n", otype); - return 0; -} - -static int dst_check_ci(struct dst_data *dst) -{ - u8 txbuf[8]; - u8 rxbuf[8]; - int retval; - int i; - struct dst_types *dsp; - u8 use_dst_type; - u32 use_type_flags; - - memset(txbuf, 0, sizeof(txbuf)); - txbuf[1] = 6; - txbuf[7] = dst_check_sum(txbuf, 7); - - dst_i2c_enable(dst); - dst_reset8820(dst); - retval = write_dst(dst, txbuf, 8); - if (retval < 0) { - dst_i2c_disable(dst); - dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__); - return retval; - } - msleep(3); - retval = read_dst(dst, rxbuf, 1); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__); - return retval; - } - if (rxbuf[0] != 0xff) { - dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]); - return retval; - } - if (!dst_wait_dst_ready(dst)) - return 0; - // dst_i2c_enable(i2c); Dimitri - retval = read_dst(dst, rxbuf, 8); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return retval; - } - if (rxbuf[7] != dst_check_sum(rxbuf, 7)) { - dprintk("%s: checksum failure\n", __FUNCTION__); - return retval; - } - rxbuf[7] = '\0'; - for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) { - if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) { - use_type_flags = dsp->type_flags; - use_dst_type = dsp->dst_type; - printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr); - break; - } - } - if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) { - printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]); - printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); - use_dst_type = DST_TYPE_IS_SAT; - use_type_flags = DST_TYPE_HAS_SYMDIV; - } - dst_type_print(use_dst_type); - - dst->type_flags = use_type_flags; - dst->dst_type = use_dst_type; - dst_type_flags_print(dst->type_flags); - - if (dst->type_flags & DST_TYPE_HAS_TS204) { - dst_packsize(dst, 204); - } - return 0; -} - -static int dst_command(struct dst_data *dst, u8 * data, u8 len) -{ - int retval; - u8 reply; - - dst_i2c_enable(dst); - dst_reset8820(dst); - retval = write_dst(dst, data, len); - if (retval < 0) { - dst_i2c_disable(dst); - dprintk("%s: write not successful\n", __FUNCTION__); - return retval; - } - msleep(33); - retval = read_dst(dst, &reply, 1); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read verify not successful\n", __FUNCTION__); - return retval; - } - if (reply != 0xff) { - dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); - return 0; - } - if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) - return 0; - if (!dst_wait_dst_ready(dst)) - return 0; - // dst_i2c_enable(i2c); Per dimitri - retval = read_dst(dst, dst->rxbuffer, 8); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return 0; - } - if (dst->rxbuffer[7] != dst_check_sum(dst->rxbuffer, 7)) { - dprintk("%s: checksum failure\n", __FUNCTION__); - return 0; - } - return 0; -} - -static int dst_get_signal(struct dst_data *dst) -{ - int retval; - u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - - if ((dst->diseq_flags & ATTEMPT_TUNE) == 0) { - dst->decode_lock = dst->decode_strength = dst->decode_snr = 0; - return 0; - } - if (0 == (dst->diseq_flags & HAS_LOCK)) { - dst->decode_lock = dst->decode_strength = dst->decode_snr = 0; - return 0; - } - if (time_after_eq(jiffies, dst->cur_jiff + (HZ / 5))) { - retval = dst_command(dst, get_signal, 8); - if (retval < 0) - return retval; - if (dst->dst_type == DST_TYPE_IS_SAT) { - dst->decode_lock = ((dst->rxbuffer[6] & 0x10) == 0) ? 1 : 0; - dst->decode_strength = dst->rxbuffer[5] << 8; - dst->decode_snr = dst->rxbuffer[2] << 8 | dst->rxbuffer[3]; - } else if ((dst->dst_type == DST_TYPE_IS_TERR) || (dst->dst_type == DST_TYPE_IS_CABLE)) { - dst->decode_lock = (dst->rxbuffer[1]) ? 1 : 0; - dst->decode_strength = dst->rxbuffer[4] << 8; - dst->decode_snr = dst->rxbuffer[3] << 8; - } - dst->cur_jiff = jiffies; - } - return 0; -} - -/* - * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 - * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 - * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 - * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 - * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 - * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec - * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 - * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 - * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 - */ - -static int dst_set_diseqc(struct dst_data *dst, u8 * cmd, u8 len) -{ - u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - if (len == 0 || len > 4) - return -EINVAL; - memcpy(&paket[3], cmd, len); - paket[7] = dst_check_sum(&paket[0], 7); - dst_command(dst, paket, 8); - return 0; -} - -static int dst_tone_power_cmd(struct dst_data *dst) -{ - u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - if (dst->voltage == SEC_VOLTAGE_OFF) - paket[4] = 0; - else - paket[4] = 1; - if (dst->tone == SEC_TONE_ON) - paket[2] = dst->k22; - else - paket[2] = 0; - paket[7] = dst_check_sum(&paket[0], 7); - dst_command(dst, paket, 8); - return 0; -} - -static int dst_set_voltage(struct dst_data *dst, fe_sec_voltage_t voltage) -{ - u8 *val; - int need_cmd; - - dst->voltage = voltage; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - need_cmd = 0; - val = &dst->tx_tuna[0]; - val[8] &= ~0x40; - switch (voltage) { - case SEC_VOLTAGE_13: - if ((dst->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - dst->diseq_flags |= HAS_POWER; - break; - case SEC_VOLTAGE_18: - if ((dst->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - dst->diseq_flags |= HAS_POWER; - val[8] |= 0x40; - break; - case SEC_VOLTAGE_OFF: - need_cmd = 1; - dst->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); - break; - default: - return -EINVAL; - } - if (need_cmd) { - dst_tone_power_cmd(dst); - } - return 0; -} - - -static int dst_set_tone(struct dst_data *dst, fe_sec_tone_mode_t tone) -{ - u8 *val; - - dst->tone = tone; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - val = &dst->tx_tuna[0]; - - val[8] &= ~0x1; - - switch (tone) { - case SEC_TONE_OFF: - break; - case SEC_TONE_ON: - val[8] |= 1; - break; - default: - return -EINVAL; - } - dst_tone_power_cmd(dst); - return 0; -} - -static int dst_get_tuna(struct dst_data *dst) -{ - int retval; - if ((dst->diseq_flags & ATTEMPT_TUNE) == 0) - return 0; - dst->diseq_flags &= ~(HAS_LOCK); - if (!dst_wait_dst_ready(dst)) - return 0; - if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) { - /* how to get variable length reply ???? */ - retval = read_dst(dst, dst->rx_tuna, 10); - } else { - retval = read_dst(dst, &dst->rx_tuna[2], 8); - } - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return 0; - } - if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) { - if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[0], 9)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); - return 0; - } - } else { - if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[2], 7)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); - return 0; - } - } - if (dst->rx_tuna[2] == 0 && dst->rx_tuna[3] == 0) - return 0; - dst->decode_freq = ((dst->rx_tuna[2] & 0x7f) << 8) + dst->rx_tuna[3]; - - dst->decode_lock = 1; - /* - dst->decode_n1 = (dst->rx_tuna[4] << 8) + - (dst->rx_tuna[5]); - - dst->decode_n2 = (dst->rx_tuna[8] << 8) + - (dst->rx_tuna[7]); - */ - dst->diseq_flags |= HAS_LOCK; - /* dst->cur_jiff = jiffies; */ - return 1; -} - -static int dst_write_tuna(struct dst_data *dst) -{ - int retval; - u8 reply; - - dprintk("%s: type_flags 0x%x \n", __FUNCTION__, dst->type_flags); - dst->decode_freq = 0; - dst->decode_lock = dst->decode_strength = dst->decode_snr = 0; - if (dst->dst_type == DST_TYPE_IS_SAT) { - if (!(dst->diseq_flags & HAS_POWER)) - dst_set_voltage(dst, SEC_VOLTAGE_13); - } - dst->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); - dst_i2c_enable(dst); - if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) { - dst_reset8820(dst); - dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[0], 9); - retval = write_dst(dst, &dst->tx_tuna[0], 10); - } else { - dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[2], 7); - retval = write_dst(dst, &dst->tx_tuna[2], 8); - } - if (retval < 0) { - dst_i2c_disable(dst); - dprintk("%s: write not successful\n", __FUNCTION__); - return retval; - } - msleep(3); - retval = read_dst(dst, &reply, 1); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read verify not successful\n", __FUNCTION__); - return retval; - } - if (reply != 0xff) { - dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); - return 0; - } - dst->diseq_flags |= ATTEMPT_TUNE; - return dst_get_tuna(dst); -} - -static void dst_init(struct dst_data *dst) -{ - static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 }; - static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 }; - static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - dst->inversion = INVERSION_ON; - dst->voltage = SEC_VOLTAGE_13; - dst->tone = SEC_TONE_OFF; - dst->symbol_rate = 29473000; - dst->fec = FEC_AUTO; - dst->diseq_flags = 0; - dst->k22 = 0x02; - dst->bandwidth = BANDWIDTH_7_MHZ; - dst->cur_jiff = jiffies; - if (dst->dst_type == DST_TYPE_IS_SAT) { - dst->frequency = 950000; - memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna)); - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - dst->frequency = 137000000; - memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna)); - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - dst->frequency = 51000000; - memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna)); - } -} - -struct lkup { - unsigned int cmd; - char *desc; -} looker[] = { - { - FE_GET_INFO, "FE_GET_INFO:"}, { - FE_READ_STATUS, "FE_READ_STATUS:"}, { - FE_READ_BER, "FE_READ_BER:"}, { - FE_READ_SIGNAL_STRENGTH, "FE_READ_SIGNAL_STRENGTH:"}, { - FE_READ_SNR, "FE_READ_SNR:"}, { - FE_READ_UNCORRECTED_BLOCKS, "FE_READ_UNCORRECTED_BLOCKS:"}, { - FE_SET_FRONTEND, "FE_SET_FRONTEND:"}, { - FE_GET_FRONTEND, "FE_GET_FRONTEND:"}, { - FE_SLEEP, "FE_SLEEP:"}, { - FE_INIT, "FE_INIT:"}, { - FE_SET_TONE, "FE_SET_TONE:"}, { -FE_SET_VOLTAGE, "FE_SET_VOLTAGE:"},}; - -static int dst_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct dst_data *dst = fe->data; - int retval; - /* - char *cc; - - cc = "FE_UNSUPP:"; - for(retval = 0; retval < sizeof(looker) / sizeof(looker[0]); retval++) { - if (looker[retval].cmd == cmd) { - cc = looker[retval].desc; - break; - } - } - dprintk("%s cmd %s (0x%x)\n",__FUNCTION__, cc, cmd); - */ - // printk("%s: dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, dst, dst->bt, dst->i2c); - /* should be set by attach, but just in case */ - - switch (cmd) { - case FE_GET_INFO: - { - struct dvb_frontend_info *info; - info = &dst_info_sat; - if (dst->dst_type == DST_TYPE_IS_TERR) - info = &dst_info_terr; - else if (dst->dst_type == DST_TYPE_IS_CABLE) - info = &dst_info_cable; - memcpy(arg, info, sizeof(struct dvb_frontend_info)); - break; - } - case FE_READ_STATUS: - { - fe_status_t *status = arg; - - *status = 0; - if (dst->diseq_flags & HAS_LOCK) { - dst_get_signal(dst); - if (dst->decode_lock) - *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; - } - break; - } - - case FE_READ_BER: - { - /* guess */ - // *(u32*) arg = dst->decode_n1; - *(u32 *) arg = 0; - return -EOPNOTSUPP; - } - - case FE_READ_SIGNAL_STRENGTH: - { - dst_get_signal(dst); - *((u16 *) arg) = dst->decode_strength; - break; - } - - case FE_READ_SNR: - { - dst_get_signal(dst); - *((u16 *) arg) = dst->decode_snr; - break; - } - - case FE_READ_UNCORRECTED_BLOCKS: - { - *((u32 *) arg) = 0; /* the stv0299 can't measure BER and */ - return -EOPNOTSUPP; /* errors at the same time.... */ - } - - case FE_SET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - dst_set_freq(dst, p->frequency); - dst_set_inversion(dst, p->inversion); - if (dst->dst_type == DST_TYPE_IS_SAT) { - dst_set_fec(dst, p->u.qpsk.fec_inner); - dst_set_symbolrate(dst, p->u.qpsk.symbol_rate); - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - dst_set_bandwidth(dst, p->u.ofdm.bandwidth); - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(dst, p->u.qam.fec_inner); - dst_set_symbolrate(dst, p->u.qam.symbol_rate); - } - dst_write_tuna(dst); - - break; - } - - case FE_GET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - - p->frequency = dst->decode_freq; - p->inversion = dst->inversion; - if (dst->dst_type == DST_TYPE_IS_SAT) { - p->u.qpsk.symbol_rate = dst->symbol_rate; - p->u.qpsk.fec_inner = dst_get_fec(dst); - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - p->u.ofdm.bandwidth = dst->bandwidth; - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - p->u.qam.symbol_rate = dst->symbol_rate; - p->u.qam.fec_inner = dst_get_fec(dst); - p->u.qam.modulation = QAM_AUTO; - } - break; - } - - case FE_SLEEP: - return 0; - - case FE_INIT: - dst_init(dst); - break; - - case FE_DISEQC_SEND_MASTER_CMD: - { - struct dvb_diseqc_master_cmd *cmd = (struct dvb_diseqc_master_cmd *) arg; - retval = dst_set_diseqc(dst, cmd->msg, cmd->msg_len); - if (retval < 0) - return retval; - break; - } - case FE_SET_TONE: - retval = dst_set_tone(dst, (fe_sec_tone_mode_t) arg); - if (retval < 0) - return retval; - break; - case FE_SET_VOLTAGE: - retval = dst_set_voltage(dst, (fe_sec_voltage_t) arg); - if (retval < 0) - return retval; - break; - default: - return -EOPNOTSUPP; - }; - - return 0; -} - -static ssize_t attr_read_type(struct device *dev, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - return sprintf(buf, "0x%02x\n", dst->dst_type); -} - -static ssize_t attr_write_type(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - unsigned long type; - type = simple_strtoul(buf, NULL, 0); - dst->dst_type = type & 0xff; - return strlen(buf) + 1; -} - -/* dst_type, "Type of DST card, 0 Satellite, 1 terrestial, 2 Cable, default driver determined"); */ -static struct device_attribute dev_attr_client_type = { - .attr = {.name = "type",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE}, - .show = &attr_read_type, - .store = &attr_write_type, -}; - -static ssize_t attr_read_flags(struct device *dev, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - return sprintf(buf, "0x%02x\n", dst->type_flags); -} - -static ssize_t attr_write_flags(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - unsigned long flags; - flags = simple_strtoul(buf, NULL, 0); - dst->type_flags = flags & 0xffffffff; - return strlen(buf) + 1; -} - -/* dst_type_flags, "Type flags of DST card, bitfield 1=10 byte tuner, 2=TS is 204, 4=symdiv"); */ -static struct device_attribute dev_attr_client_flags = { - .attr = {.name = "flags",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE}, - .show = &attr_read_flags, - .store = &attr_write_flags, -}; - -static struct i2c_client client_template; - -static int attach_adapter(struct i2c_adapter *adapter) -{ - struct i2c_client *client; - struct dst_data *dst; - struct bt878 *bt; - struct dvb_frontend_info *info; - int ret; - - bt = bt878_find_by_i2c_adap(adapter); - if (!bt) - return -ENODEV; - - dst = kmalloc(sizeof(struct dst_data), GFP_KERNEL); - if (dst == NULL) { - printk(KERN_INFO "%s: Out of memory.\n", __FUNCTION__); - return -ENOMEM; - } - - memset(dst, 0, sizeof(*dst)); - dst->bt = bt; - dst->i2c = adapter; - if (dst_check_ci(dst) < 0) { - kfree(dst); - return -ENODEV; - } - dst_init(dst); - - dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, (u32) dst, (u32) (dst->bt), (u32) (dst->i2c)); - - switch (dst->dst_type) { - case DST_TYPE_IS_TERR: - info = &dst_info_terr; - break; - case DST_TYPE_IS_CABLE: - info = &dst_info_cable; - break; - case DST_TYPE_IS_SAT: - info = &dst_info_sat; - break; - default: - printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n"); - kfree(dst); - return -ENODEV; - } - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(dst); - return -ENOMEM; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = DST_I2C_ADDR; - - i2c_set_clientdata(client, (void *) dst); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(dst); - return -EFAULT; - } - - BUG_ON(!dst->dvb); - - device_create_file(&client->dev, &dev_attr_client_type); - device_create_file(&client->dev, &dev_attr_client_flags); - - ret = dvb_register_frontend(dst_ioctl, dst->dvb, dst, info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - kfree(client); - kfree(dst); - return -EFAULT; - } - - return 0; -} - -static int detach_client(struct i2c_client *client) -{ - struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client); - - dvb_unregister_frontend(dst_ioctl, state->dvb); - - device_remove_file(&client->dev, &dev_attr_client_type); - device_remove_file(&client->dev, &dev_attr_client_flags); - - i2c_detach_client(client); - BUG_ON(state->dvb); - - kfree(client); - kfree(state); - - return 0; -} - -static int command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client); - - switch (cmd) { - case FE_REGISTER: - state->dvb = (struct dvb_adapter *) arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "dst", - .id = I2C_DRIVERID_DVBFE_DST, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; - -static struct i2c_client client_template = { - I2C_DEVNAME("dst"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_dst(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_dst(void) -{ - if (i2c_del_driver(&driver)) - printk("dst: driver deregistration failed\n"); -} - -module_init(init_dst); -module_exit(exit_dst); - -MODULE_DESCRIPTION("DST DVB-S Frontend"); -MODULE_AUTHOR("Jamie Honan"); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c 2004-12-12 17:40:52 -08:00 @@ -24,244 +24,258 @@ #include #include "dvb_frontend.h" +#include "dvb_dummy_fe.h" -#define FRONTEND_NAME "dvbfe_dummy" -static int frontend_type; -module_param(frontend_type, int, 0444); -MODULE_PARM_DESC(frontend_type, "0 == DVB-S, 1 == DVB-C, 2 == DVB-T"); - -/* depending on module parameter sct deliver different infos - */ - -static struct dvb_frontend_info dvb_s_dummyfe_info = { - .name = "DVB-S dummy frontend", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 250, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, -/* .symbol_rate_tolerance = ???,*/ - .notifier_delay = 50, /* 1/20 s */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK -}; - -static struct dvb_frontend_info dvb_c_dummyfe_info = { - .name = "DVB-C dummy frontend", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = (57840000/2)/64, /* SACLK/64 == (XIN/2)/64 */ - .symbol_rate_max = (57840000/2)/4, /* SACLK/4 */ -#if 0 - .frequency_tolerance = ???, - .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ - .notifier_delay = ?, -#endif - .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO -}; - -static struct dvb_frontend_info dvb_t_dummyfe_info = { - .name = "DVB-T dummy frontend", - .type = FE_OFDM, - .frequency_min = 0, - .frequency_max = 863250000, - .frequency_stepsize = 62500, - /*.frequency_tolerance = */ /* FIXME: 12% of SR */ - .symbol_rate_min = 0, /* FIXME */ - .symbol_rate_max = 9360000, /* FIXME */ - .symbol_rate_tolerance = 4000, - .notifier_delay = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; -struct dvb_frontend_info *frontend_info(void) -{ - switch(frontend_type) { - case 2: - return &dvb_t_dummyfe_info; - case 1: - return &dvb_c_dummyfe_info; - case 0: - default: - return &dvb_s_dummyfe_info; - } -} +struct dvb_dummy_fe_state { + struct dvb_frontend_ops ops; -static int dvbdummyfe_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, frontend_info(), - sizeof(struct dvb_frontend_info)); - break; + struct dvb_frontend frontend; +}; - case FE_READ_STATUS: +static int dvb_dummy_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) { - fe_status_t *status = arg; *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - break; + + return 0; } - case FE_READ_BER: +static int dvb_dummy_fe_read_ber(struct dvb_frontend* fe, u32* ber) { - u32 *ber = (u32 *) arg; *ber = 0; - break; + return 0; } - case FE_READ_SIGNAL_STRENGTH: +static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - u8 signal = 0xff; - *((u16*) arg) = (signal << 8) | signal; - break; + *strength = 0; + return 0; } - case FE_READ_SNR: +static int dvb_dummy_fe_read_snr(struct dvb_frontend* fe, u16* snr) { - u8 snr = 0xf0; - *(u16*) arg = (snr << 8) | snr; - break; + *snr = 0; + return 0; } - case FE_READ_UNCORRECTED_BLOCKS: - *(u32*) arg = 0; - break; - - case FE_SET_FRONTEND: - break; - - case FE_GET_FRONTEND: - break; - - case FE_SLEEP: +static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + *ucblocks = 0; return 0; +} - case FE_INIT: +static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ return 0; +} - case FE_SET_TONE: - return -EOPNOTSUPP; +static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + return 0; +} - case FE_SET_VOLTAGE: +static int dvb_dummy_fe_sleep(struct dvb_frontend* fe) +{ return 0; +} - default: - return -EOPNOTSUPP; +static int dvb_dummy_fe_init(struct dvb_frontend* fe) +{ + return 0; } + +static int dvb_dummy_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ return 0; } -static struct i2c_client client_template; +static int dvb_dummy_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + return 0; +} -static int dvbdummyfe_attach_adapter(struct i2c_adapter *adapter) +static void dvb_dummy_fe_release(struct dvb_frontend* fe) { - struct dvb_adapter *dvb; - struct i2c_client *client; - int ret; + struct dvb_dummy_fe_state* state = (struct dvb_dummy_fe_state*) fe->demodulator_priv; + kfree(state); +} - if ((client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) == NULL) - return -ENOMEM; +static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; +struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) +{ + struct dvb_dummy_fe_state* state = NULL; - if ((ret = i2c_attach_client(client))) { - kfree(client); - return ret; -} + /* allocate memory for the internal state */ + state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (state == NULL) goto error; - dvb = i2c_get_clientdata(client); - BUG_ON(!dvb); + /* setup the state */ + memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); - if ((ret = dvb_register_frontend(dvbdummyfe_ioctl, dvb, NULL, - frontend_info(), THIS_MODULE))) { - kfree(client); - return ret; - } + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; - return 0; +error: + if (state) kfree(state); + return NULL; } +static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; -static int dvbdummyfe_detach_client(struct i2c_client *client) +struct dvb_frontend* dvb_dummy_fe_qpsk_attach() { - struct dvb_adapter *dvb = i2c_get_clientdata(client); + struct dvb_dummy_fe_state* state = NULL; - dvb_unregister_frontend(dvbdummyfe_ioctl, dvb); - i2c_detach_client(client); - kfree(client); - return 0; + /* allocate memory for the internal state */ + state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; } -static int dvbdummyfe_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; + +struct dvb_frontend* dvb_dummy_fe_qam_attach() { - switch(cmd) { - case FE_REGISTER: - i2c_set_clientdata(client, arg); - break; - case FE_UNREGISTER: - break; - default: - return -EOPNOTSUPP; - } + struct dvb_dummy_fe_state* state = NULL; - return 0; + /* allocate memory for the internal state */ + state = (struct dvb_dummy_fe_state*) kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; } -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_DUMMY, - .flags = I2C_DF_NOTIFY, - .attach_adapter = dvbdummyfe_attach_adapter, - .detach_client = dvbdummyfe_detach_client, - .command = dvbdummyfe_command, -}; +static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { + + .info = { + .name = "Dummy DVB-T", + .type = FE_OFDM, + .frequency_min = 0, + .frequency_max = 863250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, }; -static int __init init_dvbdummyfe (void) -{ - return i2c_add_driver(&driver); -} +static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { -static void __exit exit_dvbdummyfe (void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "dummyfe: driver deregistration failed.\n"); -} + .info = { + .name = "Dummy DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = (57840000/2)/64, /* SACLK/64 == (XIN/2)/64 */ + .symbol_rate_max = (57840000/2)/4, /* SACLK/4 */ + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, +}; +static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { -module_init(init_dvbdummyfe); -module_exit(exit_dvbdummyfe); + .info = { + .name = "Dummy DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 250, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, + .set_voltage = dvb_dummy_fe_set_voltage, + .set_tone = dvb_dummy_fe_set_tone, +}; MODULE_DESCRIPTION("DVB DUMMY Frontend"); MODULE_AUTHOR("Emard"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach); +EXPORT_SYMBOL(dvb_dummy_fe_qam_attach); +EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach); diff -Nru a/drivers/media/dvb/frontends/dvb_dummy_fe.h b/drivers/media/dvb/frontends/dvb_dummy_fe.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,32 @@ +/* + * Driver for Dummy Frontend + * + * Written by Emard + * + * 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 DVB_DUMMY_FE_H +#define DVB_DUMMY_FE_H + +#include +#include "dvb_frontend.h" + +extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void); +extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void); +extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void); + +#endif // DVB_DUMMY_FE_H diff -Nru a/drivers/media/dvb/frontends/grundig_29504-401.c b/drivers/media/dvb/frontends/grundig_29504-401.c --- a/drivers/media/dvb/frontends/grundig_29504-401.c 2004-12-12 17:40:52 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,749 +0,0 @@ -/* - driver for Grundig 29504-401 DVB-T Frontends based on - LSI L64781 COFDM demodulator as used in Technotrend DVB-T cards - - Copyright (C) 2001 Holger Waechtler - for Convergence Integrated Media GmbH - Marko Kohtala - - 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" - -#define FRONTEND_NAME "dvbfe_l64781" - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) - -static int debug; -static int old_set_tv_freq; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -module_param(old_set_tv_freq, int, 0644); -MODULE_PARM_DESC(old_set_tv_freq, "Use old tsa5060_set_tv_freq calculations."); - -struct l64781_state { - int first:1; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - -struct dvb_frontend_info l64781_info = { - .name = "Grundig 29504-401 (LSI L64781 Based)", - .type = FE_OFDM, -/* .frequency_min = ???,*/ -/* .frequency_max = ???,*/ - .frequency_stepsize = 166666, -/* .frequency_tolerance = ???,*/ -/* .symbol_rate_tolerance = ???,*/ - .notifier_delay = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_MUTE_TS -}; - - -static int l64781_writereg (struct i2c_adapter *i2c, u8 reg, u8 data) -{ - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 }; - - if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) - dprintk ("%s: write_reg error (reg == %02x) = %02x!\n", - __FUNCTION__, reg, ret); - - return (ret != 1) ? -1 : 0; -} - - -static u8 l64781_readreg (struct i2c_adapter *i2c, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - ret = i2c_transfer(i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - - return b1[0]; -} - - -static int tsa5060_write (struct i2c_adapter *i2c, u8 data [4]) -{ - int ret; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 }; - - if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) - dprintk ("%s: write_reg error == %02x!\n", __FUNCTION__, ret); - - return (ret != 1) ? -1 : 0; -} - - -/** - * set up the downconverter frequency divisor for a - * reference clock comparision frequency of 166666 Hz. - * frequency offset is 36125000 Hz. - */ -static int tsa5060_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ - u32 div; - u8 buf [4]; - u8 cfg, cpump, band_select; - - if (old_set_tv_freq) - div = (36000000 + freq) / 166666; - else - div = (36125000 + freq) / 166666; - - cfg = 0x88; - - cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 : - freq < 470000000 ? 2 : freq < 750000000 ? 1 : 3; - - band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03; - - buf [0] = (div >> 8) & 0x7f; - buf [1] = div & 0xff; - buf [2] = ((div >> 10) & 0x60) | cfg; - - if (old_set_tv_freq) - buf [3] = 0xc0; - else - buf [3] = (cpump << 6) | band_select; - - return tsa5060_write (i2c, buf); -} - - - -static void apply_tps (struct i2c_adapter *i2c) -{ - l64781_writereg (i2c, 0x2a, 0x00); - l64781_writereg (i2c, 0x2a, 0x01); - - /* This here is a little bit questionable because it enables - the automatic update of TPS registers. I think we'd need to - handle the IRQ from FE to update some other registers as - well, or at least implement some magic to tuning to correct - to the TPS received from transmission. */ - l64781_writereg (i2c, 0x2a, 0x02); -} - - -static void reset_afc (struct i2c_adapter *i2c) -{ - /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for - timing offset */ - l64781_writereg (i2c, 0x07, 0x9e); /* stall AFC */ - l64781_writereg (i2c, 0x08, 0); /* AFC INIT FREQ */ - l64781_writereg (i2c, 0x09, 0); - l64781_writereg (i2c, 0x0a, 0); - l64781_writereg (i2c, 0x07, 0x8e); - l64781_writereg (i2c, 0x0e, 0); /* AGC gain to zero in beginning */ - l64781_writereg (i2c, 0x11, 0x80); /* stall TIM */ - l64781_writereg (i2c, 0x10, 0); /* TIM_OFFSET_LSB */ - l64781_writereg (i2c, 0x12, 0); - l64781_writereg (i2c, 0x13, 0); - l64781_writereg (i2c, 0x11, 0x00); -} - - -static int apply_frontend_param (struct i2c_adapter *i2c, - struct dvb_frontend_parameters *param) -{ - /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ - static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; - /* QPSK, QAM_16, QAM_64 */ - static const u8 qam_tab [] = { 2, 4, 0, 6 }; - static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */ - static const u8 guard_tab [] = { 1, 2, 4, 8 }; - /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ - static const u32 ppm = 8000; - struct dvb_ofdm_parameters *p = ¶m->u.ofdm; - u32 ddfs_offset_fixed; -/* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ -/* bw_tab[p->bandWidth]<<10)/15625; */ - u32 init_freq; - u32 spi_bias; - u8 val0x04; - u8 val0x05; - u8 val0x06; - int bw = p->bandwidth - BANDWIDTH_8_MHZ; - - if (param->inversion != INVERSION_ON && - param->inversion != INVERSION_OFF) - return -EINVAL; - - if (bw < 0 || bw > 2) - return -EINVAL; - - if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && - p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 && - p->code_rate_HP != FEC_7_8) - return -EINVAL; - - if (p->hierarchy_information != HIERARCHY_NONE && - (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && - p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && - p->code_rate_LP != FEC_7_8)) - return -EINVAL; - - if (p->constellation != QPSK && p->constellation != QAM_16 && - p->constellation != QAM_64) - return -EINVAL; - - if (p->transmission_mode != TRANSMISSION_MODE_2K && - p->transmission_mode != TRANSMISSION_MODE_8K) - return -EINVAL; - - if (p->guard_interval < GUARD_INTERVAL_1_32 || - p->guard_interval > GUARD_INTERVAL_1_4) - return -EINVAL; - - if (p->hierarchy_information < HIERARCHY_NONE || - p->hierarchy_information > HIERARCHY_4) - return -EINVAL; - - ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000; - - /* This works up to 20000 ppm, it overflows if too large ppm! */ - init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / - bw_tab[p->bandwidth] & 0xFFFFFF); - - /* SPI bias calculation is slightly modified to fit in 32bit */ - /* will work for high ppm only... */ - spi_bias = 378 * (1 << 10); - spi_bias *= 16; - spi_bias *= bw_tab[p->bandwidth]; - spi_bias *= qam_tab[p->constellation]; - spi_bias /= p->code_rate_HP + 1; - spi_bias /= (guard_tab[p->guard_interval] + 32); - spi_bias *= 1000ULL; - spi_bias /= 1000ULL + ppm/1000; - spi_bias *= p->code_rate_HP; - - val0x04 = (p->transmission_mode << 2) | p->guard_interval; - val0x05 = fec_tab[p->code_rate_HP]; - - if (p->hierarchy_information != HIERARCHY_NONE) - val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; - - val0x06 = (p->hierarchy_information << 2) | p->constellation; - - l64781_writereg (i2c, 0x04, val0x04); - l64781_writereg (i2c, 0x05, val0x05); - l64781_writereg (i2c, 0x06, val0x06); - - reset_afc (i2c); - - /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */ - l64781_writereg (i2c, 0x15, - p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3); - l64781_writereg (i2c, 0x16, init_freq & 0xff); - l64781_writereg (i2c, 0x17, (init_freq >> 8) & 0xff); - l64781_writereg (i2c, 0x18, (init_freq >> 16) & 0xff); - - l64781_writereg (i2c, 0x1b, spi_bias & 0xff); - l64781_writereg (i2c, 0x1c, (spi_bias >> 8) & 0xff); - l64781_writereg (i2c, 0x1d, ((spi_bias >> 16) & 0x7f) | - (param->inversion == INVERSION_ON ? 0x80 : 0x00)); - - l64781_writereg (i2c, 0x22, ddfs_offset_fixed & 0xff); - l64781_writereg (i2c, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); - - l64781_readreg (i2c, 0x00); /* clear interrupt registers... */ - l64781_readreg (i2c, 0x01); /* dto. */ - - apply_tps (i2c); - - return 0; -} - - -static int reset_and_configure (struct i2c_adapter *i2c) -{ - u8 buf [] = { 0x06 }; - struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 }; - - return (i2c_transfer(i2c, &msg, 1) == 1) ? 0 : -ENODEV; -} - - -static int get_frontend(struct i2c_adapter* i2c, struct dvb_frontend_parameters* param) -{ - int tmp; - - - tmp = l64781_readreg(i2c, 0x04); - switch(tmp & 3) { - case 0: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; - break; - } - switch((tmp >> 2) & 3) { - case 0: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - break; - case 1: - param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - break; - default: - printk("Unexpected value for transmission_mode\n"); - } - - - - tmp = l64781_readreg(i2c, 0x05); - switch(tmp & 7) { - case 0: - param->u.ofdm.code_rate_HP = FEC_1_2; - break; - case 1: - param->u.ofdm.code_rate_HP = FEC_2_3; - break; - case 2: - param->u.ofdm.code_rate_HP = FEC_3_4; - break; - case 3: - param->u.ofdm.code_rate_HP = FEC_5_6; - break; - case 4: - param->u.ofdm.code_rate_HP = FEC_7_8; - break; - default: - printk("Unexpected value for code_rate_HP\n"); - } - switch((tmp >> 3) & 7) { - case 0: - param->u.ofdm.code_rate_LP = FEC_1_2; - break; - case 1: - param->u.ofdm.code_rate_LP = FEC_2_3; - break; - case 2: - param->u.ofdm.code_rate_LP = FEC_3_4; - break; - case 3: - param->u.ofdm.code_rate_LP = FEC_5_6; - break; - case 4: - param->u.ofdm.code_rate_LP = FEC_7_8; - break; - default: - printk("Unexpected value for code_rate_LP\n"); - } - - - tmp = l64781_readreg(i2c, 0x06); - switch(tmp & 3) { - case 0: - param->u.ofdm.constellation = QPSK; - break; - case 1: - param->u.ofdm.constellation = QAM_16; - break; - case 2: - param->u.ofdm.constellation = QAM_64; - break; - default: - printk("Unexpected value for constellation\n"); - } - switch((tmp >> 2) & 7) { - case 0: - param->u.ofdm.hierarchy_information = HIERARCHY_NONE; - break; - case 1: - param->u.ofdm.hierarchy_information = HIERARCHY_1; - break; - case 2: - param->u.ofdm.hierarchy_information = HIERARCHY_2; - break; - case 3: - param->u.ofdm.hierarchy_information = HIERARCHY_4; - break; - default: - printk("Unexpected value for hierarchy\n"); - } - - - tmp = l64781_readreg (i2c, 0x1d); - param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; - - tmp = (int) (l64781_readreg (i2c, 0x08) | - (l64781_readreg (i2c, 0x09) << 8) | - (l64781_readreg (i2c, 0x0a) << 16)); - param->frequency += tmp; - - return 0; -} - - -static int init (struct i2c_adapter *i2c) -{ - reset_and_configure (i2c); - - /* Power up */ - l64781_writereg (i2c, 0x3e, 0xa5); - - /* Reset hard */ - l64781_writereg (i2c, 0x2a, 0x04); - l64781_writereg (i2c, 0x2a, 0x00); - - /* Set tuner specific things */ - /* AFC_POL, set also in reset_afc */ - l64781_writereg (i2c, 0x07, 0x8e); - - /* Use internal ADC */ - l64781_writereg (i2c, 0x0b, 0x81); - - /* AGC loop gain, and polarity is positive */ - l64781_writereg (i2c, 0x0c, 0x84); - - /* Internal ADC outputs two's complement */ - l64781_writereg (i2c, 0x0d, 0x8c); - - /* With ppm=8000, it seems the DTR_SENSITIVITY will result in - value of 2 with all possible bandwidths and guard - intervals, which is the initial value anyway. */ - /*l64781_writereg (i2c, 0x19, 0x92);*/ - - /* Everything is two's complement, soft bit and CSI_OUT too */ - l64781_writereg (i2c, 0x1e, 0x09); - - return 0; -} - - -static -int l64781_ioctl (struct dvb_frontend *fe, - unsigned int cmd, void *arg) -{ - struct l64781_state* state = fe->data; - struct i2c_adapter *i2c = state->i2c; - int res; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &l64781_info, - sizeof(struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: - { - fe_status_t *status = (fe_status_t *) arg; - int sync = l64781_readreg (i2c, 0x32); - int gain = l64781_readreg (i2c, 0x0e); - - l64781_readreg (i2c, 0x00); /* clear interrupt registers... */ - l64781_readreg (i2c, 0x01); /* dto. */ - - *status = 0; - - if (gain > 5) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x02) /* VCXO locked, this criteria should be ok */ - *status |= FE_HAS_CARRIER; - - if (sync & 0x20) - *status |= FE_HAS_VITERBI; - - if (sync & 0x40) - *status |= FE_HAS_SYNC; - - if (sync == 0x7f) - *status |= FE_HAS_LOCK; - - break; - } - - case FE_READ_BER: - { - /* XXX FIXME: set up counting period (reg 0x26...0x28) - */ - u32 *ber = (u32 *) arg; - *ber = l64781_readreg (i2c, 0x39) - | (l64781_readreg (i2c, 0x3a) << 8); - break; - } - - case FE_READ_SIGNAL_STRENGTH: - { - u8 gain = l64781_readreg (i2c, 0x0e); - *(u16 *) arg = (gain << 8) | gain; - break; - } - - case FE_READ_SNR: - { - u16 *snr = (u16 *) arg; - u8 avg_quality = 0xff - l64781_readreg (i2c, 0x33); - *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/ - break; - } - - case FE_READ_UNCORRECTED_BLOCKS: - { - u32 *ub = (u32 *) arg; - *ub = l64781_readreg (i2c, 0x37) - | (l64781_readreg (i2c, 0x38) << 8); - break; - } - - case FE_SET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - tsa5060_set_tv_freq (i2c, p->frequency); - return apply_frontend_param (i2c, p); - } - - case FE_GET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - return get_frontend(i2c, p); - } - - case FE_SLEEP: - /* Power down */ - return l64781_writereg (i2c, 0x3e, 0x5a); - - case FE_INIT: - res = init (i2c); - if ((res == 0) && (state->first)) { - state->first = 0; - msleep(200); - } - return res; - - case FE_GET_TUNE_SETTINGS: - { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; - fesettings->min_delay_ms = 200; - fesettings->step_size = 166667; - fesettings->max_drift = 166667*2; - return 0; - } - - default: - dprintk ("%s: unknown command !!!\n", __FUNCTION__); - return -EINVAL; - }; - - return 0; -} - -static int l64781_probe(struct i2c_adapter *i2c) -{ - u8 reg0x3e; - u8 b0 [] = { 0x1a }; - u8 b1 [] = { 0x00 }; - struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - - /** - * the L64781 won't show up before we send the reset_and_configure() - * broadcast. If nothing responds there is no L64781 on the bus... - */ - if (reset_and_configure(i2c) < 0) { - dprintk("No response to reset and configure broadcast...\n"); - return -ENODEV; - } - - /* The chip always responds to reads */ - if (i2c_transfer(i2c, msg, 2) != 2) { - dprintk("No response to read on I2C bus\n"); - return -ENODEV; - } - - /* Save current register contents for bailout */ - reg0x3e = l64781_readreg(i2c, 0x3e); - - /* Reading the POWER_DOWN register always returns 0 */ - if (reg0x3e != 0) { - dprintk("Device doesn't look like L64781\n"); - return -ENODEV; - } - - /* Turn the chip off */ - l64781_writereg (i2c, 0x3e, 0x5a); - - /* Responds to all reads with 0 */ - if (l64781_readreg(i2c, 0x1a) != 0) { - dprintk("Read 1 returned unexpcted value\n"); - goto out; - } - - /* Turn the chip on */ - l64781_writereg (i2c, 0x3e, 0xa5); - - /* Responds with register default value */ - if (l64781_readreg(i2c, 0x1a) != 0xa1) { - dprintk("Read 2 returned unexpcted value\n"); - goto out; - } - - return 0; -out: - l64781_writereg (i2c, 0x3e, reg0x3e); /* restore reg 0x3e */ - return -ENODEV; - } - -static struct i2c_client client_template; - -static int l64781_attach_adapter(struct i2c_adapter *adapter) -{ - struct l64781_state *state; - struct i2c_client *client; - int ret; - - dprintk("Trying to attach to adapter 0x%x:%s.\n", - adapter->id, adapter->name); - - if ((ret = l64781_probe(adapter))) - return ret; - - if ( !(state = kmalloc(sizeof(struct l64781_state), GFP_KERNEL)) ) - return -ENOMEM; - - memset(state, 0, sizeof(struct l64781_state)); - state->i2c = adapter; - state->first = 1; - - if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) { - kfree(state); - return -ENOMEM; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = 0; //XXX - i2c_set_clientdata(client, state); - - if ((ret = i2c_attach_client(client))) { - kfree(state); - kfree(client); - return ret; - } - - BUG_ON(!state->dvb); - - if ((ret = dvb_register_frontend(l64781_ioctl, state->dvb, state, - &l64781_info, THIS_MODULE))) { - i2c_detach_client(client); - kfree(state); - kfree(client); - return ret; - } - - return 0; -} - -static int l64781_detach_client(struct i2c_client *client) -{ - struct l64781_state *state = i2c_get_clientdata(client); - - dvb_unregister_frontend(l64781_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} - -static int l64781_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct l64781_state *data = i2c_get_clientdata(client); - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_REGISTER: { - data->dvb = arg; - break; - } - case FE_UNREGISTER: { - data->dvb = NULL; - break; - } - default: - return -EOPNOTSUPP; - } - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_L64781, - .flags = I2C_DF_NOTIFY, - .attach_adapter = l64781_attach_adapter, - .detach_client = l64781_detach_client, - .command = l64781_command, -}; - -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_l64781 (void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_l64781 (void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "l64781: driver deregistration failed\n"); -} - -module_init(init_l64781); -module_exit(exit_l64781); - -MODULE_DESCRIPTION("Grundig 29504-401 DVB-T Frontend (LSI L64781 Based)"); -MODULE_AUTHOR("Holger Waechtler, Marko Kohtala"); -MODULE_LICENSE("GPL"); - diff -Nru a/drivers/media/dvb/frontends/grundig_29504-491.c b/drivers/media/dvb/frontends/grundig_29504-491.c --- a/drivers/media/dvb/frontends/grundig_29504-491.c 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,557 +0,0 @@ -/* - Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend - - Copyright (C) 2001 Convergence Integrated Media GmbH - - written by Ralph Metzler - - adoption to the new DVB frontend API and diagnostic ioctl's - by Holger Waechtler - - 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" - -#define FRONTEND_NAME "dvbfe_tda8083" - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) - -static int debug; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); - - -struct tda8083_state { - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - -static struct dvb_frontend_info tda8083_info = { - .name = "Grundig 29504-491, (TDA8083 based)", - .type = FE_QPSK, - .frequency_min = 950000, /* FIXME: guessed! */ - .frequency_max = 1400000, /* FIXME: guessed! */ - .frequency_stepsize = 125, /* kHz for QPSK frontends */ -/* .frequency_tolerance = ???,*/ - .symbol_rate_min = 1000000, /* FIXME: guessed! */ - .symbol_rate_max = 45000000, /* FIXME: guessed! */ -/* .symbol_rate_tolerance = ???,*/ - .notifier_delay = 0, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_MUTE_TS -}; - - - -static u8 tda8083_init_tab [] = { - 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea, - 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10, - 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8, - 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00, - 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - - -static int tda8083_writereg (struct i2c_adapter *i2c, u8 reg, u8 data) -{ - int ret; - u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 }; - - ret = i2c_transfer(i2c, &msg, 1); - - if (ret != 1) - dprintk ("%s: writereg error (reg %02x, ret == %i)\n", - __FUNCTION__, reg, ret); - - return (ret != 1) ? -1 : 0; -} - - -static int tda8083_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len) -{ - int ret; - struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = ®1, .len = 1 }, - { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } }; - - ret = i2c_transfer(i2c, msg, 2); - - if (ret != 2) - dprintk ("%s: readreg error (reg %02x, ret == %i)\n", - __FUNCTION__, reg1, ret); - - return ret == 2 ? 0 : -1; -} - - -static inline u8 tda8083_readreg (struct i2c_adapter *i2c, u8 reg) -{ - u8 val; - - tda8083_readregs (i2c, reg, &val, 1); - - return val; -} - - -static int tsa5522_write (struct i2c_adapter *i2c, u8 data [4]) -{ - int ret; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = 4 }; - - ret = i2c_transfer(i2c, &msg, 1); - - if (ret != 1) - dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); - - return (ret != 1) ? -1 : 0; -} - - -/** - * set up the downconverter frequency divisor for a - * reference clock comparision frequency of 125 kHz. - */ -static int tsa5522_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ - u32 div = freq / 125; - u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x8e, 0x00 }; - - return tsa5522_write (i2c, buf); -} - - -static int tda8083_init (struct i2c_adapter *i2c) -{ - int i; - - dprintk("%s: init TDA8083\n", __FILE__); - - for (i=0; i<44; i++) - tda8083_writereg (i2c, i, tda8083_init_tab[i]); - - return 0; -} - - -static int tda8083_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion) -{ - /* XXX FIXME: implement other modes than FEC_AUTO */ - if (inversion == INVERSION_AUTO) - return 0; - - return -EINVAL; -} - - -static int tda8083_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec) -{ - if (fec == FEC_AUTO) - return tda8083_writereg (i2c, 0x07, 0xff); - - if (fec >= FEC_1_2 && fec <= FEC_8_9) - return tda8083_writereg (i2c, 0x07, 1 << (FEC_8_9 - fec)); - - return -EINVAL; -} - - -static fe_code_rate_t tda8083_get_fec (struct i2c_adapter *i2c) -{ - u8 index; - static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, - FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 }; - - index = tda8083_readreg(i2c, 0x0e) & 0x07; - - return fec_tab [index]; -} - - -static int tda8083_set_symbolrate (struct i2c_adapter *i2c, u32 srate) -{ - u32 ratio; - u32 tmp; - u8 filter; - - if (srate > 32000000) - srate = 32000000; - if (srate < 500000) - srate = 500000; - - filter = 0; - if (srate < 24000000) - filter = 2; - if (srate < 16000000) - filter = 3; - - tmp = 31250 << 16; - ratio = tmp / srate; - - tmp = (tmp % srate) << 8; - ratio = (ratio << 8) + tmp / srate; - - tmp = (tmp % srate) << 8; - ratio = (ratio << 8) + tmp / srate; - - dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio); - - tda8083_writereg (i2c, 0x05, filter); - tda8083_writereg (i2c, 0x02, (ratio >> 16) & 0xff); - tda8083_writereg (i2c, 0x03, (ratio >> 8) & 0xff); - tda8083_writereg (i2c, 0x04, (ratio ) & 0xff); - - tda8083_writereg (i2c, 0x00, 0x3c); - tda8083_writereg (i2c, 0x00, 0x04); - - return 1; -} - - -static void tda8083_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout) -{ - unsigned long start = jiffies; - - while (jiffies - start < timeout && - !(tda8083_readreg(i2c, 0x02) & 0x80)) - { - msleep(50); - }; -} - - -static int tda8083_send_diseqc_msg (struct i2c_adapter *i2c, - struct dvb_diseqc_master_cmd *m) -{ - int i; - - tda8083_writereg (i2c, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */ - - for (i=0; imsg_len; i++) - tda8083_writereg (i2c, 0x23 + i, m->msg[i]); - - tda8083_writereg (i2c, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */ - - tda8083_wait_diseqc_fifo (i2c, 100); - - return 0; -} - - -static int tda8083_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst) -{ - switch (burst) { - case SEC_MINI_A: - tda8083_writereg (i2c, 0x29, (5 << 2)); /* send burst A */ - break; - case SEC_MINI_B: - tda8083_writereg (i2c, 0x29, (7 << 2)); /* send B */ - break; - default: - return -EINVAL; - }; - - tda8083_wait_diseqc_fifo (i2c, 100); - - return 0; -} - - -static int tda8083_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone) -{ - tda8083_writereg (i2c, 0x26, 0xf1); - - switch (tone) { - case SEC_TONE_OFF: - return tda8083_writereg (i2c, 0x29, 0x00); - case SEC_TONE_ON: - return tda8083_writereg (i2c, 0x29, 0x80); - default: - return -EINVAL; - }; -} - - -static int tda8083_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage) -{ - switch (voltage) { - case SEC_VOLTAGE_13: - return tda8083_writereg (i2c, 0x20, 0x00); - case SEC_VOLTAGE_18: - return tda8083_writereg (i2c, 0x20, 0x11); - default: - return -EINVAL; - }; -} - - -static int tda8083_ioctl(struct dvb_frontend *fe, unsigned int cmd, - void *arg) -{ - struct tda8083_state *state = fe->data; - struct i2c_adapter *i2c = state->i2c; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &tda8083_info, sizeof(struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: - { - fe_status_t *status=(fe_status_t *) arg; - u8 signal = ~tda8083_readreg (i2c, 0x01); - u8 sync = tda8083_readreg (i2c, 0x02); - - *status = 0; - - if (signal > 10) - *status |= FE_HAS_SIGNAL; - - if (sync & 0x01) - *status |= FE_HAS_CARRIER; - - if (sync & 0x02) - *status |= FE_HAS_VITERBI; - - if (sync & 0x10) - *status |= FE_HAS_SYNC; - - if ((sync & 0x1f) == 0x1f) - *status |= FE_HAS_LOCK; - - break; - } - - case FE_READ_BER: - *((u32*) arg) = 0; /* XXX FIXME: implement me!!! */ - return -EOPNOTSUPP; - - case FE_READ_SIGNAL_STRENGTH: - { - u8 signal = ~tda8083_readreg (i2c, 0x01); - *((u16*) arg) = (signal << 8) | signal; - break; - } - case FE_READ_SNR: - { - u8 snr = tda8083_readreg (i2c, 0x08); - *((u16*) arg) = (snr << 8) | snr; - break; - } - case FE_READ_UNCORRECTED_BLOCKS: - *((u32*) arg) = 0; /* XXX FIXME: implement me!!! */ - return -EOPNOTSUPP; - - - case FE_SET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - tsa5522_set_tv_freq (i2c, p->frequency); - tda8083_set_inversion (i2c, p->inversion); - tda8083_set_fec (i2c, p->u.qpsk.fec_inner); - tda8083_set_symbolrate (i2c, p->u.qpsk.symbol_rate); - - tda8083_writereg (i2c, 0x00, 0x3c); - tda8083_writereg (i2c, 0x00, 0x04); - - break; - } - - case FE_GET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - /* FIXME: get symbolrate & frequency offset...*/ - /*p->frequency = ???;*/ - p->inversion = (tda8083_readreg (i2c, 0x0e) & 0x80) ? - INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = tda8083_get_fec (i2c); - /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (i2c);*/ - break; - } - - case FE_SLEEP: - tda8083_writereg (i2c, 0x00, 0x02); - break; - - case FE_INIT: - tda8083_init (i2c); - tda8083_writereg (i2c, 0x00, 0x3c); - tda8083_writereg (i2c, 0x00, 0x04); - break; - - case FE_DISEQC_SEND_MASTER_CMD: - return tda8083_send_diseqc_msg (i2c, arg); - - case FE_DISEQC_SEND_BURST: - tda8083_send_diseqc_burst (i2c, (fe_sec_mini_cmd_t) arg); - tda8083_writereg (i2c, 0x00, 0x3c); - tda8083_writereg (i2c, 0x00, 0x04); - - break; - - case FE_SET_TONE: - tda8083_set_tone (i2c, (fe_sec_tone_mode_t) arg); - tda8083_writereg (i2c, 0x00, 0x3c); - tda8083_writereg (i2c, 0x00, 0x04); - break; - - case FE_SET_VOLTAGE: - tda8083_set_voltage (i2c, (fe_sec_voltage_t) arg); - tda8083_writereg (i2c, 0x00, 0x3c); - tda8083_writereg (i2c, 0x00, 0x04); - break; - - default: - return -EOPNOTSUPP; - }; - - return 0; -} - -static struct i2c_client client_template; - -static int tda8083_attach_adapter(struct i2c_adapter *adapter) -{ - struct tda8083_state *state; - struct i2c_client *client; - int ret; - - dprintk("Trying to attach to adapter 0x%x:%s.\n", - adapter->id, adapter->name); - - if ((tda8083_readreg (adapter, 0x00)) != 0x05) - return -ENODEV; - - if ( !(state = kmalloc(sizeof(struct tda8083_state), GFP_KERNEL)) ) - return -ENOMEM; - - if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) { - kfree(state); - return -ENOMEM; - } - - memset(state, 0, sizeof(struct tda8083_state)); - state->i2c = adapter; - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = 0; //XXX - i2c_set_clientdata(client, state); - - if ((ret = i2c_attach_client(client))) { - kfree(state); - kfree(client); - return ret; -} - - BUG_ON(!state->dvb); - - if ((ret = dvb_register_frontend(tda8083_ioctl, state->dvb, state, - &tda8083_info, THIS_MODULE))) { - i2c_detach_client(client); - kfree(state); - kfree(client); - return ret; - } - - return 0; -} - -static int tda8083_detach_client(struct i2c_client *client) -{ - struct tda8083_state *state = i2c_get_clientdata(client); - - dvb_unregister_frontend (tda8083_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} - -static int tda8083_command (struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct tda8083_state *data = i2c_get_clientdata(client); - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_REGISTER: { - data->dvb = arg; - break; - } - case FE_UNREGISTER: { - data->dvb = NULL; - break; - } - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_TDA8083, - .flags = I2C_DF_NOTIFY, - .attach_adapter = tda8083_attach_adapter, - .detach_client = tda8083_detach_client, - .command = tda8083_command, -}; - -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_tda8083 (void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_tda8083 (void) -{ - if (i2c_del_driver(&driver)) - printk("grundig_29504_401: driver deregistration failed\n"); -} - -module_init(init_tda8083); -module_exit(exit_tda8083); - -MODULE_DESCRIPTION("Grundig 29504-491 DVB frontend driver (TDA8083 Based)"); -MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); -MODULE_LICENSE("GPL"); - diff -Nru a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/l64781.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,607 @@ +/* + driver for LSI L64781 COFDM demodulator + + Copyright (C) 2001 Holger Waechtler + for Convergence Integrated Media GmbH + Marko Kohtala + + 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 "l64781.h" + + +struct l64781_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + const struct l64781_config* config; + + struct dvb_frontend frontend; + + /* private demodulator data */ + int first:1; +}; + +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "l64781: " args); \ + } while (0) + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + + +static int l64781_writereg (struct l64781_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) + dprintk ("%s: write_reg error (reg == %02x) = %02x!\n", + __FUNCTION__, reg, ret); + + return (ret != 1) ? -1 : 0; +} + +static int l64781_readreg (struct l64781_state* state, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) return ret; + + return b1[0]; +} + +static void apply_tps (struct l64781_state* state) +{ + l64781_writereg (state, 0x2a, 0x00); + l64781_writereg (state, 0x2a, 0x01); + + /* This here is a little bit questionable because it enables + the automatic update of TPS registers. I think we'd need to + handle the IRQ from FE to update some other registers as + well, or at least implement some magic to tuning to correct + to the TPS received from transmission. */ + l64781_writereg (state, 0x2a, 0x02); +} + + +static void reset_afc (struct l64781_state* state) +{ + /* Set AFC stall for the AFC_INIT_FRQ setting, TIM_STALL for + timing offset */ + l64781_writereg (state, 0x07, 0x9e); /* stall AFC */ + l64781_writereg (state, 0x08, 0); /* AFC INIT FREQ */ + l64781_writereg (state, 0x09, 0); + l64781_writereg (state, 0x0a, 0); + l64781_writereg (state, 0x07, 0x8e); + l64781_writereg (state, 0x0e, 0); /* AGC gain to zero in beginning */ + l64781_writereg (state, 0x11, 0x80); /* stall TIM */ + l64781_writereg (state, 0x10, 0); /* TIM_OFFSET_LSB */ + l64781_writereg (state, 0x12, 0); + l64781_writereg (state, 0x13, 0); + l64781_writereg (state, 0x11, 0x00); +} + +static int reset_and_configure (struct l64781_state* state) +{ + u8 buf [] = { 0x06 }; + struct i2c_msg msg = { .addr = 0x00, .flags = 0, .buf = buf, .len = 1 }; + // NOTE: this is correct in writing to address 0x00 + + return (i2c_transfer(state->i2c, &msg, 1) == 1) ? 0 : -ENODEV; +} + +static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_parameters *param) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + /* The coderates for FEC_NONE, FEC_4_5 and FEC_FEC_6_7 are arbitrary */ + static const u8 fec_tab[] = { 7, 0, 1, 2, 9, 3, 10, 4 }; + /* QPSK, QAM_16, QAM_64 */ + static const u8 qam_tab [] = { 2, 4, 0, 6 }; + static const u8 bw_tab [] = { 8, 7, 6 }; /* 8Mhz, 7MHz, 6MHz */ + static const u8 guard_tab [] = { 1, 2, 4, 8 }; + /* The Grundig 29504-401.04 Tuner comes with 18.432MHz crystal. */ + static const u32 ppm = 8000; + struct dvb_ofdm_parameters *p = ¶m->u.ofdm; + u32 ddfs_offset_fixed; +/* u32 ddfs_offset_variable = 0x6000-((1000000UL+ppm)/ */ +/* bw_tab[p->bandWidth]<<10)/15625; */ + u32 init_freq; + u32 spi_bias; + u8 val0x04; + u8 val0x05; + u8 val0x06; + int bw = p->bandwidth - BANDWIDTH_8_MHZ; + + state->config->pll_set(fe, param); + + if (param->inversion != INVERSION_ON && + param->inversion != INVERSION_OFF) + return -EINVAL; + + if (bw < 0 || bw > 2) + return -EINVAL; + + if (p->code_rate_HP != FEC_1_2 && p->code_rate_HP != FEC_2_3 && + p->code_rate_HP != FEC_3_4 && p->code_rate_HP != FEC_5_6 && + p->code_rate_HP != FEC_7_8) + return -EINVAL; + + if (p->hierarchy_information != HIERARCHY_NONE && + (p->code_rate_LP != FEC_1_2 && p->code_rate_LP != FEC_2_3 && + p->code_rate_LP != FEC_3_4 && p->code_rate_LP != FEC_5_6 && + p->code_rate_LP != FEC_7_8)) + return -EINVAL; + + if (p->constellation != QPSK && p->constellation != QAM_16 && + p->constellation != QAM_64) + return -EINVAL; + + if (p->transmission_mode != TRANSMISSION_MODE_2K && + p->transmission_mode != TRANSMISSION_MODE_8K) + return -EINVAL; + + if (p->guard_interval < GUARD_INTERVAL_1_32 || + p->guard_interval > GUARD_INTERVAL_1_4) + return -EINVAL; + + if (p->hierarchy_information < HIERARCHY_NONE || + p->hierarchy_information > HIERARCHY_4) + return -EINVAL; + + ddfs_offset_fixed = 0x4000-(ppm<<16)/bw_tab[p->bandwidth]/1000000; + + /* This works up to 20000 ppm, it overflows if too large ppm! */ + init_freq = (((8UL<<25) + (8UL<<19) / 25*ppm / (15625/25)) / + bw_tab[p->bandwidth] & 0xFFFFFF); + + /* SPI bias calculation is slightly modified to fit in 32bit */ + /* will work for high ppm only... */ + spi_bias = 378 * (1 << 10); + spi_bias *= 16; + spi_bias *= bw_tab[p->bandwidth]; + spi_bias *= qam_tab[p->constellation]; + spi_bias /= p->code_rate_HP + 1; + spi_bias /= (guard_tab[p->guard_interval] + 32); + spi_bias *= 1000ULL; + spi_bias /= 1000ULL + ppm/1000; + spi_bias *= p->code_rate_HP; + + val0x04 = (p->transmission_mode << 2) | p->guard_interval; + val0x05 = fec_tab[p->code_rate_HP]; + + if (p->hierarchy_information != HIERARCHY_NONE) + val0x05 |= (p->code_rate_LP - FEC_1_2) << 3; + + val0x06 = (p->hierarchy_information << 2) | p->constellation; + + l64781_writereg (state, 0x04, val0x04); + l64781_writereg (state, 0x05, val0x05); + l64781_writereg (state, 0x06, val0x06); + + reset_afc (state); + + /* Technical manual section 2.6.1, TIM_IIR_GAIN optimal values */ + l64781_writereg (state, 0x15, + p->transmission_mode == TRANSMISSION_MODE_2K ? 1 : 3); + l64781_writereg (state, 0x16, init_freq & 0xff); + l64781_writereg (state, 0x17, (init_freq >> 8) & 0xff); + l64781_writereg (state, 0x18, (init_freq >> 16) & 0xff); + + l64781_writereg (state, 0x1b, spi_bias & 0xff); + l64781_writereg (state, 0x1c, (spi_bias >> 8) & 0xff); + l64781_writereg (state, 0x1d, ((spi_bias >> 16) & 0x7f) | + (param->inversion == INVERSION_ON ? 0x80 : 0x00)); + + l64781_writereg (state, 0x22, ddfs_offset_fixed & 0xff); + l64781_writereg (state, 0x23, (ddfs_offset_fixed >> 8) & 0x3f); + + l64781_readreg (state, 0x00); /* clear interrupt registers... */ + l64781_readreg (state, 0x01); /* dto. */ + + apply_tps (state); + + return 0; +} + +static int get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* param) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + int tmp; + + + tmp = l64781_readreg(state, 0x04); + switch(tmp & 3) { + case 0: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + param->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; + } + switch((tmp >> 2) & 3) { + case 0: + param->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + param->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + printk("Unexpected value for transmission_mode\n"); + } + + + + tmp = l64781_readreg(state, 0x05); + switch(tmp & 7) { + case 0: + param->u.ofdm.code_rate_HP = FEC_1_2; + break; + case 1: + param->u.ofdm.code_rate_HP = FEC_2_3; + break; + case 2: + param->u.ofdm.code_rate_HP = FEC_3_4; + break; + case 3: + param->u.ofdm.code_rate_HP = FEC_5_6; + break; + case 4: + param->u.ofdm.code_rate_HP = FEC_7_8; + break; + default: + printk("Unexpected value for code_rate_HP\n"); + } + switch((tmp >> 3) & 7) { + case 0: + param->u.ofdm.code_rate_LP = FEC_1_2; + break; + case 1: + param->u.ofdm.code_rate_LP = FEC_2_3; + break; + case 2: + param->u.ofdm.code_rate_LP = FEC_3_4; + break; + case 3: + param->u.ofdm.code_rate_LP = FEC_5_6; + break; + case 4: + param->u.ofdm.code_rate_LP = FEC_7_8; + break; + default: + printk("Unexpected value for code_rate_LP\n"); + } + + + tmp = l64781_readreg(state, 0x06); + switch(tmp & 3) { + case 0: + param->u.ofdm.constellation = QPSK; + break; + case 1: + param->u.ofdm.constellation = QAM_16; + break; + case 2: + param->u.ofdm.constellation = QAM_64; + break; + default: + printk("Unexpected value for constellation\n"); + } + switch((tmp >> 2) & 7) { + case 0: + param->u.ofdm.hierarchy_information = HIERARCHY_NONE; + break; + case 1: + param->u.ofdm.hierarchy_information = HIERARCHY_1; + break; + case 2: + param->u.ofdm.hierarchy_information = HIERARCHY_2; + break; + case 3: + param->u.ofdm.hierarchy_information = HIERARCHY_4; + break; + default: + printk("Unexpected value for hierarchy\n"); + } + + + tmp = l64781_readreg (state, 0x1d); + param->inversion = (tmp & 0x80) ? INVERSION_ON : INVERSION_OFF; + + tmp = (int) (l64781_readreg (state, 0x08) | + (l64781_readreg (state, 0x09) << 8) | + (l64781_readreg (state, 0x0a) << 16)); + param->frequency += tmp; + + return 0; +} + +static int l64781_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + int sync = l64781_readreg (state, 0x32); + int gain = l64781_readreg (state, 0x0e); + + l64781_readreg (state, 0x00); /* clear interrupt registers... */ + l64781_readreg (state, 0x01); /* dto. */ + + *status = 0; + + if (gain > 5) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x02) /* VCXO locked, this criteria should be ok */ + *status |= FE_HAS_CARRIER; + + if (sync & 0x20) + *status |= FE_HAS_VITERBI; + + if (sync & 0x40) + *status |= FE_HAS_SYNC; + + if (sync == 0x7f) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int l64781_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + + /* XXX FIXME: set up counting period (reg 0x26...0x28) + */ + *ber = l64781_readreg (state, 0x39) + | (l64781_readreg (state, 0x3a) << 8); + + return 0; +} + +static int l64781_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + + u8 gain = l64781_readreg (state, 0x0e); + *signal_strength = (gain << 8) | gain; + + return 0; +} + +static int l64781_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + + u8 avg_quality = 0xff - l64781_readreg (state, 0x33); + *snr = (avg_quality << 8) | avg_quality; /* not exact, but...*/ + + return 0; +} + +static int l64781_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + + *ucblocks = l64781_readreg (state, 0x37) + | (l64781_readreg (state, 0x38) << 8); + + return 0; +} + +static int l64781_sleep(struct dvb_frontend* fe) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + + /* Power down */ + return l64781_writereg (state, 0x3e, 0x5a); +} + +static int l64781_init(struct dvb_frontend* fe) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + + reset_and_configure (state); + + /* Power up */ + l64781_writereg (state, 0x3e, 0xa5); + + /* Reset hard */ + l64781_writereg (state, 0x2a, 0x04); + l64781_writereg (state, 0x2a, 0x00); + + /* Set tuner specific things */ + /* AFC_POL, set also in reset_afc */ + l64781_writereg (state, 0x07, 0x8e); + + /* Use internal ADC */ + l64781_writereg (state, 0x0b, 0x81); + + /* AGC loop gain, and polarity is positive */ + l64781_writereg (state, 0x0c, 0x84); + + /* Internal ADC outputs two's complement */ + l64781_writereg (state, 0x0d, 0x8c); + + /* With ppm=8000, it seems the DTR_SENSITIVITY will result in + value of 2 with all possible bandwidths and guard + intervals, which is the initial value anyway. */ + /*l64781_writereg (state, 0x19, 0x92);*/ + + /* Everything is two's complement, soft bit and CSI_OUT too */ + l64781_writereg (state, 0x1e, 0x09); + + if (state->config->pll_init) state->config->pll_init(fe); + + /* delay a bit after first init attempt */ + if (state->first) { + state->first = 0; + msleep(200); + } + + return 0; +} + +static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 200; + fesettings->step_size = 166667; + fesettings->max_drift = 166667*2; + return 0; +} + +static void l64781_release(struct dvb_frontend* fe) +{ + struct l64781_state* state = (struct l64781_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops l64781_ops; + +struct dvb_frontend* l64781_attach(const struct l64781_config* config, + struct i2c_adapter* i2c) +{ + struct l64781_state* state = NULL; + int reg0x3e = -1; + u8 b0 [] = { 0x1a }; + u8 b1 [] = { 0x00 }; + struct i2c_msg msg [] = { { .addr = config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + /* allocate memory for the internal state */ + state = (struct l64781_state*) kmalloc(sizeof(struct l64781_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops)); + state->first = 1; + + /** + * the L64781 won't show up before we send the reset_and_configure() + * broadcast. If nothing responds there is no L64781 on the bus... + */ + if (reset_and_configure(state) < 0) { + dprintk("No response to reset and configure broadcast...\n"); + goto error; + } + + /* The chip always responds to reads */ + if (i2c_transfer(state->i2c, msg, 2) != 2) { + dprintk("No response to read on I2C bus\n"); + goto error; + } + + /* Save current register contents for bailout */ + reg0x3e = l64781_readreg(state, 0x3e); + + /* Reading the POWER_DOWN register always returns 0 */ + if (reg0x3e != 0) { + dprintk("Device doesn't look like L64781\n"); + goto error; + } + + /* Turn the chip off */ + l64781_writereg (state, 0x3e, 0x5a); + + /* Responds to all reads with 0 */ + if (l64781_readreg(state, 0x1a) != 0) { + dprintk("Read 1 returned unexpcted value\n"); + goto error; + } + + /* Turn the chip on */ + l64781_writereg (state, 0x3e, 0xa5); + + /* Responds with register default value */ + if (l64781_readreg(state, 0x1a) != 0xa1) { + dprintk("Read 2 returned unexpcted value\n"); + goto error; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops l64781_ops = { + + .info = { + .name = "LSI L64781 DVB-T", + .type = FE_OFDM, + /* .frequency_min = ???,*/ + /* .frequency_max = ???,*/ + .frequency_stepsize = 166666, + /* .frequency_tolerance = ???,*/ + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_MUTE_TS + }, + + .release = l64781_release, + + .init = l64781_init, + .sleep = l64781_sleep, + + .set_frontend = apply_frontend_param, + .get_frontend = get_frontend, + .get_tune_settings = l64781_get_tune_settings, + + .read_status = l64781_read_status, + .read_ber = l64781_read_ber, + .read_signal_strength = l64781_read_signal_strength, + .read_snr = l64781_read_snr, + .read_ucblocks = l64781_read_ucblocks, +}; + +MODULE_DESCRIPTION("LSI L64781 DVB-T Demodulator driver"); +MODULE_AUTHOR("Holger Waechtler, Marko Kohtala"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(l64781_attach); diff -Nru a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/l64781.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,43 @@ +/* + driver for LSI L64781 COFDM demodulator + + Copyright (C) 2001 Holger Waechtler + for Convergence Integrated Media GmbH + Marko Kohtala + + 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 L64781_H +#define L64781_H + +#include + +struct l64781_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + + +extern struct dvb_frontend* l64781_attach(const struct l64781_config* config, + struct i2c_adapter* i2c); + +#endif // L64781_H diff -Nru a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c --- a/drivers/media/dvb/frontends/mt312.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/mt312.c 2004-12-12 17:40:52 -08:00 @@ -1,5 +1,5 @@ /* - Driver for Zarlink MT312 Satellite Channel Decoder + Driver for Zarlink VP310/MT312 Satellite Channel Decoder Copyright (C) 2003 Andreas Oberritter @@ -31,71 +31,52 @@ #include #include "dvb_frontend.h" +#include "mt312_priv.h" #include "mt312.h" -#define FRONTEND_NAME "dvbfe_mt312" -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) +struct mt312_state { -static int debug; + struct i2c_adapter* i2c; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct mt312_config* config; + struct dvb_frontend frontend; -#define I2C_ADDR_MT312 0x0e -#define I2C_ADDR_SL1935 0x61 -#define I2C_ADDR_TSA5059 0x61 + u8 id; + u8 frequency; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + 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 struct dvb_frontend_info mt312_info = { - .name = "Zarlink MT312", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, - /*.frequency_tolerance = 29500, FIXME: binary compatibility waste? */ - .symbol_rate_min = MT312_SYS_CLK / 128, - .symbol_rate_max = MT312_SYS_CLK / 2, - /*.symbol_rate_tolerance = 500, FIXME: binary compatibility waste? 2% */ - .notifier_delay = 0, - .caps = - FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS | - FE_CAN_RECOVER -}; - -struct mt312_state { - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; - int id; -}; - -static int mt312_read(struct i2c_adapter *i2c, - const enum mt312_reg_addr reg, void *buf, - const size_t count) +static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, + void *buf, const size_t count) { int ret; struct i2c_msg msg[2]; u8 regbuf[1] = { reg }; - msg[0].addr = I2C_ADDR_MT312; + msg[0].addr = state->config->demod_address; msg[0].flags = 0; msg[0].buf = regbuf; msg[0].len = 1; - msg[1].addr = I2C_ADDR_MT312; + msg[1].addr = state->config->demod_address; msg[1].flags = I2C_M_RD; msg[1].buf = buf; msg[1].len = count; - ret = i2c_transfer(i2c, msg, 2); + ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) { printk(KERN_ERR "%s: ret == %d\n", __FUNCTION__, ret); @@ -113,9 +94,8 @@ return 0; } -static int mt312_write(struct i2c_adapter *i2c, - const enum mt312_reg_addr reg, const void *src, - const size_t count) +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]; @@ -132,12 +112,12 @@ buf[0] = reg; memcpy(&buf[1], src, count); - msg.addr = I2C_ADDR_MT312; + msg.addr = state->config->demod_address; msg.flags = 0; msg.buf = buf; msg.len = count + 1; - ret = i2c_transfer(i2c, &msg, 1); + ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) { dprintk("%s: ret == %d\n", __FUNCTION__, ret); @@ -147,123 +127,136 @@ return 0; } -static inline int mt312_readreg(struct i2c_adapter *i2c, +static inline int mt312_readreg(struct mt312_state* state, const enum mt312_reg_addr reg, u8 * val) { - return mt312_read(i2c, reg, val, 1); + return mt312_read(state, reg, val, 1); } -static inline int mt312_writereg(struct i2c_adapter *i2c, +static inline int mt312_writereg(struct mt312_state* state, const enum mt312_reg_addr reg, const u8 val) { - return mt312_write(i2c, reg, &val, 1); + return mt312_write(state, reg, &val, 1); } -static int mt312_pll_write(struct i2c_adapter *i2c, const u8 addr, - u8 * buf, const u8 len) +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) +{ + return mt312_writereg(state, RESET, full ? 0x80 : 0x40); +} + +static int mt312_get_inversion(struct mt312_state* state, + fe_spectral_inversion_t *i) { int ret; - struct i2c_msg msg; + u8 vit_mode; - msg.addr = addr; - msg.flags = 0; - msg.buf = buf; - msg.len = len; + if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0) + return ret; + + if (vit_mode & 0x80) /* auto inversion was used */ + *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF; + + return 0; +} + +static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) +{ + int ret; + u8 sym_rate_h; + u8 dec_ratio; + u16 sym_rat_op; + u16 monitor; + u8 buf[2]; - if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x40)) < 0) + if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0) return ret; - if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) - printk(KERN_ERR "%s: i/o error (ret == %d)\n", __FUNCTION__, ret); + if (sym_rate_h & 0x80) { /* symbol rate search was used */ + if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0) + return ret; - if ((ret = mt312_writereg(i2c, GPP_CTRL, 0x00)) < 0) + if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) return ret; - return 0; + monitor = (buf[0] << 8) | buf[1]; + + dprintk(KERN_DEBUG "sr(auto) = %u\n", + mt312_div(monitor * 15625, 4)); + } else { + if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0) + return ret; + + if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) + return ret; + + dec_ratio = ((buf[0] >> 5) & 0x07) * 32; + + if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0) + return ret; + + sym_rat_op = (buf[0] << 8) | buf[1]; + + dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n", + sym_rat_op, dec_ratio); + dprintk(KERN_DEBUG "*sr(manual) = %lu\n", + (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * + 2) - dec_ratio); } -static inline u32 mt312_div(u32 a, u32 b) -{ - return (a + (b / 2)) / b; + return 0; } -static int sl1935_set_tv_freq(struct i2c_adapter *i2c, u32 freq, u32 sr) +static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) { - /* 155 uA, Baseband Path B */ - u8 buf[4] = { 0x00, 0x00, 0x80, 0x00 }; + 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, + FEC_AUTO, FEC_AUTO }; - u8 exp; - u32 ref; - u32 div; - - if (sr < 10000000) { /* 1-10 MSym/s: ratio 2 ^ 3 */ - exp = 3; - buf[2] |= 0x40; /* 690 uA */ - } else if (sr < 15000000) { /* 10-15 MSym/s: ratio 2 ^ 4 */ - exp = 4; - buf[2] |= 0x20; /* 330 uA */ - } else { /* 15-45 MSym/s: ratio 2 ^ 7 */ - exp = 7; - buf[3] |= 0x08; /* Baseband Path A */ + int ret; + u8 fec_status; + + if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0) + return ret; + + *cr = fec_tab[(fec_status >> 4) & 0x07]; + + return 0; } - div = mt312_div(MT312_PLL_CLK, 1 << exp); - ref = mt312_div(freq * 1000, div); - mt312_info.frequency_stepsize = mt312_div(div, 1000); - buf[0] = (ref >> 8) & 0x7f; - buf[1] = (ref >> 0) & 0xff; - buf[2] |= (exp - 1); - if (freq < 1550000) - buf[3] |= 0x10; - dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0], - buf[1], buf[2], buf[3]); - return mt312_pll_write(i2c, I2C_ADDR_SL1935, buf, sizeof(buf)); -} -static int tsa5059_set_tv_freq(struct i2c_adapter *i2c, u32 freq, u32 sr) -{ - u8 buf[4]; - u32 ref = mt312_div(freq, 125); - buf[0] = (ref >> 8) & 0x7f; - buf[1] = (ref >> 0) & 0xff; - buf[2] = 0x84 | ((ref >> 10) & 0x60); - buf[3] = 0x80; - if (freq < 1550000) - buf[3] |= 0x02; - dprintk(KERN_INFO "synth dword = %02x%02x%02x%02x\n", buf[0], - buf[1], buf[2], buf[3]); - return mt312_pll_write(i2c, I2C_ADDR_TSA5059, buf, sizeof(buf)); -} -static int mt312_reset(struct i2c_adapter *i2c, const u8 full) -{ - return mt312_writereg(i2c, RESET, full ? 0x80 : 0x40); -} -static int mt312_initfe(struct mt312_state *state, u8 pll) + + +static int mt312_initfe(struct dvb_frontend* fe) { - struct i2c_adapter *i2c = state->i2c; + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 buf[2]; /* wake up */ - if ((ret = mt312_writereg(i2c, CONFIG, (pll == 60 ? 0x88 : 0x8c))) < 0) + if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0) return ret; /* wait at least 150 usec */ udelay(150); /* full reset */ - if ((ret = mt312_reset(i2c, 1)) < 0) + if ((ret = mt312_reset(state, 1)) < 0) return ret; // Per datasheet, write correct values. 09/28/03 ACCJr. @@ -271,56 +264,63 @@ { u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00}; - if ((ret = mt312_write(i2c, VIT_SETUP, buf_def, sizeof(buf_def))) < 0) + if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0) return ret; } /* SYS_CLK */ - buf[0] = mt312_div((pll == 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); - if ((ret = mt312_write(i2c, SYS_CLK, buf, sizeof(buf))) < 0) + if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0) return ret; - if ((ret = mt312_writereg(i2c, SNR_THS_HIGH, 0x32)) < 0) + if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0) return ret; - if ((ret = mt312_writereg(i2c, OP_CTRL, 0x53)) < 0) + if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0) return ret; /* TS_SW_LIM */ buf[0] = 0x8c; buf[1] = 0x98; - if ((ret = mt312_write(i2c, TS_SW_LIM_L, buf, sizeof(buf))) < 0) + if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0) return ret; - if ((ret = mt312_writereg(i2c, CS_SW_LIM, 0x69)) < 0) + if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0) return ret; + if (state->config->pll_init) { + mt312_writereg(state, GPP_CTRL, 0x40); + state->config->pll_init(fe); + mt312_writereg(state, GPP_CTRL, 0x00); + } + return 0; } -static int mt312_send_master_cmd(struct i2c_adapter *i2c, - const struct dvb_diseqc_master_cmd *c) +static int mt312_send_master_cmd(struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *c) { + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 diseqc_mode; if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) return -EINVAL; - if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0) + if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) return ret; if ((ret = - mt312_write(i2c, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0) + mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0) return ret; if ((ret = - mt312_writereg(i2c, DISEQC_MODE, + mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) | 0x04)) < 0) return ret; @@ -328,21 +328,15 @@ /* set DISEQC_MODE[2:0] to zero if a return message is expected */ if (c->msg[0] & 0x02) if ((ret = - mt312_writereg(i2c, DISEQC_MODE, (diseqc_mode & 0x40))) < 0) + mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0) return ret; return 0; } -static int mt312_recv_slave_reply(struct i2c_adapter *i2c, - struct dvb_diseqc_slave_reply *r) -{ - /* TODO */ - return -EOPNOTSUPP; -} - -static int mt312_send_burst(struct i2c_adapter *i2c, 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 = (struct mt312_state*) fe->demodulator_priv; const u8 mini_tab[2] = { 0x02, 0x03 }; int ret; @@ -351,19 +345,20 @@ if (c > SEC_MINI_B) return -EINVAL; - if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0) + if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) return ret; if ((ret = - mt312_writereg(i2c, DISEQC_MODE, + mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) | mini_tab[c])) < 0) return ret; return 0; } -static int mt312_set_tone(struct i2c_adapter *i2c, 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 = (struct mt312_state*) fe->demodulator_priv; const u8 tone_tab[2] = { 0x01, 0x00 }; int ret; @@ -372,36 +367,37 @@ if (t > SEC_TONE_OFF) return -EINVAL; - if ((ret = mt312_readreg(i2c, DISEQC_MODE, &diseqc_mode)) < 0) + if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) return ret; if ((ret = - mt312_writereg(i2c, DISEQC_MODE, + mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) | tone_tab[t])) < 0) return ret; return 0; } -static int mt312_set_voltage(struct i2c_adapter *i2c, 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 = (struct mt312_state*) fe->demodulator_priv; const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; if (v > SEC_VOLTAGE_OFF) return -EINVAL; - return mt312_writereg(i2c, DISEQC_MODE, volt_tab[v]); + return mt312_writereg(state, DISEQC_MODE, volt_tab[v]); } -static int mt312_read_status(struct mt312_state *state, fe_status_t *s) +static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) { - struct i2c_adapter *i2c = state->i2c; + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 status[3], vit_mode; *s = 0; - if ((ret = mt312_read(i2c, QPSK_STAT_H, status, sizeof(status))) < 0) + if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0) return ret; dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); @@ -419,24 +415,25 @@ // VP310 doesn't have AUTO, so we "implement it here" ACCJr if ((state->id == ID_VP310) && !(status[0] & 0x01)) { - if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0) + if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0) return ret; vit_mode ^= 0x40; - if ((ret = mt312_writereg(i2c, VIT_MODE, vit_mode)) < 0) + if ((ret = mt312_writereg(state, VIT_MODE, vit_mode)) < 0) return ret; - if ((ret = mt312_writereg(i2c, GO, 0x01)) < 0) + if ((ret = mt312_writereg(state, GO, 0x01)) < 0) return ret; } return 0; } -static int mt312_read_bercnt(struct i2c_adapter *i2c, u32 *ber) +static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) { + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 buf[3]; - if ((ret = mt312_read(i2c, RS_BERCNT_H, buf, 3)) < 0) + if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0) return ret; *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; @@ -444,14 +441,15 @@ return 0; } -static int mt312_read_agc(struct i2c_adapter *i2c, u16 *signal_strength) +static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength) { + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 buf[3]; u16 agc; s16 err_db; - if ((ret = mt312_read(i2c, AGC_H, buf, sizeof(buf))) < 0) + if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0) return ret; agc = (buf[0] << 6) | (buf[1] >> 2); @@ -464,12 +462,13 @@ return 0; } -static int mt312_read_snr(struct i2c_adapter *i2c, u16 *snr) +static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) { + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 buf[2]; - if ((ret = mt312_read(i2c, M_SNR_H, &buf, sizeof(buf))) < 0) + if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0) return ret; *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); @@ -477,12 +476,13 @@ return 0; } -static int mt312_read_ubc(struct i2c_adapter *i2c, u32 *ubc) +static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) { + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 buf[2]; - if ((ret = mt312_read(i2c, RS_UBC_H, &buf, sizeof(buf))) < 0) + if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0) return ret; *ubc = (buf[0] << 8) | buf[1]; @@ -490,10 +490,10 @@ return 0; } -static int mt312_set_frontend(struct mt312_state *state, - const struct dvb_frontend_parameters *p) +static int mt312_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) { - struct i2c_adapter *i2c = state->i2c; + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 buf[5], config_val; u16 sr; @@ -502,20 +502,18 @@ { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10, 0x20, 0x3f, 0x3f }; const u8 inv_tab[3] = { 0x00, 0x40, 0x80 }; - int (*set_tv_freq)(struct i2c_adapter *i2c, u32 freq, u32 sr); - dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency); - if ((p->frequency < mt312_info.frequency_min) - || (p->frequency > mt312_info.frequency_max)) + if ((p->frequency < fe->ops->info.frequency_min) + || (p->frequency > fe->ops->info.frequency_max)) return -EINVAL; if ((p->inversion < INVERSION_OFF) - || (p->inversion > INVERSION_AUTO)) + || (p->inversion > INVERSION_ON)) return -EINVAL; - if ((p->u.qpsk.symbol_rate < mt312_info.symbol_rate_min) - || (p->u.qpsk.symbol_rate > mt312_info.symbol_rate_max)) + if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min) + || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max)) return -EINVAL; if ((p->u.qpsk.fec_inner < FEC_NONE) @@ -530,31 +528,36 @@ case ID_VP310: // 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 - if ((ret = mt312_readreg(i2c, CONFIG, &config_val) < 0)) + if ((ret = mt312_readreg(state, CONFIG, &config_val) < 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 ((ret = mt312_initfe(state, (u8) 90)) < 0) + if ((config_val & 0x0c) == 0x08) { //We are running 60MHz + state->frequency = 90; + if ((ret = mt312_initfe(fe)) < 0) return ret; } + } else { - if ((config_val & 0x0c) == 0x0C) //We are running 90MHz - if ((ret = mt312_initfe(state, (u8) 60)) < 0) + if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz + state->frequency = 60; + if ((ret = mt312_initfe(fe)) < 0) return ret; } - set_tv_freq = tsa5059_set_tv_freq; + } break; + case ID_MT312: - set_tv_freq = sl1935_set_tv_freq; break; + default: return -EINVAL; } - if ((ret = set_tv_freq(i2c, p->frequency, p->u.qpsk.symbol_rate)) < 0) - return ret; + mt312_writereg(state, GPP_CTRL, 0x40); + state->config->pll_set(fe, p); + mt312_writereg(state, GPP_CTRL, 0x00); /* sr = (u16)(sr * 256.0 / 1000000.0) */ sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); @@ -575,333 +578,154 @@ /* GO */ buf[4] = 0x01; - if ((ret = mt312_write(i2c, SYM_RATE_H, buf, sizeof(buf))) < 0) - return ret; - - mt312_reset(i2c, 0); - - return 0; -} - -static int mt312_get_inversion(struct i2c_adapter *i2c, - fe_spectral_inversion_t * i) -{ - int ret; - u8 vit_mode; - - if ((ret = mt312_readreg(i2c, VIT_MODE, &vit_mode)) < 0) - return ret; - - if (vit_mode & 0x80) /* auto inversion was used */ - *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF; - - return 0; -} - -static int mt312_get_symbol_rate(struct i2c_adapter *i2c, u32 *sr) -{ - int ret; - u8 sym_rate_h; - u8 dec_ratio; - u16 sym_rat_op; - u16 monitor; - u8 buf[2]; - - if ((ret = mt312_readreg(i2c, SYM_RATE_H, &sym_rate_h)) < 0) + if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0) return ret; - if (sym_rate_h & 0x80) { /* symbol rate search was used */ - if ((ret = mt312_writereg(i2c, MON_CTRL, 0x03)) < 0) - return ret; - - if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0) - return ret; - - monitor = (buf[0] << 8) | buf[1]; - - dprintk(KERN_DEBUG "sr(auto) = %u\n", - mt312_div(monitor * 15625, 4)); - } else { - if ((ret = mt312_writereg(i2c, MON_CTRL, 0x05)) < 0) - return ret; - - if ((ret = mt312_read(i2c, MONITOR_H, buf, sizeof(buf))) < 0) - return ret; - - dec_ratio = ((buf[0] >> 5) & 0x07) * 32; - - if ((ret = mt312_read(i2c, SYM_RAT_OP_H, buf, sizeof(buf))) < 0) - return ret; - - sym_rat_op = (buf[0] << 8) | buf[1]; - - dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n", - sym_rat_op, dec_ratio); - dprintk(KERN_DEBUG "*sr(manual) = %lu\n", - (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * - 2) - dec_ratio); - } - - return 0; -} - -static int mt312_get_code_rate(struct i2c_adapter *i2c, 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, - FEC_AUTO, FEC_AUTO }; - - int ret; - u8 fec_status; - - if ((ret = mt312_readreg(i2c, FEC_STATUS, &fec_status)) < 0) - return ret; - - *cr = fec_tab[(fec_status >> 4) & 0x07]; + mt312_reset(state, 0); return 0; } -static int mt312_get_frontend(struct i2c_adapter *i2c, +static int mt312_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; - if ((ret = mt312_get_inversion(i2c, &p->inversion)) < 0) + if ((ret = mt312_get_inversion(state, &p->inversion)) < 0) return ret; - if ((ret = mt312_get_symbol_rate(i2c, &p->u.qpsk.symbol_rate)) < 0) + if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0) return ret; - if ((ret = mt312_get_code_rate(i2c, &p->u.qpsk.fec_inner)) < 0) + if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0) return ret; return 0; } -static int mt312_sleep(struct i2c_adapter *i2c) +static int mt312_sleep(struct dvb_frontend* fe) { + struct mt312_state *state = (struct mt312_state*) fe->demodulator_priv; int ret; u8 config; /* reset all registers to defaults */ - if ((ret = mt312_reset(i2c, 1)) < 0) + if ((ret = mt312_reset(state, 1)) < 0) return ret; - if ((ret = mt312_readreg(i2c, CONFIG, &config)) < 0) + if ((ret = mt312_readreg(state, CONFIG, &config)) < 0) return ret; /* enter standby */ - if ((ret = mt312_writereg(i2c, CONFIG, config & 0x7f)) < 0) + if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0) return ret; return 0; } -static int mt312_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct mt312_state *state = fe->data; - struct i2c_adapter *i2c = state->i2c; - - switch (cmd) { - case FE_GET_INFO: - memcpy(arg, &mt312_info, sizeof(struct dvb_frontend_info)); - break; - - case FE_DISEQC_RESET_OVERLOAD: - return -EOPNOTSUPP; - - case FE_DISEQC_SEND_MASTER_CMD: - return mt312_send_master_cmd(i2c, arg); - - case FE_DISEQC_RECV_SLAVE_REPLY: - if (state->id == ID_MT312) - return mt312_recv_slave_reply(i2c, arg); - else - return -EOPNOTSUPP; - - case FE_DISEQC_SEND_BURST: - return mt312_send_burst(i2c, (fe_sec_mini_cmd_t) arg); - - case FE_SET_TONE: - return mt312_set_tone(i2c, (fe_sec_tone_mode_t) arg); - - case FE_SET_VOLTAGE: - return mt312_set_voltage(i2c, (fe_sec_voltage_t) arg); - - case FE_ENABLE_HIGH_LNB_VOLTAGE: - return -EOPNOTSUPP; - - case FE_READ_STATUS: - return mt312_read_status(state, arg); - - case FE_READ_BER: - return mt312_read_bercnt(i2c, arg); - - case FE_READ_SIGNAL_STRENGTH: - return mt312_read_agc(i2c, arg); - - case FE_READ_SNR: - return mt312_read_snr(i2c, arg); - - case FE_READ_UNCORRECTED_BLOCKS: - return mt312_read_ubc(i2c, arg); - - case FE_SET_FRONTEND: - return mt312_set_frontend(state, arg); - - case FE_GET_FRONTEND: - return mt312_get_frontend(i2c, arg); - - case FE_GET_EVENT: - return -EOPNOTSUPP; - - case FE_SLEEP: - return mt312_sleep(i2c); - - case FE_INIT: - /* For the VP310 we should run at 60MHz when ever possible. - * It should be better to run the mt312 ar lower speed when - * ever possible, but tunning will be slower. ACCJr 09/29/03 - */ - if (state->id == ID_MT312) - return mt312_initfe(state, (u8) 90); - else - return mt312_initfe(state, (u8) 60); - - case FE_GET_TUNE_SETTINGS: +static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; fesettings->min_delay_ms = 50; fesettings->step_size = 0; fesettings->max_drift = 0; return 0; } - default: - return -ENOIOCTLCMD; - } - - return 0; -} - -static struct i2c_client client_template; - -static int mt312_attach_adapter(struct i2c_adapter *adapter) +static void mt312_release(struct dvb_frontend* fe) { - struct mt312_state *state; - struct i2c_client *client; - int ret; - u8 id; - - dprintk("Trying to attach to adapter 0x%x:%s.\n", - adapter->id, adapter->name); - - if (mt312_readreg(adapter, ID, &id) < 0) - return -ENODEV; - - if ((id != ID_VP310) && (id != ID_MT312)) - return -ENODEV; - - if ( !(state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL)) ) - return -ENOMEM; - - memset(state, 0, sizeof(struct mt312_state)); - state->i2c = adapter; - state->id = id; - - if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) { - kfree(state); - return -ENOMEM; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = I2C_ADDR_MT312; - i2c_set_clientdata(client, state); - - if ((ret = i2c_attach_client(client))) { - kfree(client); - kfree(state); - return ret; - } - - BUG_ON(!state->dvb); - - if ((ret = dvb_register_frontend(mt312_ioctl, state->dvb, state, - &mt312_info, THIS_MODULE))) { - i2c_detach_client(client); - kfree(client); - kfree(state); - return ret; - } - - return 0; -} - -static int mt312_detach_client(struct i2c_client *client) -{ - struct mt312_state *state = i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - dvb_unregister_frontend (mt312_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); + struct mt312_state* state = (struct mt312_state*) fe->demodulator_priv; kfree(state); - return 0; } -static int mt312_command (struct i2c_client *client, unsigned int cmd, void *arg) +static struct dvb_frontend_ops mt312_ops; + +struct dvb_frontend* mt312_attach(const struct mt312_config* config, + struct i2c_adapter* i2c) { - struct mt312_state *state = i2c_get_clientdata(client); + struct mt312_state* state = NULL; - dprintk ("%s\n", __FUNCTION__); + /* allocate memory for the internal state */ + state = (struct mt312_state*) kmalloc(sizeof(struct mt312_state), GFP_KERNEL); + if (state == NULL) goto error; - switch (cmd) { - case FE_REGISTER: - state->dvb = arg; + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &mt312_ops, sizeof(struct dvb_frontend_ops)); + + /* check if the demod is there */ + if (mt312_readreg(state, ID, &state->id) < 0) goto error; + switch(state->id) { + case ID_VP310: + state->frequency = 90; + printk("mt312: Detected Zarlink VP310\n"); break; - case FE_UNREGISTER: - state->dvb = NULL; + + case ID_MT312: + state->frequency = 60; + printk("mt312: Detected Zarlink MT312\n"); break; + default: - return -EOPNOTSUPP; - } - return 0; + goto error; } -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_MT312, - .flags = I2C_DF_NOTIFY, - .attach_adapter = mt312_attach_adapter, - .detach_client = mt312_detach_client, - .command = mt312_command, + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops mt312_ops = { + + .info = { + .name = "Zarlink VP310/MT312 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, + /*.frequency_tolerance = 29500, FIXME: binary compatibility waste? */ + .symbol_rate_min = MT312_SYS_CLK / 128, + .symbol_rate_max = MT312_SYS_CLK / 2, + /*.symbol_rate_tolerance = 500, FIXME: binary compatibility waste? 2% */ + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_MUTE_TS | + FE_CAN_RECOVER + }, + + .release = mt312_release, + + .init = mt312_initfe, + .sleep = mt312_sleep, + + .set_frontend = mt312_set_frontend, + .get_frontend = mt312_get_frontend, + .get_tune_settings = mt312_get_tune_settings, + + .read_status = mt312_read_status, + .read_ber = mt312_read_ber, + .read_signal_strength = mt312_read_signal_strength, + .read_snr = mt312_read_snr, + .read_ucblocks = mt312_read_ucblocks, + + .diseqc_send_master_cmd = mt312_send_master_cmd, + .diseqc_send_burst = mt312_send_burst, + .set_tone = mt312_set_tone, + .set_voltage = mt312_set_voltage, }; -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init mt312_module_init(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit mt312_module_exit(void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "mt312: driver deregistration failed.\n"); -} - -module_init(mt312_module_init); -module_exit(mt312_module_exit); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("MT312 Satellite Channel Decoder Driver"); +MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver"); MODULE_AUTHOR("Andreas Oberritter "); MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(mt312_attach); diff -Nru a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h --- a/drivers/media/dvb/frontends/mt312.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/mt312.h 2004-12-12 17:40:52 -08:00 @@ -1,5 +1,5 @@ /* - Driver for Zarlink MT312 QPSK Frontend + Driver for Zarlink MT312 Satellite Channel Decoder Copyright (C) 2003 Andreas Oberritter @@ -18,145 +18,27 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + References: + http://products.zarlink.com/product_profiles/MT312.htm + http://products.zarlink.com/product_profiles/SL1935.htm */ -#ifndef _DVB_FRONTENDS_MT312 -#define _DVB_FRONTENDS_MT312 +#ifndef MT312_H +#define MT312_H -enum mt312_reg_addr { - QPSK_INT_H = 0, - QPSK_INT_M = 1, - QPSK_INT_L = 2, - FEC_INT = 3, - QPSK_STAT_H = 4, - QPSK_STAT_L = 5, - FEC_STATUS = 6, - LNB_FREQ_H = 7, - LNB_FREQ_L = 8, - M_SNR_H = 9, - M_SNR_L = 10, - VIT_ERRCNT_H = 11, - VIT_ERRCNT_M = 12, - VIT_ERRCNT_L = 13, - RS_BERCNT_H = 14, - RS_BERCNT_M = 15, - RS_BERCNT_L = 16, - RS_UBC_H = 17, - RS_UBC_L = 18, - SIG_LEVEL = 19, - GPP_CTRL = 20, - RESET = 21, - DISEQC_MODE = 22, - SYM_RATE_H = 23, - SYM_RATE_L = 24, - VIT_MODE = 25, - QPSK_CTRL = 26, - GO = 27, - IE_QPSK_H = 28, - IE_QPSK_M = 29, - IE_QPSK_L = 30, - IE_FEC = 31, - QPSK_STAT_EN = 32, - FEC_STAT_EN = 33, - SYS_CLK = 34, - DISEQC_RATIO = 35, - DISEQC_INSTR = 36, - FR_LIM = 37, - FR_OFF = 38, - AGC_CTRL = 39, - AGC_INIT = 40, - AGC_REF = 41, - AGC_MAX = 42, - AGC_MIN = 43, - AGC_LK_TH = 44, - TS_AGC_LK_TH = 45, - AGC_PWR_SET = 46, - QPSK_MISC = 47, - SNR_THS_LOW = 48, - SNR_THS_HIGH = 49, - TS_SW_RATE = 50, - TS_SW_LIM_L = 51, - TS_SW_LIM_H = 52, - CS_SW_RATE_1 = 53, - CS_SW_RATE_2 = 54, - CS_SW_RATE_3 = 55, - CS_SW_RATE_4 = 56, - CS_SW_LIM = 57, - TS_LPK = 58, - TS_LPK_M = 59, - TS_LPK_L = 60, - CS_KPROP_H = 61, - CS_KPROP_L = 62, - CS_KINT_H = 63, - CS_KINT_L = 64, - QPSK_SCALE = 65, - TLD_OUTCLK_TH = 66, - TLD_INCLK_TH = 67, - FLD_TH = 68, - PLD_OUTLK3 = 69, - PLD_OUTLK2 = 70, - PLD_OUTLK1 = 71, - PLD_OUTLK0 = 72, - PLD_INLK3 = 73, - PLD_INLK2 = 74, - PLD_INLK1 = 75, - PLD_INLK0 = 76, - PLD_ACC_TIME = 77, - SWEEP_PAR = 78, - STARTUP_TIME = 79, - LOSSLOCK_TH = 80, - FEC_LOCK_TM = 81, - LOSSLOCK_TM = 82, - VIT_ERRPER_H = 83, - VIT_ERRPER_M = 84, - VIT_ERRPER_L = 85, - VIT_SETUP = 86, - VIT_REF0 = 87, - VIT_REF1 = 88, - VIT_REF2 = 89, - VIT_REF3 = 90, - VIT_REF4 = 91, - VIT_REF5 = 92, - VIT_REF6 = 93, - VIT_MAXERR = 94, - BA_SETUPT = 95, - OP_CTRL = 96, - FEC_SETUP = 97, - PROG_SYNC = 98, - AFC_SEAR_TH = 99, - CSACC_DIF_TH = 100, - QPSK_LK_CT = 101, - QPSK_ST_CT = 102, - MON_CTRL = 103, - QPSK_RESET = 104, - QPSK_TST_CT = 105, - QPSK_TST_ST = 106, - TEST_R = 107, - AGC_H = 108, - AGC_M = 109, - AGC_L = 110, - FREQ_ERR1_H = 111, - FREQ_ERR1_M = 112, - FREQ_ERR1_L = 113, - FREQ_ERR2_H = 114, - FREQ_ERR2_L = 115, - SYM_RAT_OP_H = 116, - SYM_RAT_OP_L = 117, - DESEQC2_INT = 118, - DISEQC2_STAT = 119, - DISEQC2_FIFO = 120, - DISEQC2_CTRL1 = 121, - DISEQC2_CTRL2 = 122, - MONITOR_H = 123, - MONITOR_L = 124, - TEST_MODE = 125, - ID = 126, - CONFIG = 127 -}; +#include -enum mt312_model_id { - ID_VP310 = 1, - ID_MT312 = 3 +struct mt312_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; -#endif /* DVB_FRONTENDS_MT312 */ +extern struct dvb_frontend* mt312_attach(const struct mt312_config* config, + struct i2c_adapter* i2c); + +#endif // MT312_H diff -Nru a/drivers/media/dvb/frontends/mt312_priv.h b/drivers/media/dvb/frontends/mt312_priv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/mt312_priv.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,162 @@ +/* + Driver for Zarlink MT312 QPSK Frontend + + Copyright (C) 2003 Andreas Oberritter + + 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 _DVB_FRONTENDS_MT312_PRIV +#define _DVB_FRONTENDS_MT312_PRIV + +enum mt312_reg_addr { + QPSK_INT_H = 0, + QPSK_INT_M = 1, + QPSK_INT_L = 2, + FEC_INT = 3, + QPSK_STAT_H = 4, + QPSK_STAT_L = 5, + FEC_STATUS = 6, + LNB_FREQ_H = 7, + LNB_FREQ_L = 8, + M_SNR_H = 9, + M_SNR_L = 10, + VIT_ERRCNT_H = 11, + VIT_ERRCNT_M = 12, + VIT_ERRCNT_L = 13, + RS_BERCNT_H = 14, + RS_BERCNT_M = 15, + RS_BERCNT_L = 16, + RS_UBC_H = 17, + RS_UBC_L = 18, + SIG_LEVEL = 19, + GPP_CTRL = 20, + RESET = 21, + DISEQC_MODE = 22, + SYM_RATE_H = 23, + SYM_RATE_L = 24, + VIT_MODE = 25, + QPSK_CTRL = 26, + GO = 27, + IE_QPSK_H = 28, + IE_QPSK_M = 29, + IE_QPSK_L = 30, + IE_FEC = 31, + QPSK_STAT_EN = 32, + FEC_STAT_EN = 33, + SYS_CLK = 34, + DISEQC_RATIO = 35, + DISEQC_INSTR = 36, + FR_LIM = 37, + FR_OFF = 38, + AGC_CTRL = 39, + AGC_INIT = 40, + AGC_REF = 41, + AGC_MAX = 42, + AGC_MIN = 43, + AGC_LK_TH = 44, + TS_AGC_LK_TH = 45, + AGC_PWR_SET = 46, + QPSK_MISC = 47, + SNR_THS_LOW = 48, + SNR_THS_HIGH = 49, + TS_SW_RATE = 50, + TS_SW_LIM_L = 51, + TS_SW_LIM_H = 52, + CS_SW_RATE_1 = 53, + CS_SW_RATE_2 = 54, + CS_SW_RATE_3 = 55, + CS_SW_RATE_4 = 56, + CS_SW_LIM = 57, + TS_LPK = 58, + TS_LPK_M = 59, + TS_LPK_L = 60, + CS_KPROP_H = 61, + CS_KPROP_L = 62, + CS_KINT_H = 63, + CS_KINT_L = 64, + QPSK_SCALE = 65, + TLD_OUTCLK_TH = 66, + TLD_INCLK_TH = 67, + FLD_TH = 68, + PLD_OUTLK3 = 69, + PLD_OUTLK2 = 70, + PLD_OUTLK1 = 71, + PLD_OUTLK0 = 72, + PLD_INLK3 = 73, + PLD_INLK2 = 74, + PLD_INLK1 = 75, + PLD_INLK0 = 76, + PLD_ACC_TIME = 77, + SWEEP_PAR = 78, + STARTUP_TIME = 79, + LOSSLOCK_TH = 80, + FEC_LOCK_TM = 81, + LOSSLOCK_TM = 82, + VIT_ERRPER_H = 83, + VIT_ERRPER_M = 84, + VIT_ERRPER_L = 85, + VIT_SETUP = 86, + VIT_REF0 = 87, + VIT_REF1 = 88, + VIT_REF2 = 89, + VIT_REF3 = 90, + VIT_REF4 = 91, + VIT_REF5 = 92, + VIT_REF6 = 93, + VIT_MAXERR = 94, + BA_SETUPT = 95, + OP_CTRL = 96, + FEC_SETUP = 97, + PROG_SYNC = 98, + AFC_SEAR_TH = 99, + CSACC_DIF_TH = 100, + QPSK_LK_CT = 101, + QPSK_ST_CT = 102, + MON_CTRL = 103, + QPSK_RESET = 104, + QPSK_TST_CT = 105, + QPSK_TST_ST = 106, + TEST_R = 107, + AGC_H = 108, + AGC_M = 109, + AGC_L = 110, + FREQ_ERR1_H = 111, + FREQ_ERR1_M = 112, + FREQ_ERR1_L = 113, + FREQ_ERR2_H = 114, + FREQ_ERR2_L = 115, + SYM_RAT_OP_H = 116, + SYM_RAT_OP_L = 117, + DESEQC2_INT = 118, + DISEQC2_STAT = 119, + DISEQC2_FIFO = 120, + DISEQC2_CTRL1 = 121, + DISEQC2_CTRL2 = 122, + MONITOR_H = 123, + MONITOR_L = 124, + TEST_MODE = 125, + ID = 126, + CONFIG = 127 +}; + +enum mt312_model_id { + ID_VP310 = 1, + ID_MT312 = 3 +}; + +#endif /* DVB_FRONTENDS_MT312_PRIV */ diff -Nru a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c --- a/drivers/media/dvb/frontends/mt352.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/mt352.c 2004-12-12 17:40:52 -08:00 @@ -37,438 +37,90 @@ #include #include "dvb_frontend.h" +#include "mt352_priv.h" #include "mt352.h" -#define FRONTEND_NAME "dvbfe_mt352" +struct mt352_state { -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) + struct i2c_adapter* i2c; -static int debug; -#define MAX_CARDS 4 -static int force_card[MAX_CARDS] = { -1, -1, -1, -1 }; -static int force_card_count = 0; + struct dvb_frontend_ops ops; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -module_param_array(force_card, int, &force_card_count, 0444); -MODULE_PARM_DESC(force_card, "Forces the type of each attached mt352 frontend.\n\t" - "If your card is not autodetected, then you must specify its type here.\n\t" - "Valid card types are: 0 == AVDVBT771, 1 == TUA6034, 2 == TDTC9251DH01C,\n\t" - "3 == DVICO FusionHDTV DVB-T1, 4 == DVICO FusionHDTV DVB-T Lite."); + /* configuration settings */ + const struct mt352_config* config; -struct mt352_state { - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; - struct dvb_frontend_info fe_info; - int card_type; + struct dvb_frontend frontend; }; -#define mt352_write(ibuf, ilen) \ +static int debug; +#define dprintk(args...) \ do { \ - struct i2c_msg msg = { .addr = I2C_MT352_ADDR, .flags = 0, \ - .buf = ibuf, .len = ilen }; \ - int err = i2c_transfer(i2c, &msg, 1); \ - if (err != 1) { \ - printk(KERN_WARNING \ - "mt352_write() failed (err = %d)!\n", err); \ - return err; \ - } \ + if (debug) printk(KERN_DEBUG "mt352: " args); \ } while (0) -static struct _tuner_info tuner_info [] = { - { - .fe_name = "AverMedia DVB-T 771", - .fe_frequency_min = 174000000, - .fe_frequency_max = 862000000, - .fe_frequency_stepsize = 166667, - .pll_i2c_addr = 0xc2, - .mt352_init = mt352_init_AVERMEDIA771, - .mt352_charge_pump = mt352_cp_AVERMEDIA771, - .mt352_band_select = mt352_bs_AVERMEDIA771 - }, - { - .fe_name = "Zarlink MT352 + TUA6034 DVB-T", - .fe_frequency_min = 174000000, - .fe_frequency_max = 862000000, - .fe_frequency_stepsize = 166667, - .pll_i2c_addr = 0xc2, - .mt352_init = mt352_init_TUA6034, - .mt352_charge_pump = mt352_cp_TUA6034, - .mt352_band_select = mt352_bs_TUA6034 - }, - { - .fe_name = "Zarlink MT352 + Samsung TDTC9251DH01C DVB-T", - .fe_frequency_min = 474000000, - .fe_frequency_max = 858000000, - .fe_frequency_stepsize = 166667, - .pll_i2c_addr = 0xc2, - .mt352_init = mt352_init_TDTC9251DH01C, - .mt352_charge_pump = mt352_cp_TDTC9251DH01C, - .mt352_band_select = mt352_bs_TDTC9251DH01C - }, - { - .fe_name = "DVICO FusionHDTV DVB-T1", - .fe_frequency_min = 174000000, - .fe_frequency_max = 862000000, - .fe_frequency_stepsize = 166667, - .pll_i2c_addr = 0xc2, - .mt352_init = mt352_init_DVICODVBT1, - .mt352_charge_pump = mt352_cp_DVICODVBT1, - .mt352_band_select = mt352_bs_DVICODVBT1, - }, - { - .fe_name = "DVICO FusionHDTV DVB-T Lite", - .fe_frequency_min = 174000000, - .fe_frequency_max = 862000000, - .fe_frequency_stepsize = 166667, - .pll_i2c_addr = 0xc0, - .mt352_init = mt352_init_DVICODVBTLITE, - .mt352_charge_pump = mt352_cp_DVICODVBTLITE, - .mt352_band_select = mt352_bs_DVICODVBTLITE, - } -}; - -static struct dvb_frontend_info mt352_info_template = { - .name = "DVB-T Zarlink MT352 demodulator driver", - .type = FE_OFDM, -/* - .frequency_min = 0, - .frequency_max = 0, - .frequency_stepsize = 0, - .frequency_tolerance = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = ???, -*/ - .notifier_delay = 0, - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | - FE_CAN_MUTE_TS -}; - -static u8 mt352_reset [] = { RESET, 0x80 }; -static u8 mt352_adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; -static u8 mt352_capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - -static int mt352_init_TUA6034(struct i2c_adapter *i2c) -{ - static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x2d }; - static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x19, 0xa0 }; - - mt352_write(mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(mt352_reset, sizeof(mt352_reset)); - mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int mt352_init_AVERMEDIA771(struct i2c_adapter *i2c) -{ - static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x2d }; - static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x10, 0x23, 0x00, 0xFF, 0xFF, - 0x00, 0xFF, 0x00, 0x40, 0x40 }; - static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; - static u8 mt352_capt_range_cfg[] = { CAPT_RANGE, 0x32 }; - - mt352_write(mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(mt352_reset, sizeof(mt352_reset)); - mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(mt352_agc_cfg,sizeof(mt352_agc_cfg)); - udelay(2000); - mt352_write(mt352_av771_extra,sizeof(mt352_av771_extra)); - mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static int mt352_init_TDTC9251DH01C(struct i2c_adapter *i2c) +int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen) { - static u8 mt352_clock_config [] = { CLOCK_CTL, 0x10, 0x2d }; - static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x28, 0xa1 }; - - mt352_write(mt352_clock_config, sizeof(mt352_clock_config)); - udelay(2000); - mt352_write(mt352_reset, sizeof(mt352_reset)); - mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, + .buf = ibuf, .len = ilen }; + int err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) { + printk(KERN_WARNING + "mt352_write() failed (err = %d)!\n", err); + return err; } -static int mt352_init_DVICODVBT1(struct i2c_adapter *i2c) -{ - static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; - static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; - static u8 mt352_gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - - mt352_write(mt352_clock_config, sizeof(mt352_clock_config)); - udelay(200); - mt352_write(mt352_reset, sizeof(mt352_reset)); - mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); - mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - return 0; } -static int mt352_init_DVICODVBTLITE(struct i2c_adapter *i2c) -{ - static u8 mt352_clock_config [] = { CLOCK_CTL, 0x38, 0x38 }; - static u8 mt352_agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; - static u8 mt352_gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; - - mt352_write(mt352_clock_config, sizeof(mt352_clock_config)); - udelay(200); - mt352_write(mt352_reset, sizeof(mt352_reset)); - mt352_write(mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - - mt352_write(mt352_agc_cfg, sizeof(mt352_agc_cfg)); - mt352_write(mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); - mt352_write(mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - - return 0; -} - -static unsigned char mt352_cp_TUA6034(u32 freq) -{ - unsigned char cp = 0; - - if (freq < 542000000) - cp = 0xbe; - else if (freq < 830000000) - cp = 0xf6; - else - cp = 0xfe; - - return cp; -} - -static unsigned char mt352_cp_AVERMEDIA771(u32 freq) -{ - unsigned char cp = 0; - - if (freq < 150000000) - cp = 0xB4; - else if (freq < 173000000) - cp = 0xBC; - else if (freq < 250000000) - cp = 0xB4; - else if (freq < 400000000) - cp = 0xBC; - else if (freq < 420000000) - cp = 0xF4; - else if (freq < 470000000) - cp = 0xFC; - else if (freq < 600000000) - cp = 0xBC; - else if (freq < 730000000) - cp = 0xF4; - else - cp = 0xFC; - - return cp; -} - -static unsigned char mt352_cp_TDTC9251DH01C(u32 freq) -{ - return(0xcc); -} - -static unsigned char mt352_cp_DVICODVBT1(u32 freq) +static u8 mt352_read_register(struct mt352_state* state, u8 reg) { - unsigned char cp = 0; - - if (freq < 542000000) - cp = 0xbc; - else if (freq < 830000000) - cp = 0xf4; - else - cp = 0xfc; - - return cp; -} - -static unsigned char mt352_cp_DVICODVBTLITE(u32 freq) -{ - unsigned char cp = 0; - - if (freq < 542000000) - cp = 0xb4; - else if (freq < 771000000) - cp = 0xbc; - else - cp = 0xf4; - - return cp; -} + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, + .flags = 0, + .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, .len = 1 } }; -static unsigned char mt352_bs_TUA6034(u32 freq) -{ - unsigned char bs = 0; + ret = i2c_transfer(state->i2c, msg, 2); - if (freq < 250000000) - bs = 0x01; - else - bs = 0x08; + if (ret != 2) + printk(KERN_WARNING + "%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - return bs; + return b1[0]; } -static unsigned char mt352_bs_AVERMEDIA771(u32 freq) -{ - unsigned char bs = 0; - if (freq < 150000000) - bs = 0x01; - else if (freq < 173000000) - bs = 0x01; - else if (freq < 250000000) - bs = 0x02; - else if (freq < 400000000) - bs = 0x02; - else if (freq < 420000000) - bs = 0x02; - else if (freq < 470000000) - bs = 0x02; - else if (freq < 600000000) - bs = 0x08; - else if (freq < 730000000) - bs = 0x08; - else - bs = 0x08; - return bs; -} -static unsigned char mt352_bs_TDTC9251DH01C(u32 freq) -{ - unsigned char bs = 0; - if (freq >= 48000000 && freq <= 154000000) /* low band */ - bs = 0x09; - if (freq >= 161000000 && freq <= 439000000) /* medium band */ - bs = 0x0a; - if (freq >= 447000000 && freq <= 863000000) /* high band */ - bs = 0x08; - return bs; -} -static unsigned char mt352_bs_DVICODVBT1(u32 freq) -{ - unsigned char bs = 0; - if (freq == 0) /* power down PLL */ - bs = 0x03; - else if (freq < 157500000) /* low band */ - bs = 0x01; - else if (freq < 443250000) /* mid band */ - bs = 0x02; - else /* high band */ - bs = 0x04; - return bs; -} -static unsigned char mt352_bs_DVICODVBTLITE(u32 freq) -{ - unsigned char bs = 0; - - if (freq == 0) /* power down PLL */ - bs = 0x03; - else if (freq < 443250000) /* mid band */ - bs = 0x02; - else /* high band */ - bs = 0x08; - - return bs; -} - -static u32 mt352_read_eeprom_dword(struct i2c_adapter *i2c, int dword_base) - { - int i; - u32 dword = 0; - u8 reg, val; - struct i2c_msg msg[2] = { - { - .addr = 0x50, - .flags = 0, - .buf = ®, - .len = 1 - }, - { - .addr = 0x50, - .flags = I2C_M_RD, - .buf = &val, - .len = 1 - } - }; - - for (i = 0; i < 4; i++) { - reg = dword_base + i; - if (i2c_transfer(i2c,msg,2) != 2) - return 0; - dword = (dword << 8) | val; - } - - return dword; -} - -static int mt352_init(struct i2c_adapter *i2c, int card_type) -{ - /** - * all register write sequence have the register address of the - * first register in the first byte, thenafter the value to write - * into this and the following registers. - * - * - * We only write non-default settings, all default settings are - * restored by the full mt352_reset sequence. - * - * - * The optimal AGC target value and slope might vary from tuner - * type to tuner type, so check whether you need to adjust this one... - **/ - - return(MT352_INIT(i2c)); -} - -static int mt352_sleep(struct i2c_adapter *i2c) +static int mt352_sleep(struct dvb_frontend* fe) { static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 }; - mt352_write(mt352_softdown, sizeof(mt352_softdown)); + mt352_write(fe, mt352_softdown, sizeof(mt352_softdown)); return 0; } -static int mt352_set_parameters(struct i2c_adapter *i2c, - struct dvb_frontend_parameters *param, - int card_type) +static int mt352_set_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) { + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; unsigned char buf[14]; unsigned int tps = 0; struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - uint16_t tmp; int i; switch (op->code_rate_HP) { @@ -600,22 +252,7 @@ buf[6] = 0x31; /* INPUT_FREQ_(1|0), 20.48MHz clock, 36.166667MHz IF */ buf[7] = 0x05; /* see MT352 Design Manual page 32 for details */ - buf[8] = PLL_I2C_ADDR; - - /** - * All the following settings are tuner module dependent, - * check the datasheet... - */ - - /* here we assume 1/6MHz == 166.66kHz stepsize */ - #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ - tmp = (((param->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - - buf[9] = msb(tmp); /* CHAN_START_(1|0) */ - buf[10] = lsb(tmp); - - buf[11] = MT352_CHARGE_PUMP(param->frequency); - buf[12] = MT352_BAND_SELECT(param->frequency); + state->config->pll_set(fe, param, buf+8); buf[13] = 0x01; /* TUNER_GO!! */ @@ -623,39 +260,18 @@ * parameters already set. Enhances tuning time and prevents stream * breakup when retuning the same transponder. */ for (i = 1; i < 13; i++) - if (buf[i] != mt352_read_register(i2c, i + 0x50)) { - mt352_write(buf, sizeof(buf)); + if (buf[i] != mt352_read_register(state, i + 0x50)) { + mt352_write(fe, buf, sizeof(buf)); break; } return 0; } -static u8 mt352_read_register(struct i2c_adapter *i2c, u8 reg) -{ - int ret; - u8 b0 [] = { reg }; - u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = I2C_MT352_ADDR, - .flags = 0, - .buf = b0, .len = 1 }, - { .addr = I2C_MT352_ADDR, - .flags = I2C_M_RD, - .buf = b1, .len = 1 } }; - - ret = i2c_transfer(i2c, msg, 2); - - if (ret != 2) - printk(KERN_WARNING - "%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - - return b1[0]; -} - - -static int mt352_get_parameters(struct i2c_adapter *i2c, +static int mt352_get_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; u16 tps; u16 div; u8 trl; @@ -672,7 +288,7 @@ FEC_AUTO }; - if ( (mt352_read_register(i2c,0x00) & 0xC0) != 0xC0 ) + if ( (mt352_read_register(state,0x00) & 0xC0) != 0xC0 ) { return -EINVAL; } @@ -680,9 +296,9 @@ /* Use TPS_RECEIVED-registers, not the TPS_CURRENT-registers because * the mt352 sometimes works with the wrong parameters */ - tps = (mt352_read_register(i2c, TPS_RECEIVED_1) << 8) | mt352_read_register(i2c, TPS_RECEIVED_0); - div = (mt352_read_register(i2c, CHAN_START_1) << 8) | mt352_read_register(i2c, CHAN_START_0); - trl = mt352_read_register(i2c, TRL_NOMINAL_RATE_1); + tps = (mt352_read_register(state, TPS_RECEIVED_1) << 8) | mt352_read_register(state, TPS_RECEIVED_0); + div = (mt352_read_register(state, CHAN_START_1) << 8) | mt352_read_register(state, CHAN_START_0); + trl = mt352_read_register(state, TRL_NOMINAL_RATE_1); op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; @@ -759,7 +375,7 @@ } - if (mt352_read_register(i2c, STATUS_2) & 0x02) + if (mt352_read_register(state, STATUS_2) & 0x02) param->inversion = INVERSION_OFF; else param->inversion = INVERSION_ON; @@ -767,26 +383,13 @@ return 0; } - -static int mt352_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int mt352_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct mt352_state *state = fe->data; - struct i2c_adapter *i2c = state->i2c; - int card_type = state->card_type; - u8 r,snr; - fe_status_t *status; - u16 signal; - struct dvb_frontend_tune_settings *fe_tune_settings; - - switch (cmd) { - case FE_GET_INFO: - memcpy(arg, &state->fe_info, sizeof(struct dvb_frontend_info)); - break; + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; + u8 r; - case FE_READ_STATUS: - status = arg; *status = 0; - r = mt352_read_register (i2c, STATUS_0); + r = mt352_read_register (state, STATUS_0); if (r & (1 << 4)) *status = FE_HAS_CARRIER; if (r & (1 << 1)) @@ -794,243 +397,164 @@ if (r & (1 << 5)) *status |= FE_HAS_LOCK; - r = mt352_read_register (i2c, STATUS_1); + r = mt352_read_register (state, STATUS_1); if (r & (1 << 1)) *status |= FE_HAS_SYNC; - r = mt352_read_register (i2c, STATUS_3); + r = mt352_read_register (state, STATUS_3); if (r & (1 << 6)) *status |= FE_HAS_SIGNAL; - break; + if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != + (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) + *status &= ~FE_HAS_LOCK; - case FE_READ_BER: - *((u32 *) arg) = (mt352_read_register (i2c, RS_ERR_CNT_2) << 16) | - (mt352_read_register (i2c, RS_ERR_CNT_1) << 8) | - (mt352_read_register (i2c, RS_ERR_CNT_0)); - break; - - case FE_READ_SIGNAL_STRENGTH: - signal = (mt352_read_register (i2c, AGC_GAIN_3) << 8) | - (mt352_read_register (i2c, AGC_GAIN_2)); - *((u16*) arg) = ~signal; - break; - - case FE_READ_SNR: - snr = mt352_read_register (i2c, SNR); - *((u16*) arg) = (snr << 8) | snr; - break; - - case FE_READ_UNCORRECTED_BLOCKS: - *(u32*) arg = (mt352_read_register (i2c, RS_UBC_1) << 8) | - (mt352_read_register (i2c, RS_UBC_0)); - break; - - case FE_SET_FRONTEND: - return mt352_set_parameters (i2c, - (struct dvb_frontend_parameters *) arg, - card_type); - - case FE_GET_FRONTEND: - return mt352_get_parameters (i2c, - (struct dvb_frontend_parameters *) arg); - - case FE_GET_TUNE_SETTINGS: - fe_tune_settings = (struct dvb_frontend_tune_settings *) arg; - fe_tune_settings->min_delay_ms = 800; - fe_tune_settings->step_size = 0; - fe_tune_settings->max_drift = 0; - break; - - case FE_SLEEP: - return mt352_sleep(i2c); - - case FE_INIT: - /* Only send the initialisation command if the demodulator - * isn't already enabled. Greatly enhances tuning time. */ - if ((mt352_read_register(i2c, CLOCK_CTL) & 0x10) == 0 || - (mt352_read_register(i2c, CONFIG) & 0x20) == 0) - return mt352_init(i2c, card_type); - else - return 0; + return 0; +} + +static int mt352_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; - default: - return -EOPNOTSUPP; + *ber = (mt352_read_register (state, RS_ERR_CNT_2) << 16) | + (mt352_read_register (state, RS_ERR_CNT_1) << 8) | + (mt352_read_register (state, RS_ERR_CNT_0)); + + return 0; } +static int mt352_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; + + u16 signal = (mt352_read_register (state, AGC_GAIN_3) << 8) | + (mt352_read_register (state, AGC_GAIN_2)); + + *strength = ~signal; return 0; } -static struct i2c_client client_template; - -static int mt352_attach_adapter(struct i2c_adapter *i2c) +static int mt352_read_snr(struct dvb_frontend* fe, u16* snr) { - static int num_cards_probed; - struct mt352_state *state; - struct i2c_client *client; - static u8 mt352_reset_attach [] = { RESET, 0xC0 }; - int ret; - int card_type, forced_card = -1; + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; - dprintk("Trying to attach to adapter 0x%x:%s.\n", - i2c->id, i2c->name); + u8 _snr = mt352_read_register (state, SNR); + *snr = (_snr << 8) | _snr; - if (mt352_read_register(i2c, CHIP_ID) != ID_MT352) - return -ENODEV; + return 0; +} - if ( !(state = kmalloc(sizeof(struct mt352_state), GFP_KERNEL)) ) - return -ENOMEM; +static int mt352_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; - memset(state, 0, sizeof(struct mt352_state)); - state->i2c = i2c; - state->card_type = -1; - memcpy(&state->fe_info, &mt352_info_template, sizeof(struct dvb_frontend_info)); + *ucblocks = (mt352_read_register (state, RS_UBC_1) << 8) | + (mt352_read_register (state, RS_UBC_0)); - /* Attempt autodetection of card type based on PCI ID information - * stored in any on-board EEPROM. */ - switch (mt352_read_eeprom_dword(i2c, 0xFC)) { /* BT878A chipset */ - case 0x07711461: - state->card_type = CARD_AVDVBT771; - break; - case 0xdb1018ac: - state->card_type = CARD_DVICODVBTLITE; - break; - default: - break; - } - - switch (mt352_read_eeprom_dword(i2c, 0x04)) { /* CX2388x chipset */ - case 0xac1800db: - state->card_type = CARD_DVICODVBT1; - break; - default: - break; - } - - if (num_cards_probed < force_card_count) - forced_card = force_card[num_cards_probed++]; - - if (state->card_type == -1 && forced_card < 0) { - dprintk("Card type not automatically detected. You " - "must use the 'force_card' module parameter.\n"); - kfree(state); - return -ENODEV; + return 0; } - if (forced_card >= 0) { - if (state->card_type >= 0 && forced_card != state->card_type) - printk(KERN_WARNING FRONTEND_NAME ": Warning, overriding" - " detected card type.\n"); - state->card_type = forced_card; +static int mt352_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 800; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + + return 0; } - card_type = state->card_type; - printk(KERN_INFO FRONTEND_NAME ": Setup for %s\n", FE_NAME); +static int mt352_init(struct dvb_frontend* fe) +{ + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; - /* set the frontend name and card-specific frequency info */ - strlcpy(state->fe_info.name, FE_NAME, sizeof(state->fe_info.name)); - state->fe_info.frequency_min = FE_FREQ_MIN; - state->fe_info.frequency_max = FE_FREQ_MAX; - state->fe_info.frequency_stepsize = FE_FREQ_STEPSIZE; + static u8 mt352_reset_attach [] = { RESET, 0xC0 }; - /* Do a "hard" reset */ - mt352_write(mt352_reset_attach, sizeof(mt352_reset_attach)); + if ((mt352_read_register(state, CLOCK_CTL) & 0x10) == 0 || + (mt352_read_register(state, CONFIG) & 0x20) == 0) { - /* Try to intiialise the device */ - if (mt352_init(i2c, card_type) != 0) { - kfree(state); - return -ENODEV; + /* Do a "hard" reset */ + mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach)); + return state->config->demod_init(fe); } - if ( !(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)) ) { - kfree(state); - return -ENOMEM; + return 0; } - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = i2c; - client->addr = 0; // XXX - i2c_set_clientdata(client, state); - - if ((ret = i2c_attach_client(client))) { - kfree(client); +static void mt352_release(struct dvb_frontend* fe) +{ + struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; kfree(state); - return ret; } - return 0; -} +static struct dvb_frontend_ops mt352_ops; -static int mt352_detach_client(struct i2c_client *client) +struct dvb_frontend* mt352_attach(const struct mt352_config* config, + struct i2c_adapter* i2c) { - struct mt352_state *state = i2c_get_clientdata(client); + struct mt352_state* state = NULL; - if (state->dvb) - dvb_unregister_frontend (mt352_ioctl, state->dvb); - i2c_detach_client(client); - kfree(client); - kfree(state); - return 0; -} + /* allocate memory for the internal state */ + state = (struct mt352_state*) kmalloc(sizeof(struct mt352_state), GFP_KERNEL); + if (state == NULL) goto error; -static int mt352_command (struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct mt352_state *state = i2c_get_clientdata(client); - int ret; + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops)); - switch (cmd) { - case FE_REGISTER: - if (!state->dvb) { - if ((ret = dvb_register_frontend(mt352_ioctl, arg, - state, &state->fe_info, - THIS_MODULE))) - return ret; - state->dvb = arg; - } - break; - case FE_UNREGISTER: - if (state->dvb == arg) { - dvb_unregister_frontend(mt352_ioctl, state->dvb); - state->dvb = NULL; - } - break; - default: - return -EOPNOTSUPP; - } - return 0; -} + /* check if the demod is there */ + if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error; -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_MT352, - .flags = I2C_DF_NOTIFY, - .attach_adapter = mt352_attach_adapter, - .detach_client = mt352_detach_client, - .command = mt352_command, -}; + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops mt352_ops = { + + .info = { + .name = "Zarlink MT352 DVB-T", + .type = FE_OFDM, + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | + FE_CAN_MUTE_TS + }, -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; + .release = mt352_release, -static int __init mt352_module_init(void) -{ - return i2c_add_driver(&driver); -} + .init = mt352_init, + .sleep = mt352_sleep, -static void __exit mt352_module_exit(void) -{ - if (i2c_del_driver(&driver)) - printk(KERN_ERR "mt352: driver deregistration failed.\n"); -} + .set_frontend = mt352_set_parameters, + .get_frontend = mt352_get_parameters, + .get_tune_settings = mt352_get_tune_settings, + + .read_status = mt352_read_status, + .read_ber = mt352_read_ber, + .read_signal_strength = mt352_read_signal_strength, + .read_snr = mt352_read_snr, + .read_ucblocks = mt352_read_ucblocks, +}; -module_init(mt352_module_init); -module_exit(mt352_module_exit); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("DVB-T MT352 Zarlink"); +MODULE_DESCRIPTION("Zarlink MT352 DVB-T Demodulator driver"); MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(mt352_attach); +EXPORT_SYMBOL(mt352_write); diff -Nru a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h --- a/drivers/media/dvb/frontends/mt352.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/frontends/mt352.h 2004-12-12 17:40:53 -08:00 @@ -30,145 +30,29 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= */ -#ifndef _MT352_ -#define _MT352_ +#ifndef MT352_H +#define MT352_H -#define I2C_MT352_ADDR 0x0f -#define ID_MT352 0x13 +#include -#define CARD_AVDVBT771 0x00 -#define CARD_TUA6034 0x01 -#define CARD_TDTC9251DH01C 0x02 -#define CARD_DVICODVBT1 0x03 -#define CARD_DVICODVBTLITE 0x04 - -#define msb(x) (((x) >> 8) & 0xff) -#define lsb(x) ((x) & 0xff) - -enum mt352_reg_addr { - STATUS_0 = 0x00, - STATUS_1 = 0x01, - STATUS_2 = 0x02, - STATUS_3 = 0x03, - STATUS_4 = 0x04, - INTERRUPT_0 = 0x05, - INTERRUPT_1 = 0x06, - INTERRUPT_2 = 0x07, - INTERRUPT_3 = 0x08, - SNR = 0x09, - VIT_ERR_CNT_2 = 0x0A, - VIT_ERR_CNT_1 = 0x0B, - VIT_ERR_CNT_0 = 0x0C, - RS_ERR_CNT_2 = 0x0D, - RS_ERR_CNT_1 = 0x0E, - RS_ERR_CNT_0 = 0x0F, - RS_UBC_1 = 0x10, - RS_UBC_0 = 0x11, - AGC_GAIN_3 = 0x12, - AGC_GAIN_2 = 0x13, - AGC_GAIN_1 = 0x14, - AGC_GAIN_0 = 0x15, - FREQ_OFFSET_2 = 0x17, - FREQ_OFFSET_1 = 0x18, - FREQ_OFFSET_0 = 0x19, - TIMING_OFFSET_1 = 0x1A, - TIMING_OFFSET_0 = 0x1B, - CHAN_FREQ_1 = 0x1C, - CHAN_FREQ_0 = 0x1D, - TPS_RECEIVED_1 = 0x1E, - TPS_RECEIVED_0 = 0x1F, - TPS_CURRENT_1 = 0x20, - TPS_CURRENT_0 = 0x21, - TPS_CELL_ID_1 = 0x22, - TPS_CELL_ID_0 = 0x23, - TPS_MISC_DATA_2 = 0x24, - TPS_MISC_DATA_1 = 0x25, - TPS_MISC_DATA_0 = 0x26, - RESET = 0x50, - TPS_GIVEN_1 = 0x51, - TPS_GIVEN_0 = 0x52, - ACQ_CTL = 0x53, - TRL_NOMINAL_RATE_1 = 0x54, - TRL_NOMINAL_RATE_0 = 0x55, - INPUT_FREQ_1 = 0x56, - INPUT_FREQ_0 = 0x57, - TUNER_ADDR = 0x58, - CHAN_START_1 = 0x59, - CHAN_START_0 = 0x5A, - CONT_1 = 0x5B, - CONT_0 = 0x5C, - TUNER_GO = 0x5D, - STATUS_EN_0 = 0x5F, - STATUS_EN_1 = 0x60, - INTERRUPT_EN_0 = 0x61, - INTERRUPT_EN_1 = 0x62, - INTERRUPT_EN_2 = 0x63, - INTERRUPT_EN_3 = 0x64, - AGC_TARGET = 0x67, - AGC_CTL = 0x68, - CAPT_RANGE = 0x75, - SNR_SELECT_1 = 0x79, - SNR_SELECT_0 = 0x7A, - RS_ERR_PER_1 = 0x7C, - RS_ERR_PER_0 = 0x7D, - CHIP_ID = 0x7F, - CHAN_STOP_1 = 0x80, - CHAN_STOP_0 = 0x81, - CHAN_STEP_1 = 0x82, - CHAN_STEP_0 = 0x83, - FEC_LOCK_TIME = 0x85, - OFDM_LOCK_TIME = 0x86, - ACQ_DELAY = 0x87, - SCAN_CTL = 0x88, - CLOCK_CTL = 0x89, - CONFIG = 0x8A, - MCLK_RATIO = 0x8B, - GPP_CTL = 0x8C, - ADC_CTL_1 = 0x8E, - ADC_CTL_0 = 0x8F +struct mt352_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* Initialise the demodulator and PLL. Cannot be NULL */ + int (*demod_init)(struct dvb_frontend* fe); + + /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings. + * byte0: Set to pll i2c address (nonlinux; left shifted by 1) + * byte1-4: PLL configuration. + */ + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf); }; -struct _tuner_info { - char *fe_name; -#define FE_NAME tuner_info[card_type].fe_name +extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, + struct i2c_adapter* i2c); - __u32 fe_frequency_min; -#define FE_FREQ_MIN tuner_info[card_type].fe_frequency_min +extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen); - __u32 fe_frequency_max; -#define FE_FREQ_MAX tuner_info[card_type].fe_frequency_max - - __u32 fe_frequency_stepsize; //verificare se u32 e' corretto -#define FE_FREQ_STEPSIZE tuner_info[card_type].fe_frequency_stepsize - - u8 pll_i2c_addr; -#define PLL_I2C_ADDR tuner_info[card_type].pll_i2c_addr - - int (* mt352_init) (struct i2c_adapter *i2c); -#define MT352_INIT tuner_info[card_type].mt352_init - - unsigned char (* mt352_charge_pump) (u32 freq); -#define MT352_CHARGE_PUMP tuner_info[card_type].mt352_charge_pump - - unsigned char (* mt352_band_select) (u32 freq); -#define MT352_BAND_SELECT tuner_info[card_type].mt352_band_select -}; - -static int mt352_init_TUA6034(struct i2c_adapter *i2c); -static int mt352_init_AVERMEDIA771(struct i2c_adapter *i2c); -static int mt352_init_TDTC9251DH01C(struct i2c_adapter *i2c); -static int mt352_init_DVICODVBT1(struct i2c_adapter *i2c); -static int mt352_init_DVICODVBTLITE(struct i2c_adapter *i2c); -static unsigned char mt352_cp_TUA6034(u32 freq); -static unsigned char mt352_cp_AVERMEDIA771(u32 freq); -static unsigned char mt352_cp_TDTC9251DH01C(u32 freq); -static unsigned char mt352_cp_DVICODVBT1(u32 freq); -static unsigned char mt352_cp_DVICODVBTLITE(u32 freq); -static unsigned char mt352_bs_TUA6034(u32 freq); -static unsigned char mt352_bs_AVERMEDIA771(u32 freq); -static unsigned char mt352_bs_TDTC9251DH01C(u32 freq); -static unsigned char mt352_bs_DVICODVBT1(u32 freq); -static unsigned char mt352_bs_DVICODVBTLITE(u32 freq); -static u8 mt352_read_register(struct i2c_adapter *i2c, u8 reg); - -#endif /* _MT352_ */ +#endif // MT352_H diff -Nru a/drivers/media/dvb/frontends/mt352_priv.h b/drivers/media/dvb/frontends/mt352_priv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/mt352_priv.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,127 @@ +/* + * Driver for Zarlink DVB-T MT352 demodulator + * + * Written by Holger Waechtler + * and Daniel Mack + * + * AVerMedia AVerTV DVB-T 771 support by + * Wolfram Joost + * + * Support for Samsung TDTC9251DH01C(M) tuner + * Copyright (C) 2004 Antonio Mancuso + * Amauri Celani + * + * DVICO FusionHDTV DVB-T1 and DVICO FusionHDTV DVB-T Lite support by + * 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 + * 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 _MT352_PRIV_ +#define _MT352_PRIV_ + +#define ID_MT352 0x13 + +#define msb(x) (((x) >> 8) & 0xff) +#define lsb(x) ((x) & 0xff) + +enum mt352_reg_addr { + STATUS_0 = 0x00, + STATUS_1 = 0x01, + STATUS_2 = 0x02, + STATUS_3 = 0x03, + STATUS_4 = 0x04, + INTERRUPT_0 = 0x05, + INTERRUPT_1 = 0x06, + INTERRUPT_2 = 0x07, + INTERRUPT_3 = 0x08, + SNR = 0x09, + VIT_ERR_CNT_2 = 0x0A, + VIT_ERR_CNT_1 = 0x0B, + VIT_ERR_CNT_0 = 0x0C, + RS_ERR_CNT_2 = 0x0D, + RS_ERR_CNT_1 = 0x0E, + RS_ERR_CNT_0 = 0x0F, + RS_UBC_1 = 0x10, + RS_UBC_0 = 0x11, + AGC_GAIN_3 = 0x12, + AGC_GAIN_2 = 0x13, + AGC_GAIN_1 = 0x14, + AGC_GAIN_0 = 0x15, + FREQ_OFFSET_2 = 0x17, + FREQ_OFFSET_1 = 0x18, + FREQ_OFFSET_0 = 0x19, + TIMING_OFFSET_1 = 0x1A, + TIMING_OFFSET_0 = 0x1B, + CHAN_FREQ_1 = 0x1C, + CHAN_FREQ_0 = 0x1D, + TPS_RECEIVED_1 = 0x1E, + TPS_RECEIVED_0 = 0x1F, + TPS_CURRENT_1 = 0x20, + TPS_CURRENT_0 = 0x21, + TPS_CELL_ID_1 = 0x22, + TPS_CELL_ID_0 = 0x23, + TPS_MISC_DATA_2 = 0x24, + TPS_MISC_DATA_1 = 0x25, + TPS_MISC_DATA_0 = 0x26, + RESET = 0x50, + TPS_GIVEN_1 = 0x51, + TPS_GIVEN_0 = 0x52, + ACQ_CTL = 0x53, + TRL_NOMINAL_RATE_1 = 0x54, + TRL_NOMINAL_RATE_0 = 0x55, + INPUT_FREQ_1 = 0x56, + INPUT_FREQ_0 = 0x57, + TUNER_ADDR = 0x58, + CHAN_START_1 = 0x59, + CHAN_START_0 = 0x5A, + CONT_1 = 0x5B, + CONT_0 = 0x5C, + TUNER_GO = 0x5D, + STATUS_EN_0 = 0x5F, + STATUS_EN_1 = 0x60, + INTERRUPT_EN_0 = 0x61, + INTERRUPT_EN_1 = 0x62, + INTERRUPT_EN_2 = 0x63, + INTERRUPT_EN_3 = 0x64, + AGC_TARGET = 0x67, + AGC_CTL = 0x68, + CAPT_RANGE = 0x75, + SNR_SELECT_1 = 0x79, + SNR_SELECT_0 = 0x7A, + RS_ERR_PER_1 = 0x7C, + RS_ERR_PER_0 = 0x7D, + CHIP_ID = 0x7F, + CHAN_STOP_1 = 0x80, + CHAN_STOP_0 = 0x81, + CHAN_STEP_1 = 0x82, + CHAN_STEP_0 = 0x83, + FEC_LOCK_TIME = 0x85, + OFDM_LOCK_TIME = 0x86, + ACQ_DELAY = 0x87, + SCAN_CTL = 0x88, + CLOCK_CTL = 0x89, + CONFIG = 0x8A, + MCLK_RATIO = 0x8B, + GPP_CTL = 0x8C, + ADC_CTL_1 = 0x8E, + ADC_CTL_0 = 0x8F +}; + +/* here we assume 1/6MHz == 166.66kHz stepsize */ +#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + +#endif /* _MT352_PRIV_ */ diff -Nru a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c --- a/drivers/media/dvb/frontends/nxt6000.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/frontends/nxt6000.c 2004-12-12 17:40:53 -08:00 @@ -1,13 +1,6 @@ /* - NxtWave Communications - NXT6000 demodulator driver - This driver currently supports: - - Alps TDME7 (Tuner: MITEL SP5659) - Alps TDED4 (Tuner: TI ALP510, external Nxt6000) - Comtech DVBT-6k07 (PLL IC: SP5730) - Copyright (C) 2002-2003 Florian Schirmer Copyright (C) 2003 Paul Andreassen @@ -34,217 +27,68 @@ #include #include "dvb_frontend.h" +#include "nxt6000_priv.h" #include "nxt6000.h" -MODULE_DESCRIPTION("NxtWave NXT6000 DVB demodulator driver"); -MODULE_AUTHOR("Florian Schirmer"); -MODULE_LICENSE("GPL"); - -static int debug = 0; -MODULE_PARM(debug, "i"); -static struct dvb_frontend_info nxt6000_info = { - .name = "NxtWave NXT6000", - .type = FE_OFDM, - .frequency_min = 0, - .frequency_max = 863250000, - .frequency_stepsize = 62500, - /*.frequency_tolerance = */ /* FIXME: 12% of SR */ - .symbol_rate_min = 0, /* FIXME */ - .symbol_rate_max = 9360000, /* FIXME */ - .symbol_rate_tolerance = 4000, - .notifier_delay = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; +struct nxt6000_state { -struct nxt6000_config { - u8 demod_addr; - u8 tuner_addr; - u8 tuner_type; - u8 clock_inversion; struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; -#define TUNER_TYPE_ALP510 0 -#define TUNER_TYPE_SP5659 1 -#define TUNER_TYPE_SP5730 2 + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct nxt6000_config* config; -// #define FE2NXT(fe) ((struct nxt6000_config *)((fe)->data)) -#define FREQ2DIV(freq) ((freq + 36166667) / 166667) + struct dvb_frontend frontend; +}; + +static int debug = 0; #define dprintk if (debug) printk -static int nxt6000_write(struct i2c_adapter *i2c, u8 addr, u8 reg, u8 data) +static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data) { u8 buf[] = {reg, data}; - struct i2c_msg msg = {.addr = addr >> 1, .flags = 0, .buf = buf, .len = 2}; + struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 2 }; int ret; - if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) - dprintk("nxt6000: nxt6000_write error (.addr = 0x%02X, reg: 0x%02X, data: 0x%02X, ret: %d)\n", addr, reg, data, ret); + if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) + dprintk("nxt6000: nxt6000_write error (reg: 0x%02X, data: 0x%02X, ret: %d)\n", reg, data, ret); return (ret != 1) ? -EFAULT : 0; } -static u8 nxt6000_writereg(struct nxt6000_config *nxt, u8 reg, u8 data) -{ - return nxt6000_write(nxt->i2c, nxt->demod_addr, reg, data); -} - -static u8 nxt6000_read(struct i2c_adapter *i2c, u8 addr, u8 reg) +static u8 nxt6000_readreg(struct nxt6000_state* state, u8 reg) { int ret; u8 b0[] = {reg}; u8 b1[] = {0}; struct i2c_msg msgs[] = { - {.addr = addr >> 1,.flags = 0,.buf = b0,.len = 1}, - {.addr = addr >> 1,.flags = I2C_M_RD,.buf = b1,.len = 1} + {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, + {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} }; - ret = i2c_transfer(i2c, msgs, 2); + ret = i2c_transfer(state->i2c, msgs, 2); if (ret != 2) - dprintk("nxt6000: nxt6000_read error (.addr = 0x%02X, reg: 0x%02X, ret: %d)\n", addr, reg, ret); + dprintk("nxt6000: nxt6000_read error (reg: 0x%02X, ret: %d)\n", reg, ret); return b1[0]; } -static u8 nxt6000_readreg(struct nxt6000_config *nxt, u8 reg) -{ - return nxt6000_read(nxt->i2c, nxt->demod_addr, reg); -} - -static int pll_test(struct i2c_adapter *i2c, u8 demod_addr, u8 tuner_addr) -{ - u8 buf [1]; - struct i2c_msg msg = {.addr = tuner_addr >> 1,.flags = I2C_M_RD,.buf = buf,.len = 1 }; - int ret; - - nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ - ret = i2c_transfer(i2c, &msg, 1); - nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ - - return (ret != 1) ? -EFAULT : 0; -} - -static int pll_write(struct i2c_adapter *i2c, u8 demod_addr, u8 tuner_addr, u8 * buf, u8 len) -{ - struct i2c_msg msg = {.addr = tuner_addr >> 1, .flags = 0, .buf = buf, .len = len}; - int ret; - - nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ - ret = i2c_transfer(i2c, &msg, 1); - nxt6000_write(i2c, demod_addr, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ - - if (ret != 1) - dprintk("nxt6000: pll_write error %d\n", ret); - - return (ret != 1) ? -EFAULT : 0; -} - -static int sp5659_set_tv_freq(struct nxt6000_config *nxt, u32 freq) -{ - u8 buf[4]; - - buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F; - buf[1] = FREQ2DIV(freq) & 0xFF; - buf[2] = (((FREQ2DIV(freq) >> 15) & 0x03) << 5) | 0x85; - - if ((freq >= 174000000) && (freq < 230000000)) - buf[3] = 0x82; - else if ((freq >= 470000000) && (freq < 782000000)) - buf[3] = 0x85; - else if ((freq >= 782000000) && (freq < 863000000)) - buf[3] = 0xC5; - else - return -EINVAL; - - return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4); -} - -static int alp510_set_tv_freq(struct nxt6000_config *nxt, u32 freq) -{ - u8 buf[4]; - - buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F; - buf[1] = FREQ2DIV(freq) & 0xFF; - buf[2] = 0x85; - -#if 0 - if ((freq >= 47000000) && (freq < 153000000)) - buf[3] = 0x01; - else if ((freq >= 153000000) && (freq < 430000000)) - buf[3] = 0x02; - else if ((freq >= 430000000) && (freq < 824000000)) - buf[3] = 0x08; - else if ((freq >= 824000000) && (freq < 863000000)) - buf[3] = 0x88; - else - return -EINVAL; -#else - if ((freq >= 47000000) && (freq < 153000000)) - buf[3] = 0x01; - else if ((freq >= 153000000) && (freq < 430000000)) - buf[3] = 0x02; - else if ((freq >= 430000000) && (freq < 824000000)) - buf[3] = 0x0C; - else if ((freq >= 824000000) && (freq < 863000000)) - buf[3] = 0x8C; - else - return -EINVAL; -#endif - - return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4); -} - -static int sp5730_set_tv_freq(struct nxt6000_config *nxt, u32 freq) -{ - u8 buf[4]; - - buf[0] = (FREQ2DIV(freq) >> 8) & 0x7F; - buf[1] = FREQ2DIV(freq) & 0xFF; - buf[2] = 0x93; - - if ((freq >= 51000000) && (freq < 132100000)) - buf[3] = 0x05; - else if ((freq >= 132100000) && (freq < 143000000)) - buf[3] = 0x45; - else if ((freq >= 146000000) && (freq < 349100000)) - buf[3] = 0x06; - else if ((freq >= 349100000) && (freq < 397100000)) - buf[3] = 0x46; - else if ((freq >= 397100000) && (freq < 426000000)) - buf[3] = 0x86; - else if ((freq >= 430000000) && (freq < 659100000)) - buf[3] = 0x03; - else if ((freq >= 659100000) && (freq < 759100000)) - buf[3] = 0x43; - else if ((freq >= 759100000) && (freq < 858000000)) - buf[3] = 0x83; - else - return -EINVAL; - - return pll_write(nxt->i2c, nxt->demod_addr, nxt->tuner_addr, buf, 4); -} - -static void nxt6000_reset(struct nxt6000_config *fe) +static void nxt6000_reset(struct nxt6000_state* state) { u8 val; - val = nxt6000_readreg(fe, OFDM_COR_CTL); + val = nxt6000_readreg(state, OFDM_COR_CTL); - nxt6000_writereg(fe, OFDM_COR_CTL, val & ~COREACT); - nxt6000_writereg(fe, OFDM_COR_CTL, val | COREACT); + nxt6000_writereg(state, OFDM_COR_CTL, val & ~COREACT); + nxt6000_writereg(state, OFDM_COR_CTL, val | COREACT); } -static int nxt6000_set_bandwidth(struct nxt6000_config *fe, fe_bandwidth_t bandwidth) +static int nxt6000_set_bandwidth(struct nxt6000_state* state, fe_bandwidth_t bandwidth) { u16 nominal_rate; int result; @@ -270,119 +114,115 @@ break; default: - return -EINVAL; - } - if ((result = nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0) + if ((result = nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, nominal_rate & 0xFF)) < 0) return result; - return nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF); + return nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, (nominal_rate >> 8) & 0xFF); } -static int nxt6000_set_guard_interval(struct nxt6000_config *fe, fe_guard_interval_t guard_interval) +static int nxt6000_set_guard_interval(struct nxt6000_state* state, fe_guard_interval_t guard_interval) { switch(guard_interval) { case GUARD_INTERVAL_1_32: - - return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03)); + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x00 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); case GUARD_INTERVAL_1_16: - - return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03)); + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x01 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); case GUARD_INTERVAL_AUTO: case GUARD_INTERVAL_1_8: - - return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03)); + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x02 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); case GUARD_INTERVAL_1_4: - - return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x03)); + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, 0x03 | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x03)); default: return -EINVAL; } } -static int nxt6000_set_inversion(struct nxt6000_config *fe, fe_spectral_inversion_t inversion) +static int nxt6000_set_inversion(struct nxt6000_state* state, fe_spectral_inversion_t inversion) { switch(inversion) { case INVERSION_OFF: - - return nxt6000_writereg(fe, OFDM_ITB_CTL, 0x00); + return nxt6000_writereg(state, OFDM_ITB_CTL, 0x00); case INVERSION_ON: - - return nxt6000_writereg(fe, OFDM_ITB_CTL, ITBINV); + return nxt6000_writereg(state, OFDM_ITB_CTL, ITBINV); default: - return -EINVAL; } } -static int nxt6000_set_transmission_mode(struct nxt6000_config *fe, fe_transmit_mode_t transmission_mode) +static int nxt6000_set_transmission_mode(struct nxt6000_state* state, fe_transmit_mode_t transmission_mode) { int result; switch(transmission_mode) { case TRANSMISSION_MODE_2K: - - if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0) + if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x00 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) return result; - return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04)); + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x00 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); case TRANSMISSION_MODE_8K: case TRANSMISSION_MODE_AUTO: - - if ((result = nxt6000_writereg(fe, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(fe, EN_DMD_RACQ) & ~0x03))) < 0) + if ((result = nxt6000_writereg(state, EN_DMD_RACQ, 0x02 | (nxt6000_readreg(state, EN_DMD_RACQ) & ~0x03))) < 0) return result; - return nxt6000_writereg(fe, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(fe, OFDM_COR_MODEGUARD) & ~0x04)); + return nxt6000_writereg(state, OFDM_COR_MODEGUARD, (0x01 << 2) | (nxt6000_readreg(state, OFDM_COR_MODEGUARD) & ~0x04)); default: - return -EINVAL; } } -static void nxt6000_setup(struct nxt6000_config *fe) +static void nxt6000_setup(struct dvb_frontend* fe) { - nxt6000_writereg(fe, RS_COR_SYNC_PARAM, SYNC_PARAM); - nxt6000_writereg(fe, BER_CTRL, /*(1 << 2) |*/ (0x01 << 1) | 0x01); - nxt6000_writereg(fe, VIT_COR_CTL, VIT_COR_RESYNC); - nxt6000_writereg(fe, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(fe, OFDM_COR_CTL) & 0x0F)); - nxt6000_writereg(fe, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02); - nxt6000_writereg(fe, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW); - nxt6000_writereg(fe, OFDM_ITB_FREQ_1, 0x06); - nxt6000_writereg(fe, OFDM_ITB_FREQ_2, 0x31); - nxt6000_writereg(fe, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04); - nxt6000_writereg(fe, CAS_FREQ, 0xBB); /* CHECKME */ - nxt6000_writereg(fe, OFDM_SYR_CTL, 1 << 2); - nxt6000_writereg(fe, OFDM_PPM_CTL_1, PPM256); - nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_1, 0x49); - nxt6000_writereg(fe, OFDM_TRL_NOMINALRATE_2, 0x72); - nxt6000_writereg(fe, ANALOG_CONTROL_0, 1 << 5); - nxt6000_writereg(fe, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2); - nxt6000_writereg(fe, DIAG_CONFIG, TB_SET); + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; - if (fe->clock_inversion) - nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, CLKINVERSION); + nxt6000_writereg(state, RS_COR_SYNC_PARAM, SYNC_PARAM); + nxt6000_writereg(state, BER_CTRL, /*(1 << 2) | */ (0x01 << 1) | 0x01); + nxt6000_writereg(state, VIT_COR_CTL, VIT_COR_RESYNC); + nxt6000_writereg(state, OFDM_COR_CTL, (0x01 << 5) | (nxt6000_readreg(state, OFDM_COR_CTL) & 0x0F)); + nxt6000_writereg(state, OFDM_COR_MODEGUARD, FORCEMODE8K | 0x02); + nxt6000_writereg(state, OFDM_AGC_CTL, AGCLAST | INITIAL_AGC_BW); + nxt6000_writereg(state, OFDM_ITB_FREQ_1, 0x06); + nxt6000_writereg(state, OFDM_ITB_FREQ_2, 0x31); + nxt6000_writereg(state, OFDM_CAS_CTL, (0x01 << 7) | (0x02 << 3) | 0x04); + nxt6000_writereg(state, CAS_FREQ, 0xBB); /* CHECKME */ + nxt6000_writereg(state, OFDM_SYR_CTL, 1 << 2); + nxt6000_writereg(state, OFDM_PPM_CTL_1, PPM256); + nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_1, 0x49); + nxt6000_writereg(state, OFDM_TRL_NOMINALRATE_2, 0x72); + nxt6000_writereg(state, ANALOG_CONTROL_0, 1 << 5); + nxt6000_writereg(state, EN_DMD_RACQ, (1 << 7) | (3 << 4) | 2); + nxt6000_writereg(state, DIAG_CONFIG, TB_SET); + + if (state->config->clock_inversion) + nxt6000_writereg(state, SUB_DIAG_MODE_SEL, CLKINVERSION); else - nxt6000_writereg(fe, SUB_DIAG_MODE_SEL, 0); + nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0); + + nxt6000_writereg(state, TS_FORMAT, 0); - nxt6000_writereg(fe, TS_FORMAT, 0); + if (state->config->pll_init) { + nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ + state->config->pll_init(fe); + nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ + } } -static void nxt6000_dump_status(struct nxt6000_config *fe) +static void nxt6000_dump_status(struct nxt6000_state *state) { u8 val; @@ -400,12 +240,12 @@ */ printk("NXT6000 status:"); - val = nxt6000_readreg(fe, RS_COR_STAT); + val = nxt6000_readreg(state, RS_COR_STAT); printk(" DATA DESCR LOCK: %d,", val & 0x01); printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01); - val = nxt6000_readreg(fe, VIT_SYNC_STATUS); + val = nxt6000_readreg(state, VIT_SYNC_STATUS); printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01); @@ -443,7 +283,7 @@ } - val = nxt6000_readreg(fe, OFDM_COR_STAT); + val = nxt6000_readreg(state, OFDM_COR_STAT); printk(" CHCTrack: %d,", (val >> 7) & 0x01); printk(" TPSLock: %d,", (val >> 6) & 0x01); @@ -496,7 +336,7 @@ } - val = nxt6000_readreg(fe, OFDM_SYR_STAT); + val = nxt6000_readreg(state, OFDM_SYR_STAT); printk(" SYRLock: %d,", (val >> 4) & 0x01); printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K"); @@ -522,14 +362,11 @@ break; case 0x03: - printk(" SYRGuard: 1/4,"); - break; - } - val = nxt6000_readreg(fe, OFDM_TPS_RCVD_3); + val = nxt6000_readreg(state, OFDM_TPS_RCVD_3); switch((val >> 4) & 0x07) { @@ -599,7 +436,7 @@ } - val = nxt6000_readreg(fe, OFDM_TPS_RCVD_4); + val = nxt6000_readreg(state, OFDM_TPS_RCVD_4); printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K"); @@ -632,299 +469,156 @@ } /* Strange magic required to gain access to RF_AGC_STATUS */ - nxt6000_readreg(fe, RF_AGC_VAL_1); - val = nxt6000_readreg(fe, RF_AGC_STATUS); - val = nxt6000_readreg(fe, RF_AGC_STATUS); + nxt6000_readreg(state, RF_AGC_VAL_1); + val = nxt6000_readreg(state, RF_AGC_STATUS); + val = nxt6000_readreg(state, RF_AGC_STATUS); printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01); printk("\n"); } -static int nxt6000_ioctl(struct dvb_frontend *f, unsigned int cmd, void *arg) -{ - struct nxt6000_config *fe = (struct nxt6000_config *) f->data; - switch (cmd) { - case FE_GET_INFO: - memcpy(arg, &nxt6000_info, sizeof (struct dvb_frontend_info)); - return 0; - case FE_READ_STATUS: - { - fe_status_t *status = (fe_status_t *)arg; + + + + +static int nxt6000_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ u8 core_status; + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; *status = 0; - core_status = nxt6000_readreg(fe, OFDM_COR_STAT); + core_status = nxt6000_readreg(state, OFDM_COR_STAT); if (core_status & AGCLOCKED) *status |= FE_HAS_SIGNAL; - if (nxt6000_readreg(fe, OFDM_SYR_STAT) & GI14_SYR_LOCK) + if (nxt6000_readreg(state, OFDM_SYR_STAT) & GI14_SYR_LOCK) *status |= FE_HAS_CARRIER; - if (nxt6000_readreg(fe, VIT_SYNC_STATUS) & VITINSYNC) + if (nxt6000_readreg(state, VIT_SYNC_STATUS) & VITINSYNC) *status |= FE_HAS_VITERBI; - if (nxt6000_readreg(fe, RS_COR_STAT) & RSCORESTATUS) + if (nxt6000_readreg(state, RS_COR_STAT) & RSCORESTATUS) *status |= FE_HAS_SYNC; if ((core_status & TPSLOCKED) && (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))) *status |= FE_HAS_LOCK; if (debug) - nxt6000_dump_status(fe); + nxt6000_dump_status(state); return 0; - } - case FE_READ_BER: +static int nxt6000_init(struct dvb_frontend* fe) { - u32 *ber = (u32 *)arg; - - *ber=0; + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; - return 0; - - } + nxt6000_reset(state); + nxt6000_setup(fe); - case FE_READ_SIGNAL_STRENGTH: - { - s16 *signal = (s16 *) arg; -/* - *signal=(((signed char)readreg(client, 0x16))+128)<<8; -*/ - *signal = 0; return 0; - - } - - case FE_READ_SNR: - { - s16 *snr = (s16 *) arg; -/* - *snr=readreg(client, 0x24)<<8; - *snr|=readreg(client, 0x25); -*/ - *snr = 0; - break; - } - - case FE_READ_UNCORRECTED_BLOCKS: - { - u32 *ublocks = (u32 *)arg; - - *ublocks = 0; - - break; } - case FE_INIT: - nxt6000_reset(fe); - nxt6000_setup(fe); - break; - case FE_SET_FRONTEND: +static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { - struct dvb_frontend_parameters *param = (struct dvb_frontend_parameters *)arg; + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; int result; - switch (fe->tuner_type) { - - case TUNER_TYPE_ALP510: - if ((result = alp510_set_tv_freq(fe, param->frequency)) < 0) - return result; - break; - - case TUNER_TYPE_SP5659: - - if ((result = sp5659_set_tv_freq(fe, param->frequency)) < 0) - return result; - - break; - - case TUNER_TYPE_SP5730: + nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ + state->config->pll_set(fe, param); + nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ - if ((result = sp5730_set_tv_freq(fe, param->frequency)) < 0) + if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0) return result; - - break; - - default: - - return -EFAULT; - - } - - if ((result = nxt6000_set_bandwidth(fe, param->u.ofdm.bandwidth)) < 0) - return result; - if ((result = nxt6000_set_guard_interval(fe, param->u.ofdm.guard_interval)) < 0) + if ((result = nxt6000_set_guard_interval(state, param->u.ofdm.guard_interval)) < 0) return result; - if ((result = nxt6000_set_transmission_mode(fe, param->u.ofdm.transmission_mode)) < 0) + if ((result = nxt6000_set_transmission_mode(state, param->u.ofdm.transmission_mode)) < 0) return result; - if ((result = nxt6000_set_inversion(fe, param->inversion)) < 0) + if ((result = nxt6000_set_inversion(state, param->inversion)) < 0) return result; - - break; - } - - default: - - return -EOPNOTSUPP; - - } return 0; - } -static u8 demod_addr_tbl[] = {0x14, 0x18, 0x24, 0x28}; - -static struct i2c_client client_template; -static int attach_adapter(struct i2c_adapter *adapter) +static void nxt6000_release(struct dvb_frontend* fe) { - struct i2c_client *client; - struct nxt6000_config *nxt; - u8 addr_nr; - int ret; - - if ((nxt = kmalloc(sizeof(struct nxt6000_config), GFP_KERNEL)) == NULL) - return -ENOMEM; - - memset(nxt, 0, sizeof(*nxt)); - nxt->i2c = adapter; - - for (addr_nr = 0; addr_nr < sizeof(demod_addr_tbl); addr_nr++) { - - if (nxt6000_read(adapter, demod_addr_tbl[addr_nr], OFDM_MSC_REV) != NXT6000ASICDEVICE) - continue; - - if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC0) == 0) { - nxt->tuner_addr = 0xC0; - nxt->tuner_type = TUNER_TYPE_ALP510; - nxt->clock_inversion = 1; - - dprintk("nxt6000: detected TI ALP510 tuner at 0x%02X\n", nxt->tuner_addr); - - } else if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC2) == 0) { - nxt->tuner_addr = 0xC2; - nxt->tuner_type = TUNER_TYPE_SP5659; - nxt->clock_inversion = 0; - - dprintk("nxt6000: detected MITEL SP5659 tuner at 0x%02X\n", nxt->tuner_addr); - - } else if (pll_test(adapter, demod_addr_tbl[addr_nr], 0xC0) == 0) { - nxt->tuner_addr = 0xC0; - nxt->tuner_type = TUNER_TYPE_SP5730; - nxt->clock_inversion = 0; - - dprintk("nxt6000: detected SP5730 tuner at 0x%02X\n", nxt->tuner_addr); - - } else { - printk("nxt6000: unable to detect tuner\n"); - continue; - } + struct nxt6000_state* state = (struct nxt6000_state*) fe->demodulator_priv; + kfree(state); } - if (addr_nr == sizeof(demod_addr_tbl)) { - kfree(nxt); - return -ENODEV; - } +static struct dvb_frontend_ops nxt6000_ops; - nxt->demod_addr = demod_addr_tbl[addr_nr]; - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(nxt); - return -ENOMEM; -} - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = demod_addr_tbl[addr_nr]; - i2c_set_clientdata(client, (void *) nxt); - - ret = i2c_attach_client(client); - if (ret) - goto out; - - BUG_ON(!nxt->dvb); - - ret = dvb_register_frontend(nxt6000_ioctl, nxt->dvb, nxt, &nxt6000_info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - goto out; - } - - ret = 0; -out: - kfree(client); - kfree(nxt); - return ret; -} - -static int detach_client(struct i2c_client *client) +struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, + struct i2c_adapter* i2c) { - struct nxt6000_config *state = (struct nxt6000_config *) i2c_get_clientdata(client); - dvb_unregister_frontend(nxt6000_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} + struct nxt6000_state* state = NULL; -static int command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct nxt6000_config *state = (struct nxt6000_config *) i2c_get_clientdata(client); + /* allocate memory for the internal state */ + state = (struct nxt6000_state*) kmalloc(sizeof(struct nxt6000_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops)); + + /* check if the demod is there */ + if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; + } + +static struct dvb_frontend_ops nxt6000_ops = { + + .info = { + .name = "NxtWave NXT6000 DVB-T", + .type = FE_OFDM, + .frequency_min = 0, + .frequency_max = 863250000, + .frequency_stepsize = 62500, + /*.frequency_tolerance = *//* FIXME: 12% of SR */ + .symbol_rate_min = 0, /* FIXME */ + .symbol_rate_max = 9360000, /* FIXME */ + .symbol_rate_tolerance = 4000, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, - switch (cmd) { - case FE_REGISTER:{ - state->dvb = (struct dvb_adapter *) arg; - break; - } - case FE_UNREGISTER:{ - state->dvb = NULL; - break; - } - default: - return -EOPNOTSUPP; - } - return 0; -} + .release = nxt6000_release, + + .init = nxt6000_init, -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "nxt6000", - .id = I2C_DRIVERID_DVBFE_NXT6000, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; + .set_frontend = nxt6000_set_frontend, -static struct i2c_client client_template = { - I2C_DEVNAME("nxt6000"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + .read_status = nxt6000_read_status, }; -static __init int nxt6000_init(void) -{ - return i2c_add_driver(&driver); -} +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -static __exit void nxt6000_exit(void) -{ - if (i2c_del_driver(&driver)) - printk("nxt6000: driver deregistration failed\n"); -} +MODULE_DESCRIPTION("NxtWave NXT6000 DVB-T demodulator driver"); +MODULE_AUTHOR("Florian Schirmer"); +MODULE_LICENSE("GPL"); -module_init(nxt6000_init); -module_exit(nxt6000_exit); +EXPORT_SYMBOL(nxt6000_attach); diff -Nru a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h --- a/drivers/media/dvb/frontends/nxt6000.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/nxt6000.h 2004-12-12 17:40:52 -08:00 @@ -1,266 +1,43 @@ /* - * Public Include File for DRV6000 users - * (ie. NxtWave Communications - NXT6000 demodulator driver) - * - * Copyright (C) 2001 NxtWave Communications, Inc. - * - */ - -/* Nxt6000 Register Addresses and Bit Masks */ - -/* Maximum Register Number */ -#define MAXNXT6000REG (0x9A) - -/* 0x1B A_VIT_BER_0 aka 0x3A */ -#define A_VIT_BER_0 (0x1B) - -/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */ -#define A_VIT_BER_TIMER_0 (0x1D) - -/* 0x21 RS_COR_STAT */ -#define RS_COR_STAT (0x21) -#define RSCORESTATUS (0x03) - -/* 0x22 RS_COR_INTEN */ -#define RS_COR_INTEN (0x22) - -/* 0x23 RS_COR_INSTAT */ -#define RS_COR_INSTAT (0x23) -#define INSTAT_ERROR (0x04) -#define LOCK_LOSS_BITS (0x03) - -/* 0x24 RS_COR_SYNC_PARAM */ -#define RS_COR_SYNC_PARAM (0x24) -#define SYNC_PARAM (0x03) - -/* 0x25 BER_CTRL */ -#define BER_CTRL (0x25) -#define BER_ENABLE (0x02) -#define BER_RESET (0x01) - -/* 0x26 BER_PAY */ -#define BER_PAY (0x26) - -/* 0x27 BER_PKT_L */ -#define BER_PKT_L (0x27) -#define BER_PKTOVERFLOW (0x80) - -/* 0x30 VIT_COR_CTL */ -#define VIT_COR_CTL (0x30) -#define BER_CONTROL (0x02) -#define VIT_COR_MASK (0x82) -#define VIT_COR_RESYNC (0x80) - - -/* 0x32 VIT_SYNC_STATUS */ -#define VIT_SYNC_STATUS (0x32) -#define VITINSYNC (0x80) - -/* 0x33 VIT_COR_INTEN */ -#define VIT_COR_INTEN (0x33) -#define GLOBAL_ENABLE (0x80) - -/* 0x34 VIT_COR_INTSTAT */ -#define VIT_COR_INTSTAT (0x34) -#define BER_DONE (0x08) -#define BER_OVERFLOW (0x10) - -/* 0x38 OFDM_BERTimer */ /* Use the alias registers */ -#define A_VIT_BER_TIMER_0 (0x1D) - -/* 0x3A VIT_BER_TIMER_0 */ /* Use the alias registers */ -#define A_VIT_BER_0 (0x1B) - -/* 0x40 OFDM_COR_CTL */ -#define OFDM_COR_CTL (0x40) -#define COREACT (0x20) -#define HOLDSM (0x10) -#define WAIT_AGC (0x02) -#define WAIT_SYR (0x03) - -/* 0x41 OFDM_COR_STAT */ -#define OFDM_COR_STAT (0x41) -#define COR_STATUS (0x0F) -#define MONITOR_TPS (0x06) -#define TPSLOCKED (0x40) -#define AGCLOCKED (0x10) - -/* 0x42 OFDM_COR_INTEN */ -#define OFDM_COR_INTEN (0x42) -#define TPSRCVBAD (0x04) -#define TPSRCVCHANGED (0x02) -#define TPSRCVUPDATE (0x01) - -/* 0x43 OFDM_COR_INSTAT */ -#define OFDM_COR_INSTAT (0x43) - -/* 0x44 OFDM_COR_MODEGUARD */ -#define OFDM_COR_MODEGUARD (0x44) -#define FORCEMODE (0x08) -#define FORCEMODE8K (0x04) - -/* 0x45 OFDM_AGC_CTL */ -#define OFDM_AGC_CTL (0x45) -#define INITIAL_AGC_BW (0x08) -#define AGCNEG (0x02) -#define AGCLAST (0x10) - -/* 0x48 OFDM_AGC_TARGET */ -#define OFDM_AGC_TARGET (0x48) -#define OFDM_AGC_TARGET_DEFAULT (0x28) -#define OFDM_AGC_TARGET_IMPULSE (0x38) - -/* 0x49 OFDM_AGC_GAIN_1 */ -#define OFDM_AGC_GAIN_1 (0x49) - -/* 0x4B OFDM_ITB_CTL */ -#define OFDM_ITB_CTL (0x4B) -#define ITBINV (0x01) - -/* 0x4C OFDM_ITB_FREQ_1 */ -#define OFDM_ITB_FREQ_1 (0x4C) - -/* 0x4D OFDM_ITB_FREQ_2 */ -#define OFDM_ITB_FREQ_2 (0x4D) - -/* 0x4E OFDM_CAS_CTL */ -#define OFDM_CAS_CTL (0x4E) -#define ACSDIS (0x40) -#define CCSEN (0x80) - -/* 0x4F CAS_FREQ */ -#define CAS_FREQ (0x4F) - -/* 0x51 OFDM_SYR_CTL */ -#define OFDM_SYR_CTL (0x51) -#define SIXTH_ENABLE (0x80) -#define SYR_TRACKING_DISABLE (0x01) - -/* 0x52 OFDM_SYR_STAT */ -#define OFDM_SYR_STAT (0x52) -#define GI14_2K_SYR_LOCK (0x13) -#define GI14_8K_SYR_LOCK (0x17) -#define GI14_SYR_LOCK (0x10) - -/* 0x55 OFDM_SYR_OFFSET_1 */ -#define OFDM_SYR_OFFSET_1 (0x55) - -/* 0x56 OFDM_SYR_OFFSET_2 */ -#define OFDM_SYR_OFFSET_2 (0x56) - -/* 0x58 OFDM_SCR_CTL */ -#define OFDM_SCR_CTL (0x58) -#define SYR_ADJ_DECAY_MASK (0x70) -#define SYR_ADJ_DECAY (0x30) - -/* 0x59 OFDM_PPM_CTL_1 */ -#define OFDM_PPM_CTL_1 (0x59) -#define PPMMAX_MASK (0x30) -#define PPM256 (0x30) - -/* 0x5B OFDM_TRL_NOMINALRATE_1 */ -#define OFDM_TRL_NOMINALRATE_1 (0x5B) - -/* 0x5C OFDM_TRL_NOMINALRATE_2 */ -#define OFDM_TRL_NOMINALRATE_2 (0x5C) - -/* 0x5D OFDM_TRL_TIME_1 */ -#define OFDM_TRL_TIME_1 (0x5D) - -/* 0x60 OFDM_CRL_FREQ_1 */ -#define OFDM_CRL_FREQ_1 (0x60) - -/* 0x63 OFDM_CHC_CTL_1 */ -#define OFDM_CHC_CTL_1 (0x63) -#define MANMEAN1 (0xF0); -#define CHCFIR (0x01) - -/* 0x64 OFDM_CHC_SNR */ -#define OFDM_CHC_SNR (0x64) - -/* 0x65 OFDM_BDI_CTL */ -#define OFDM_BDI_CTL (0x65) -#define LP_SELECT (0x02) - -/* 0x67 OFDM_TPS_RCVD_1 */ -#define OFDM_TPS_RCVD_1 (0x67) -#define TPSFRAME (0x03) - -/* 0x68 OFDM_TPS_RCVD_2 */ -#define OFDM_TPS_RCVD_2 (0x68) - -/* 0x69 OFDM_TPS_RCVD_3 */ -#define OFDM_TPS_RCVD_3 (0x69) - -/* 0x6A OFDM_TPS_RCVD_4 */ -#define OFDM_TPS_RCVD_4 (0x6A) - -/* 0x6B OFDM_TPS_RESERVED_1 */ -#define OFDM_TPS_RESERVED_1 (0x6B) - -/* 0x6C OFDM_TPS_RESERVED_2 */ -#define OFDM_TPS_RESERVED_2 (0x6C) - -/* 0x73 OFDM_MSC_REV */ -#define OFDM_MSC_REV (0x73) - -/* 0x76 OFDM_SNR_CARRIER_2 */ -#define OFDM_SNR_CARRIER_2 (0x76) -#define MEAN_MASK (0x80) -#define MEANBIT (0x80) - -/* 0x80 ANALOG_CONTROL_0 */ -#define ANALOG_CONTROL_0 (0x80) -#define POWER_DOWN_ADC (0x40) - -/* 0x81 ENABLE_TUNER_IIC */ -#define ENABLE_TUNER_IIC (0x81) -#define ENABLE_TUNER_BIT (0x01) - -/* 0x82 EN_DMD_RACQ */ -#define EN_DMD_RACQ (0x82) -#define EN_DMD_RACQ_REG_VAL (0x81) -#define EN_DMD_RACQ_REG_VAL_14 (0x01) - -/* 0x84 SNR_COMMAND */ -#define SNR_COMMAND (0x84) -#define SNRStat (0x80) - -/* 0x85 SNRCARRIERNUMBER_LSB */ -#define SNRCARRIERNUMBER_LSB (0x85) - -/* 0x87 SNRMINTHRESHOLD_LSB */ -#define SNRMINTHRESHOLD_LSB (0x87) - -/* 0x89 SNR_PER_CARRIER_LSB */ -#define SNR_PER_CARRIER_LSB (0x89) - -/* 0x8B SNRBELOWTHRESHOLD_LSB */ -#define SNRBELOWTHRESHOLD_LSB (0x8B) - -/* 0x91 RF_AGC_VAL_1 */ -#define RF_AGC_VAL_1 (0x91) - -/* 0x92 RF_AGC_STATUS */ -#define RF_AGC_STATUS (0x92) - -/* 0x98 DIAG_CONFIG */ -#define DIAG_CONFIG (0x98) -#define DIAG_MASK (0x70) -#define TB_SET (0x10) -#define TRAN_SELECT (0x07) -#define SERIAL_SELECT (0x01) - -/* 0x99 SUB_DIAG_MODE_SEL */ -#define SUB_DIAG_MODE_SEL (0x99) -#define CLKINVERSION (0x01) - -/* 0x9A TS_FORMAT */ -#define TS_FORMAT (0x9A) -#define ERROR_SENSE (0x08) -#define VALID_SENSE (0x04) -#define SYNC_SENSE (0x02) -#define GATED_CLOCK (0x01) + NxtWave Communications - NXT6000 demodulator driver -#define NXT6000ASICDEVICE (0x0b) + Copyright (C) 2002-2003 Florian Schirmer + Copyright (C) 2003 Paul Andreassen + 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 NXT6000_H +#define NXT6000_H + +#include + +struct nxt6000_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* should clock inversion be used? */ + u8 clock_inversion:1; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, + struct i2c_adapter* i2c); + +#endif // NXT6000_H diff -Nru a/drivers/media/dvb/frontends/nxt6000_priv.h b/drivers/media/dvb/frontends/nxt6000_priv.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/nxt6000_priv.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,265 @@ +/* + * Public Include File for DRV6000 users + * (ie. NxtWave Communications - NXT6000 demodulator driver) + * + * Copyright (C) 2001 NxtWave Communications, Inc. + * + */ + +/* Nxt6000 Register Addresses and Bit Masks */ + +/* Maximum Register Number */ +#define MAXNXT6000REG (0x9A) + +/* 0x1B A_VIT_BER_0 aka 0x3A */ +#define A_VIT_BER_0 (0x1B) + +/* 0x1D A_VIT_BER_TIMER_0 aka 0x38 */ +#define A_VIT_BER_TIMER_0 (0x1D) + +/* 0x21 RS_COR_STAT */ +#define RS_COR_STAT (0x21) +#define RSCORESTATUS (0x03) + +/* 0x22 RS_COR_INTEN */ +#define RS_COR_INTEN (0x22) + +/* 0x23 RS_COR_INSTAT */ +#define RS_COR_INSTAT (0x23) +#define INSTAT_ERROR (0x04) +#define LOCK_LOSS_BITS (0x03) + +/* 0x24 RS_COR_SYNC_PARAM */ +#define RS_COR_SYNC_PARAM (0x24) +#define SYNC_PARAM (0x03) + +/* 0x25 BER_CTRL */ +#define BER_CTRL (0x25) +#define BER_ENABLE (0x02) +#define BER_RESET (0x01) + +/* 0x26 BER_PAY */ +#define BER_PAY (0x26) + +/* 0x27 BER_PKT_L */ +#define BER_PKT_L (0x27) +#define BER_PKTOVERFLOW (0x80) + +/* 0x30 VIT_COR_CTL */ +#define VIT_COR_CTL (0x30) +#define BER_CONTROL (0x02) +#define VIT_COR_MASK (0x82) +#define VIT_COR_RESYNC (0x80) + + +/* 0x32 VIT_SYNC_STATUS */ +#define VIT_SYNC_STATUS (0x32) +#define VITINSYNC (0x80) + +/* 0x33 VIT_COR_INTEN */ +#define VIT_COR_INTEN (0x33) +#define GLOBAL_ENABLE (0x80) + +/* 0x34 VIT_COR_INTSTAT */ +#define VIT_COR_INTSTAT (0x34) +#define BER_DONE (0x08) +#define BER_OVERFLOW (0x10) + + /* 0x38 OFDM_BERTimer *//* Use the alias registers */ +#define A_VIT_BER_TIMER_0 (0x1D) + + /* 0x3A VIT_BER_TIMER_0 *//* Use the alias registers */ +#define A_VIT_BER_0 (0x1B) + +/* 0x40 OFDM_COR_CTL */ +#define OFDM_COR_CTL (0x40) +#define COREACT (0x20) +#define HOLDSM (0x10) +#define WAIT_AGC (0x02) +#define WAIT_SYR (0x03) + +/* 0x41 OFDM_COR_STAT */ +#define OFDM_COR_STAT (0x41) +#define COR_STATUS (0x0F) +#define MONITOR_TPS (0x06) +#define TPSLOCKED (0x40) +#define AGCLOCKED (0x10) + +/* 0x42 OFDM_COR_INTEN */ +#define OFDM_COR_INTEN (0x42) +#define TPSRCVBAD (0x04) +#define TPSRCVCHANGED (0x02) +#define TPSRCVUPDATE (0x01) + +/* 0x43 OFDM_COR_INSTAT */ +#define OFDM_COR_INSTAT (0x43) + +/* 0x44 OFDM_COR_MODEGUARD */ +#define OFDM_COR_MODEGUARD (0x44) +#define FORCEMODE (0x08) +#define FORCEMODE8K (0x04) + +/* 0x45 OFDM_AGC_CTL */ +#define OFDM_AGC_CTL (0x45) +#define INITIAL_AGC_BW (0x08) +#define AGCNEG (0x02) +#define AGCLAST (0x10) + +/* 0x48 OFDM_AGC_TARGET */ +#define OFDM_AGC_TARGET (0x48) +#define OFDM_AGC_TARGET_DEFAULT (0x28) +#define OFDM_AGC_TARGET_IMPULSE (0x38) + +/* 0x49 OFDM_AGC_GAIN_1 */ +#define OFDM_AGC_GAIN_1 (0x49) + +/* 0x4B OFDM_ITB_CTL */ +#define OFDM_ITB_CTL (0x4B) +#define ITBINV (0x01) + +/* 0x4C OFDM_ITB_FREQ_1 */ +#define OFDM_ITB_FREQ_1 (0x4C) + +/* 0x4D OFDM_ITB_FREQ_2 */ +#define OFDM_ITB_FREQ_2 (0x4D) + +/* 0x4E OFDM_CAS_CTL */ +#define OFDM_CAS_CTL (0x4E) +#define ACSDIS (0x40) +#define CCSEN (0x80) + +/* 0x4F CAS_FREQ */ +#define CAS_FREQ (0x4F) + +/* 0x51 OFDM_SYR_CTL */ +#define OFDM_SYR_CTL (0x51) +#define SIXTH_ENABLE (0x80) +#define SYR_TRACKING_DISABLE (0x01) + +/* 0x52 OFDM_SYR_STAT */ +#define OFDM_SYR_STAT (0x52) +#define GI14_2K_SYR_LOCK (0x13) +#define GI14_8K_SYR_LOCK (0x17) +#define GI14_SYR_LOCK (0x10) + +/* 0x55 OFDM_SYR_OFFSET_1 */ +#define OFDM_SYR_OFFSET_1 (0x55) + +/* 0x56 OFDM_SYR_OFFSET_2 */ +#define OFDM_SYR_OFFSET_2 (0x56) + +/* 0x58 OFDM_SCR_CTL */ +#define OFDM_SCR_CTL (0x58) +#define SYR_ADJ_DECAY_MASK (0x70) +#define SYR_ADJ_DECAY (0x30) + +/* 0x59 OFDM_PPM_CTL_1 */ +#define OFDM_PPM_CTL_1 (0x59) +#define PPMMAX_MASK (0x30) +#define PPM256 (0x30) + +/* 0x5B OFDM_TRL_NOMINALRATE_1 */ +#define OFDM_TRL_NOMINALRATE_1 (0x5B) + +/* 0x5C OFDM_TRL_NOMINALRATE_2 */ +#define OFDM_TRL_NOMINALRATE_2 (0x5C) + +/* 0x5D OFDM_TRL_TIME_1 */ +#define OFDM_TRL_TIME_1 (0x5D) + +/* 0x60 OFDM_CRL_FREQ_1 */ +#define OFDM_CRL_FREQ_1 (0x60) + +/* 0x63 OFDM_CHC_CTL_1 */ +#define OFDM_CHC_CTL_1 (0x63) +#define MANMEAN1 (0xF0); +#define CHCFIR (0x01) + +/* 0x64 OFDM_CHC_SNR */ +#define OFDM_CHC_SNR (0x64) + +/* 0x65 OFDM_BDI_CTL */ +#define OFDM_BDI_CTL (0x65) +#define LP_SELECT (0x02) + +/* 0x67 OFDM_TPS_RCVD_1 */ +#define OFDM_TPS_RCVD_1 (0x67) +#define TPSFRAME (0x03) + +/* 0x68 OFDM_TPS_RCVD_2 */ +#define OFDM_TPS_RCVD_2 (0x68) + +/* 0x69 OFDM_TPS_RCVD_3 */ +#define OFDM_TPS_RCVD_3 (0x69) + +/* 0x6A OFDM_TPS_RCVD_4 */ +#define OFDM_TPS_RCVD_4 (0x6A) + +/* 0x6B OFDM_TPS_RESERVED_1 */ +#define OFDM_TPS_RESERVED_1 (0x6B) + +/* 0x6C OFDM_TPS_RESERVED_2 */ +#define OFDM_TPS_RESERVED_2 (0x6C) + +/* 0x73 OFDM_MSC_REV */ +#define OFDM_MSC_REV (0x73) + +/* 0x76 OFDM_SNR_CARRIER_2 */ +#define OFDM_SNR_CARRIER_2 (0x76) +#define MEAN_MASK (0x80) +#define MEANBIT (0x80) + +/* 0x80 ANALOG_CONTROL_0 */ +#define ANALOG_CONTROL_0 (0x80) +#define POWER_DOWN_ADC (0x40) + +/* 0x81 ENABLE_TUNER_IIC */ +#define ENABLE_TUNER_IIC (0x81) +#define ENABLE_TUNER_BIT (0x01) + +/* 0x82 EN_DMD_RACQ */ +#define EN_DMD_RACQ (0x82) +#define EN_DMD_RACQ_REG_VAL (0x81) +#define EN_DMD_RACQ_REG_VAL_14 (0x01) + +/* 0x84 SNR_COMMAND */ +#define SNR_COMMAND (0x84) +#define SNRStat (0x80) + +/* 0x85 SNRCARRIERNUMBER_LSB */ +#define SNRCARRIERNUMBER_LSB (0x85) + +/* 0x87 SNRMINTHRESHOLD_LSB */ +#define SNRMINTHRESHOLD_LSB (0x87) + +/* 0x89 SNR_PER_CARRIER_LSB */ +#define SNR_PER_CARRIER_LSB (0x89) + +/* 0x8B SNRBELOWTHRESHOLD_LSB */ +#define SNRBELOWTHRESHOLD_LSB (0x8B) + +/* 0x91 RF_AGC_VAL_1 */ +#define RF_AGC_VAL_1 (0x91) + +/* 0x92 RF_AGC_STATUS */ +#define RF_AGC_STATUS (0x92) + +/* 0x98 DIAG_CONFIG */ +#define DIAG_CONFIG (0x98) +#define DIAG_MASK (0x70) +#define TB_SET (0x10) +#define TRAN_SELECT (0x07) +#define SERIAL_SELECT (0x01) + +/* 0x99 SUB_DIAG_MODE_SEL */ +#define SUB_DIAG_MODE_SEL (0x99) +#define CLKINVERSION (0x01) + +/* 0x9A TS_FORMAT */ +#define TS_FORMAT (0x9A) +#define ERROR_SENSE (0x08) +#define VALID_SENSE (0x04) +#define SYNC_SENSE (0x02) +#define GATED_CLOCK (0x01) + +#define NXT6000ASICDEVICE (0x0b) diff -Nru a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/sp8870.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,613 @@ +/* + Driver for Spase SP8870 demodulator + + Copyright (C) 1999 Juergen Peitz + + 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. + +*/ +/* + * This driver needs external firmware. Please use the command + * "/Documentation/dvb/get_dvb_firmware alps_tdlb7" to + * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + */ +#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw" + +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "sp8870.h" + + +struct sp8870_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + const struct sp8870_config* config; + + struct dvb_frontend frontend; + + /* demodulator private data */ + u8 initialised:1; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "sp8870: " args); \ + } while (0) + +/* firmware size for sp8870 */ +#define SP8870_FIRMWARE_SIZE 16382 + +/* starting point for firmware in file 'Sc_main.mc' */ +#define SP8870_FIRMWARE_OFFSET 0x0A + +static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data) +{ + u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 }; + int err; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + +static int sp8870_readreg (struct sp8870_state* state, u16 reg) +{ + int ret; + u8 b0 [] = { reg >> 8 , reg & 0xff }; + u8 b1 [] = { 0, 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } }; + + ret = i2c_transfer (state->i2c, msg, 2); + + if (ret != 2) { + dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + return -1; + } + + return (b1[0] << 8 | b1[1]); +} + +static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw) +{ + struct i2c_msg msg; + char *fw_buf = fw->data; + int fw_pos; + u8 tx_buf[255]; + int tx_len; + int err = 0; + + dprintk ("%s: ...\n", __FUNCTION__); + + if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET) + return -EINVAL; + + // system controller stop + sp8870_writereg(state, 0x0F00, 0x0000); + + // instruction RAM register hiword + sp8870_writereg(state, 0x8F08, ((SP8870_FIRMWARE_SIZE / 2) & 0xFFFF)); + + // instruction RAM MWR + sp8870_writereg(state, 0x8F0A, ((SP8870_FIRMWARE_SIZE / 2) >> 16)); + + // do firmware upload + fw_pos = SP8870_FIRMWARE_OFFSET; + while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){ + tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos; + // write register 0xCF0A + tx_buf[0] = 0xCF; + tx_buf[1] = 0x0A; + memcpy(&tx_buf[2], fw_buf + fw_pos, tx_len); + msg.addr = state->config->demod_address; + msg.flags = 0; + msg.buf = tx_buf; + msg.len = tx_len + 2; + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk("%s: firmware upload failed!\n", __FUNCTION__); + printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err); + return err; + } + fw_pos += tx_len; + } + + dprintk ("%s: done!\n", __FUNCTION__); + return 0; +}; + +static void sp8870_microcontroller_stop (struct sp8870_state* state) +{ + sp8870_writereg(state, 0x0F08, 0x000); + sp8870_writereg(state, 0x0F09, 0x000); + + // microcontroller STOP + sp8870_writereg(state, 0x0F00, 0x000); +} + +static void sp8870_microcontroller_start (struct sp8870_state* state) +{ + sp8870_writereg(state, 0x0F08, 0x000); + sp8870_writereg(state, 0x0F09, 0x000); + + // microcontroller START + sp8870_writereg(state, 0x0F00, 0x001); + // not documented but if we don't read 0x0D01 out here + // we don't get a correct data valid signal + sp8870_readreg(state, 0x0D01); +} + +static int sp8870_read_data_valid_signal(struct sp8870_state* state) +{ + return (sp8870_readreg(state, 0x0D02) > 0); +} + +static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) +{ + int known_parameters = 1; + + *reg0xc05 = 0x000; + + switch (p->u.ofdm.constellation) { + case QPSK: + break; + case QAM_16: + *reg0xc05 |= (1 << 10); + break; + case QAM_64: + *reg0xc05 |= (2 << 10); + break; + case QAM_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->u.ofdm.hierarchy_information) { + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + *reg0xc05 |= (1 << 7); + break; + case HIERARCHY_2: + *reg0xc05 |= (2 << 7); + break; + case HIERARCHY_4: + *reg0xc05 |= (3 << 7); + break; + case HIERARCHY_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + switch (p->u.ofdm.code_rate_HP) { + case FEC_1_2: + break; + case FEC_2_3: + *reg0xc05 |= (1 << 3); + break; + case FEC_3_4: + *reg0xc05 |= (2 << 3); + break; + case FEC_5_6: + *reg0xc05 |= (3 << 3); + break; + case FEC_7_8: + *reg0xc05 |= (4 << 3); + break; + case FEC_AUTO: + known_parameters = 0; + break; + default: + return -EINVAL; + }; + + if (known_parameters) + *reg0xc05 |= (2 << 1); /* use specified parameters */ + else + *reg0xc05 |= (1 << 1); /* enable autoprobing */ + + return 0; +} + +static int sp8870_wake_up(struct sp8870_state* state) +{ + // enable TS output and interface pins + return sp8870_writereg(state, 0xC18, 0x00D); +} + +static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + int err; + u16 reg0xc05; + + if ((err = configure_reg0xc05(p, ®0xc05))) + return err; + + // system controller stop + sp8870_microcontroller_stop(state); + + // set tuner parameters + sp8870_writereg(state, 0x206, 0x001); + state->config->pll_set(fe, p); + sp8870_writereg(state, 0x206, 0x000); + + // sample rate correction bit [23..17] + sp8870_writereg(state, 0x0319, 0x000A); + + // sample rate correction bit [16..0] + sp8870_writereg(state, 0x031A, 0x0AAB); + + // integer carrier offset + sp8870_writereg(state, 0x0309, 0x0400); + + // fractional carrier offset + sp8870_writereg(state, 0x030A, 0x0000); + + // filter for 6/7/8 Mhz channel + if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) + sp8870_writereg(state, 0x0311, 0x0002); + else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + sp8870_writereg(state, 0x0311, 0x0001); + else + sp8870_writereg(state, 0x0311, 0x0000); + + // scan order: 2k first = 0x0000, 8k first = 0x0001 + if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) + sp8870_writereg(state, 0x0338, 0x0000); + else + sp8870_writereg(state, 0x0338, 0x0001); + + sp8870_writereg(state, 0xc05, reg0xc05); + + // read status reg in order to clear pending irqs + sp8870_readreg(state, 0x200); + + // system controller start + sp8870_microcontroller_start(state); + + return 0; +} + +static int sp8870_init (struct dvb_frontend* fe) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + const struct firmware *fw = NULL; + + sp8870_wake_up(state); + if (state->initialised) return 0; + state->initialised = 1; + + dprintk ("%s\n", __FUNCTION__); + + + /* request the firmware, this will block until someone uploads it */ + printk("sp8870: waiting for firmware upload...\n"); + if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) { + printk("sp8870: no firmware upload (timeout or file not found?)\n"); + release_firmware(fw); + return -EIO; + } + + if (sp8870_firmware_upload(state, fw)) { + printk("sp8870: writing firmware to device failed\n"); + release_firmware(fw); + return -EIO; + } + + /* enable TS output and interface pins */ + sp8870_writereg(state, 0xc18, 0x00d); + + // system controller stop + sp8870_microcontroller_stop(state); + + // ADC mode + sp8870_writereg(state, 0x0301, 0x0003); + + // Reed Solomon parity bytes passed to output + sp8870_writereg(state, 0x0C13, 0x0001); + + // MPEG clock is suppressed if no valid data + sp8870_writereg(state, 0x0C14, 0x0001); + + /* bit 0x010: enable data valid signal */ + sp8870_writereg(state, 0x0D00, 0x010); + sp8870_writereg(state, 0x0D01, 0x000); + + /* setup PLL */ + if (state->config->pll_init) { + sp8870_writereg(state, 0x206, 0x001); + state->config->pll_init(fe); + sp8870_writereg(state, 0x206, 0x000); + } + + return 0; +} + +static int sp8870_read_status (struct dvb_frontend* fe, fe_status_t * fe_status) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + int status; + int signal; + + *fe_status = 0; + + status = sp8870_readreg (state, 0x0200); + if (status < 0) + return -EIO; + + signal = sp8870_readreg (state, 0x0303); + if (signal < 0) + return -EIO; + + if (signal > 0x0F) + *fe_status |= FE_HAS_SIGNAL; + if (status & 0x08) + *fe_status |= FE_HAS_SYNC; + if (status & 0x04) + *fe_status |= FE_HAS_LOCK | FE_HAS_CARRIER | FE_HAS_VITERBI; + + return 0; +} + +static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + int ret; + u32 tmp; + + *ber = 0; + + ret = sp8870_readreg(state, 0xC08); + if (ret < 0) + return -EIO; + + tmp = ret & 0x3F; + + ret = sp8870_readreg(state, 0xC07); + if (ret < 0) + return -EIO; + + tmp = ret << 6; + + if (tmp >= 0x3FFF0) + tmp = ~0; + + *ber = tmp; + + return 0; +} + +static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + int ret; + u16 tmp; + + *signal = 0; + + ret = sp8870_readreg (state, 0x306); + if (ret < 0) + return -EIO; + + tmp = ret << 8; + + ret = sp8870_readreg (state, 0x303); + if (ret < 0) + return -EIO; + + tmp |= ret; + + if (tmp) + *signal = 0xFFFF - tmp; + + return 0; +} + +static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + int ret; + + *ublocks = 0; + + ret = sp8870_readreg(state, 0xC0C); + if (ret < 0) + return -EIO; + + if (ret == 0xFFFF) + ret = ~0; + + *ublocks = ret; + + return 0; +} + +// number of trials to recover from lockup +#define MAXTRIALS 5 +// maximum checks for data valid signal +#define MAXCHECKS 100 + +// only for debugging: counter for detected lockups +static int lockups = 0; +// only for debugging: counter for channel switches +static int switches = 0; + +static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + + /* + The firmware of the sp8870 sometimes locks up after setting frontend parameters. + We try to detect this by checking the data valid signal. + If it is not set after MAXCHECKS we try to recover the lockup by setting + the frontend parameters again. + */ + + int err = 0; + int valid = 0; + int trials = 0; + int check_count = 0; + + dprintk("%s: frequency = %i\n", __FUNCTION__, p->frequency); + + for (trials = 1; trials <= MAXTRIALS; trials++) { + + if ((err = sp8870_set_frontend_parameters(fe, p))) + return err; + + for (check_count = 0; check_count < MAXCHECKS; check_count++) { +// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0); + valid = sp8870_read_data_valid_signal(state); + if (valid) { + dprintk("%s: delay = %i usec\n", + __FUNCTION__, check_count * 10); + break; + } + udelay(10); + } + if (valid) + break; + } + + if (!valid) { + printk("%s: firmware crash!!!!!!\n", __FUNCTION__); + return -EIO; + } + + if (debug) { + if (valid) { + if (trials > 1) { + printk("%s: firmware lockup!!!\n", __FUNCTION__); + printk("%s: recovered after %i trial(s))\n", __FUNCTION__, trials - 1); + lockups++; + } + } + switches++; + printk("%s: switches = %i lockups = %i\n", __FUNCTION__, switches, lockups); + } + + return 0; +} + +static int sp8870_sleep(struct dvb_frontend* fe) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + + // tristate TS output and disable interface pins + return sp8870_writereg(state, 0xC18, 0x000); +} + +static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 350; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void sp8870_release(struct dvb_frontend* fe) +{ + struct sp8870_state* state = (struct sp8870_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops sp8870_ops; + +struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c) +{ + struct sp8870_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct sp8870_state*) kmalloc(sizeof(struct sp8870_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + + /* check if the demod is there */ + if (sp8870_readreg(state, 0x0200) < 0) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops sp8870_ops = { + + .info = { + .name = "Spase SP8870 DVB-T", + .type = FE_OFDM, + .frequency_min = 470000000, + .frequency_max = 860000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER + }, + + .release = sp8870_release, + + .init = sp8870_init, + .sleep = sp8870_sleep, + + .set_frontend = sp8870_set_frontend, + .get_tune_settings = sp8870_get_tune_settings, + + .read_status = sp8870_read_status, + .read_ber = sp8870_read_ber, + .read_signal_strength = sp8870_read_signal_strength, + .read_ucblocks = sp8870_read_uncorrected_blocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver"); +MODULE_AUTHOR("Juergen Peitz"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(sp8870_attach); diff -Nru a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/sp8870.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,45 @@ +/* + Driver for Spase SP8870 demodulator + + Copyright (C) 1999 Juergen Peitz + + 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 SP8870_H +#define SP8870_H + +#include +#include + +struct sp8870_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, + struct i2c_adapter* i2c); + +#endif // SP8870_H diff -Nru a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c --- a/drivers/media/dvb/frontends/sp887x.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/frontends/sp887x.c 2004-12-12 17:40:53 -08:00 @@ -1,5 +1,5 @@ /* - Driver for the Microtune 7202D Frontend + Driver for the Spase sp887x demodulator */ /* @@ -16,74 +16,50 @@ #include #include "dvb_frontend.h" +#include "sp887x.h" -#define FRONTEND_NAME "dvbfe_sp887x" -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) +struct sp887x_state { -static int debug; + struct i2c_adapter* i2c; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + struct dvb_frontend_ops ops; -#if 0 -#define LOG(dir,addr,buf,len) \ - do { \ - int i; \ - printk("%s (%02x):", dir, addr & 0xff); \ - for (i=0; iconfig->demod_address, .flags = 0, .buf = buf, .len = len }; int err; - LOG("i2c_writebytes", msg.addr, msg.buf, msg.len); - - if ((err = i2c_transfer (i2c, &msg, 1)) != 1) { + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { printk ("%s: i2c write error (addr %02x, err == %i)\n", - __FUNCTION__, addr, err); + __FUNCTION__, state->config->demod_address, err); return -EREMOTEIO; } return 0; } -static int sp887x_writereg (struct i2c_adapter *i2c, u16 reg, u16 data) +static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data) { u8 b0 [] = { reg >> 8 , reg & 0xff, data >> 8, data & 0xff }; - struct i2c_msg msg = { .addr = 0x70, .flags = 0, .buf = b0, .len = 4 }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 4 }; int ret; - LOG("sp887x_writereg", msg.addr, msg.buf, msg.len); - - if ((ret = i2c_transfer(i2c, &msg, 1)) != 1) { + if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { /** * in case of soft reset we ignore ACK errors... */ @@ -100,61 +76,60 @@ return 0; } -static u16 sp887x_readreg (struct i2c_adapter *i2c, u16 reg) +static int sp887x_readreg (struct sp887x_state* state, u16 reg) { u8 b0 [] = { reg >> 8 , reg & 0xff }; u8 b1 [2]; int ret; - struct i2c_msg msg[] = {{ .addr = 0x70, .flags = 0, .buf = b0, .len = 2 }, - { .addr = 0x70, .flags = I2C_M_RD, .buf = b1, .len = 2 }}; - - LOG("sp887x_readreg (w)", msg[0].addr, msg[0].buf, msg[0].len); - LOG("sp887x_readreg (r)", msg[1].addr, msg[1].buf, msg[1].len); + struct i2c_msg msg[] = {{ .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }}; - if ((ret = i2c_transfer(i2c, msg, 2)) != 2) + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + return -1; + } return (((b1[0] << 8) | b1[1]) & 0xfff); } -static void sp887x_microcontroller_stop (struct i2c_adapter *fe) +static void sp887x_microcontroller_stop (struct sp887x_state* state) { dprintk("%s\n", __FUNCTION__); - sp887x_writereg(fe, 0xf08, 0x000); - sp887x_writereg(fe, 0xf09, 0x000); + sp887x_writereg(state, 0xf08, 0x000); + sp887x_writereg(state, 0xf09, 0x000); /* microcontroller STOP */ - sp887x_writereg(fe, 0xf00, 0x000); + sp887x_writereg(state, 0xf00, 0x000); } -static void sp887x_microcontroller_start (struct i2c_adapter *fe) +static void sp887x_microcontroller_start (struct sp887x_state* state) { dprintk("%s\n", __FUNCTION__); - sp887x_writereg(fe, 0xf08, 0x000); - sp887x_writereg(fe, 0xf09, 0x000); + sp887x_writereg(state, 0xf08, 0x000); + sp887x_writereg(state, 0xf09, 0x000); /* microcontroller START */ - sp887x_writereg(fe, 0xf00, 0x001); + sp887x_writereg(state, 0xf00, 0x001); } -static void sp887x_setup_agc (struct i2c_adapter *fe) +static void sp887x_setup_agc (struct sp887x_state* state) { /* setup AGC parameters */ dprintk("%s\n", __FUNCTION__); - sp887x_writereg(fe, 0x33c, 0x054); - sp887x_writereg(fe, 0x33b, 0x04c); - sp887x_writereg(fe, 0x328, 0x000); - sp887x_writereg(fe, 0x327, 0x005); - sp887x_writereg(fe, 0x326, 0x001); - sp887x_writereg(fe, 0x325, 0x001); - sp887x_writereg(fe, 0x324, 0x001); - sp887x_writereg(fe, 0x318, 0x050); - sp887x_writereg(fe, 0x317, 0x3fe); - sp887x_writereg(fe, 0x316, 0x001); - sp887x_writereg(fe, 0x313, 0x005); - sp887x_writereg(fe, 0x312, 0x002); - sp887x_writereg(fe, 0x306, 0x000); - sp887x_writereg(fe, 0x303, 0x000); + sp887x_writereg(state, 0x33c, 0x054); + sp887x_writereg(state, 0x33b, 0x04c); + sp887x_writereg(state, 0x328, 0x000); + sp887x_writereg(state, 0x327, 0x005); + sp887x_writereg(state, 0x326, 0x001); + sp887x_writereg(state, 0x325, 0x001); + sp887x_writereg(state, 0x324, 0x001); + sp887x_writereg(state, 0x318, 0x050); + sp887x_writereg(state, 0x317, 0x3fe); + sp887x_writereg(state, 0x316, 0x001); + sp887x_writereg(state, 0x313, 0x005); + sp887x_writereg(state, 0x312, 0x002); + sp887x_writereg(state, 0x306, 0x000); + sp887x_writereg(state, 0x303, 0x000); } #define BLOCKSIZE 30 @@ -162,8 +137,9 @@ /** * load firmware and setup MPEG interface... */ -static int sp887x_initial_setup (struct i2c_adapter *fe, const struct firmware *fw) +static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware *fw) { + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; u8 buf [BLOCKSIZE+2]; int i; int fw_size = fw->size; @@ -178,18 +154,18 @@ mem = fw->data + 10; /* soft reset */ - sp887x_writereg(fe, 0xf1a, 0x000); + sp887x_writereg(state, 0xf1a, 0x000); - sp887x_microcontroller_stop (fe); + sp887x_microcontroller_stop (state); printk ("%s: firmware upload... ", __FUNCTION__); /* setup write pointer to -1 (end of memory) */ /* bit 0x8000 in address is set to enable 13bit mode */ - sp887x_writereg(fe, 0x8f08, 0x1fff); + sp887x_writereg(state, 0x8f08, 0x1fff); /* dummy write (wrap around to start of memory) */ - sp887x_writereg(fe, 0x8f0a, 0x0000); + sp887x_writereg(state, 0x8f0a, 0x0000); for (i = 0; i < FW_SIZE; i += BLOCKSIZE) { int c = BLOCKSIZE; @@ -206,7 +182,7 @@ memcpy(&buf[2], mem + i, c); - if ((err = i2c_writebytes (fe, 0x70, buf, c+2)) < 0) { + if ((err = i2c_writebytes (state, buf, c+2)) < 0) { printk ("failed.\n"); printk ("%s: i2c error (err == %i)\n", __FUNCTION__, err); return err; @@ -214,61 +190,37 @@ } /* don't write RS bytes between packets */ - sp887x_writereg(fe, 0xc13, 0x001); + sp887x_writereg(state, 0xc13, 0x001); /* suppress clock if (!data_valid) */ - sp887x_writereg(fe, 0xc14, 0x000); + sp887x_writereg(state, 0xc14, 0x000); /* setup MPEG interface... */ - sp887x_writereg(fe, 0xc1a, 0x872); - sp887x_writereg(fe, 0xc1b, 0x001); - sp887x_writereg(fe, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */ - sp887x_writereg(fe, 0xc1a, 0x871); + sp887x_writereg(state, 0xc1a, 0x872); + sp887x_writereg(state, 0xc1b, 0x001); + sp887x_writereg(state, 0xc1c, 0x000); /* parallel mode (serial mode == 1) */ + sp887x_writereg(state, 0xc1a, 0x871); /* ADC mode, 2 for MT8872, 3 for SP8870/SP8871 */ - sp887x_writereg(fe, 0x301, 0x002); + sp887x_writereg(state, 0x301, 0x002); - sp887x_setup_agc(fe); + sp887x_setup_agc(state); /* bit 0x010: enable data valid signal */ - sp887x_writereg(fe, 0xd00, 0x010); - sp887x_writereg(fe, 0x0d1, 0x000); + sp887x_writereg(state, 0xd00, 0x010); + sp887x_writereg(state, 0x0d1, 0x000); + + /* setup the PLL */ + if (state->config->pll_init) { + sp887x_writereg(state, 0x206, 0x001); + state->config->pll_init(fe); + sp887x_writereg(state, 0x206, 0x000); + } printk ("done.\n"); return 0; }; -/** - * returns the actual tuned center frequency which can be used - * to initialise the AFC registers - */ -static int tsa5060_setup_pll (struct i2c_adapter *fe, int freq) -{ - u8 cfg, cpump, band_select; - u8 buf [4]; - u32 div; - - div = (36000000 + freq + 83333) / 166666; - cfg = 0x88; - - cpump = freq < 175000000 ? 2 : freq < 390000000 ? 1 : - freq < 470000000 ? 2 : freq < 750000000 ? 2 : 3; - - band_select = freq < 175000000 ? 0x0e : freq < 470000000 ? 0x05 : 0x03; - - buf [0] = (div >> 8) & 0x7f; - buf [1] = div & 0xff; - buf [2] = ((div >> 10) & 0x60) | cfg; - buf [3] = cpump | band_select; - - /* open i2c gate for PLL message transmission... */ - sp887x_writereg(fe, 0x206, 0x001); - i2c_writebytes(fe, 0x60, buf, 4); - sp887x_writereg(fe, 0x206, 0x000); - - return (div * 166666 - 36000000); -} - static int configure_reg0xc05 (struct dvb_frontend_parameters *p, u16 *reg0xc05) { int known_parameters = 1; @@ -362,7 +314,7 @@ } } -static void sp887x_correct_offsets (struct i2c_adapter *fe, +static void sp887x_correct_offsets (struct sp887x_state* state, struct dvb_frontend_parameters *p, int actual_freq) { @@ -385,17 +337,31 @@ frequency_shift = -frequency_shift; /* sample rate correction */ - sp887x_writereg(fe, 0x319, srate_correction[bw_index] >> 12); - sp887x_writereg(fe, 0x31a, srate_correction[bw_index] & 0xfff); + sp887x_writereg(state, 0x319, srate_correction[bw_index] >> 12); + sp887x_writereg(state, 0x31a, srate_correction[bw_index] & 0xfff); /* carrier offset correction */ - sp887x_writereg(fe, 0x309, frequency_shift >> 12); - sp887x_writereg(fe, 0x30a, frequency_shift & 0xfff); + sp887x_writereg(state, 0x309, frequency_shift >> 12); + sp887x_writereg(state, 0x30a, frequency_shift & 0xfff); } -static int sp887x_setup_frontend_parameters (struct i2c_adapter *fe, + + + + + + + + + + + + + +static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; int actual_freq, err; u16 val, reg0xc05; @@ -407,14 +373,17 @@ if ((err = configure_reg0xc05(p, ®0xc05))) return err; - sp887x_microcontroller_stop(fe); + sp887x_microcontroller_stop(state); - actual_freq = tsa5060_setup_pll(fe, p->frequency); + /* setup the PLL */ + sp887x_writereg(state, 0x206, 0x001); + actual_freq = state->config->pll_set(fe, p); + sp887x_writereg(state, 0x206, 0x000); - /* read status reg in order to clear pending irqs */ - sp887x_readreg(fe, 0x200); + /* read status reg in order to clear u.ofdm.bandwidth == BANDWIDTH_6_MHZ) @@ -424,15 +393,15 @@ else val = 0; - sp887x_writereg(fe, 0x311, val); + sp887x_writereg(state, 0x311, val); /* scan order: 2k first = 0, 8k first = 1 */ if (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_2K) - sp887x_writereg(fe, 0x338, 0x000); + sp887x_writereg(state, 0x338, 0x000); else - sp887x_writereg(fe, 0x338, 0x001); + sp887x_writereg(state, 0x338, 0x001); - sp887x_writereg(fe, 0xc05, reg0xc05); + sp887x_writereg(state, 0xc05, reg0xc05); if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) val = 2 << 3; @@ -444,29 +413,19 @@ /* enable OFDM and SAW bits as lock indicators in sync register 0xf17, * optimize algorithm for given bandwidth... */ - sp887x_writereg(fe, 0xf14, 0x160 | val); - sp887x_writereg(fe, 0xf15, 0x000); + sp887x_writereg(state, 0xf14, 0x160 | val); + sp887x_writereg(state, 0xf15, 0x000); - sp887x_microcontroller_start(fe); + sp887x_microcontroller_start(state); return 0; } -static int sp887x_ioctl(struct dvb_frontend *f, unsigned int cmd, void *arg) -{ - struct sp887x_state *state = (struct sp887x_state *) f->data; - struct i2c_adapter *fe = state->i2c; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &sp887x_info, sizeof(struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: +static int sp887x_read_status(struct dvb_frontend* fe, fe_status_t* status) { - u16 snr12 = sp887x_readreg(fe, 0xf16); - u16 sync0x200 = sp887x_readreg(fe, 0x200); - u16 sync0xf17 = sp887x_readreg(fe, 0xf17); - fe_status_t *status = arg; + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + u16 snr12 = sp887x_readreg(state, 0xf16); + u16 sync0x200 = sp887x_readreg(state, 0x200); + u16 sync0xf17 = sp887x_readreg(state, 0xf17); *status = 0; @@ -492,212 +451,172 @@ steps); } - break; - + return 0; } - case FE_READ_BER: +static int sp887x_read_ber(struct dvb_frontend* fe, u32* ber) { - u32* ber = arg; - *ber = (sp887x_readreg(fe, 0xc08) & 0x3f) | - (sp887x_readreg(fe, 0xc07) << 6); - sp887x_writereg(fe, 0xc08, 0x000); - sp887x_writereg(fe, 0xc07, 0x000); + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + + *ber = (sp887x_readreg(state, 0xc08) & 0x3f) | + (sp887x_readreg(state, 0xc07) << 6); + sp887x_writereg(state, 0xc08, 0x000); + sp887x_writereg(state, 0xc07, 0x000); if (*ber >= 0x3fff0) *ber = ~0; - break; + return 0; } - case FE_READ_SIGNAL_STRENGTH: // FIXME: correct registers ? +static int sp887x_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - u16 snr12 = sp887x_readreg(fe, 0xf16); + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + + u16 snr12 = sp887x_readreg(state, 0xf16); u32 signal = 3 * (snr12 << 4); - *((u16*) arg) = (signal < 0xffff) ? signal : 0xffff; - break; - } + *strength = (signal < 0xffff) ? signal : 0xffff; - case FE_READ_SNR: - { - u16 snr12 = sp887x_readreg(fe, 0xf16); - *(u16*) arg = (snr12 << 4) | (snr12 >> 8); - break; + return 0; } - case FE_READ_UNCORRECTED_BLOCKS: +static int sp887x_read_snr(struct dvb_frontend* fe, u16* snr) { - u32 *ublocks = (u32 *) arg; - *ublocks = sp887x_readreg(fe, 0xc0c); - if (*ublocks == 0xfff) - *ublocks = ~0; - break; - } + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; - case FE_SET_FRONTEND: - return sp887x_setup_frontend_parameters(fe, arg); - - case FE_GET_FRONTEND: // FIXME: read known values back from Hardware... - break; + u16 snr12 = sp887x_readreg(state, 0xf16); + *snr = (snr12 << 4) | (snr12 >> 8); - case FE_SLEEP: - /* tristate TS output and disable interface pins */ - sp887x_writereg(fe, 0xc18, 0x000); - break; - - case FE_INIT: - /* enable TS output and interface pins */ - sp887x_writereg(fe, 0xc18, 0x00d); - break; - - case FE_GET_TUNE_SETTINGS: - { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; - fesettings->min_delay_ms = 350; - fesettings->step_size = 166666*2; - fesettings->max_drift = (166666*2)+1; return 0; } - default: - return -EOPNOTSUPP; - }; +static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + + *ucblocks = sp887x_readreg(state, 0xc0c); + if (*ucblocks == 0xfff) + *ucblocks = ~0; return 0; } -static struct i2c_client client_template; - -static int attach_adapter(struct i2c_adapter *adapter) +static int sp887x_sleep(struct dvb_frontend* fe) { - struct i2c_client *client; - struct sp887x_state *state; - const struct firmware *fw; - int ret; - - struct i2c_msg msg = {.addr = 0x70, .flags = 0, .buf = NULL, .len = 0 }; - - dprintk ("%s\n", __FUNCTION__); - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - return -ENOMEM; - } + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; - if (NULL == (state = kmalloc(sizeof(struct sp887x_state), GFP_KERNEL))) { - kfree(client); - return -ENOMEM; - } - state->i2c = adapter; + /* tristate TS output and disable interface pins */ + sp887x_writereg(state, 0xc18, 0x000); - if (i2c_transfer (adapter, &msg, 1) != 1) { - kfree(state); - kfree(client); - return -ENODEV; + return 0; } - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - i2c_set_clientdata(client, (void*)state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(state); - return ret; - } +static int sp887x_init(struct dvb_frontend* fe) +{ + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + const struct firmware *fw = NULL; + int ret; + if (!state->initialised) { /* request the firmware, this will block until someone uploads it */ printk("sp887x: waiting for firmware upload...\n"); - ret = request_firmware(&fw, SP887X_DEFAULT_FIRMWARE, &client->dev); + ret = state->config->request_firmware(fe, &fw, SP887X_DEFAULT_FIRMWARE); if (ret) { printk("sp887x: no firmware upload (timeout or file not found?)\n"); - goto out; + return ret; } - ret = sp887x_initial_setup(adapter, fw); + ret = sp887x_initial_setup(fe, fw); if (ret) { printk("sp887x: writing firmware to device failed\n"); - goto out; + release_firmware(fw); + return ret; } - - ret = dvb_register_frontend(sp887x_ioctl, state->dvb, state, - &sp887x_info, THIS_MODULE); - if (ret) { - printk("sp887x: registering frontend to dvb-core failed.\n"); - goto out; + state->initialised = 1; } + /* enable TS output and interface pins */ + sp887x_writereg(state, 0xc18, 0x00d); + return 0; -out: - release_firmware(fw); - i2c_detach_client(client); - kfree(client); - kfree(state); - return ret; } -static int detach_client(struct i2c_client *client) +static int sp887x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - dvb_unregister_frontend (sp887x_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; + fesettings->min_delay_ms = 350; + fesettings->step_size = 166666*2; + fesettings->max_drift = (166666*2)+1; + return 0; } -static int command (struct i2c_client *client, unsigned int cmd, void *arg) +static void sp887x_release(struct dvb_frontend* fe) { - struct sp887x_state *state = (struct sp887x_state*)i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_REGISTER: - state->dvb = (struct dvb_adapter*)arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - return 0; + struct sp887x_state* state = (struct sp887x_state*) fe->demodulator_priv; + kfree(state); } -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_SP887X, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; - -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; +static struct dvb_frontend_ops sp887x_ops; -static int __init init_sp887x(void) +struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, + struct i2c_adapter* i2c) { - return i2c_add_driver(&driver); -} + struct sp887x_state* state = NULL; -static void __exit exit_sp887x(void) -{ - if (i2c_del_driver(&driver)) - printk("sp887x: driver deregistration failed\n"); -} + /* allocate memory for the internal state */ + state = (struct sp887x_state*) kmalloc(sizeof(struct sp887x_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + + /* check if the demod is there */ + if (sp887x_readreg(state, 0x0200) < 0) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops sp887x_ops = { + + .info = { + .name = "Spase SP887x DVB-T", + .type = FE_OFDM, + .frequency_min = 50500000, + .frequency_max = 858000000, + .frequency_stepsize = 166666, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_RECOVER + }, + + .release = sp887x_release, + + .init = sp887x_init, + .sleep = sp887x_sleep, + + .set_frontend = sp887x_setup_frontend_parameters, + .get_tune_settings = sp887x_get_tune_settings, + + .read_status = sp887x_read_status, + .read_ber = sp887x_read_ber, + .read_signal_strength = sp887x_read_signal_strength, + .read_snr = sp887x_read_snr, + .read_ucblocks = sp887x_read_ucblocks, +}; -module_init(init_sp887x); -module_exit(exit_sp887x); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("sp887x DVB-T demodulator driver"); +MODULE_DESCRIPTION("Spase sp887x DVB-T demodulator driver"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(sp887x_attach); diff -Nru a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/sp887x.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,29 @@ +/* + Driver for the Spase sp887x demodulator +*/ + +#ifndef SP887X_H +#define SP887X_H + +#include +#include + +struct sp887x_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + + /* this should return the actual frequency tuned to */ + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, + struct i2c_adapter* i2c); + +#endif // SP887X_H diff -Nru a/drivers/media/dvb/frontends/sp887x_firm.h b/drivers/media/dvb/frontends/sp887x_firm.h --- a/drivers/media/dvb/frontends/sp887x_firm.h 2004-12-12 17:40:52 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,1375 +0,0 @@ -#ifndef __SP887x_FIRM_H__ -#define __SP887x_FIRM_H__ - - -static const -u8 sp887x_firm [16384] __devinitdata = { - 0x00, 0xb9, 0x00, 0xb9, 0x0f, 0xf9, 0x1f, 0x5d, 0x0f, 0xf9, 0x1b, 0x67, - 0x0f, 0xf9, 0x19, 0x2f, 0x0f, 0xf9, 0x00, 0x36, 0x0f, 0xf9, 0x00, 0x3c, - 0x0f, 0xf5, 0x00, 0x3e, 0x0f, 0xf9, 0x03, 0x0c, 0x0f, 0xf9, 0x0c, 0x59, - 0x0f, 0xf9, 0x15, 0xde, 0x0f, 0xf9, 0x19, 0x07, 0x0f, 0xf9, 0x08, 0x98, - 0x0f, 0xf9, 0x08, 0x03, 0x0f, 0xf9, 0x00, 0x26, 0x0f, 0xf9, 0x03, 0x11, - 0x0f, 0xf9, 0x1b, 0x47, 0x0f, 0xf9, 0x00, 0x76, 0x0f, 0xf9, 0x0a, 0xdd, - 0x0f, 0xf9, 0x0d, 0x09, 0x0f, 0xc4, 0x01, 0x62, 0x0b, 0x21, 0x0f, 0x38, - 0x00, 0x15, 0x0f, 0xf8, 0x00, 0x32, 0x09, 0xa1, 0x0f, 0xf9, 0x04, 0x2e, - 0x0f, 0xf9, 0x04, 0x5e, 0x0f, 0xd9, 0x00, 0x2e, 0x09, 0xfb, 0x0f, 0x39, - 0x0f, 0xf0, 0x02, 0x02, 0x0f, 0xc4, 0x01, 0x7a, 0x0f, 0xf9, 0x00, 0x42, - 0x0f, 0xf0, 0x02, 0x05, 0x0f, 0xc4, 0x01, 0x7b, 0x0f, 0xf9, 0x00, 0x42, - 0x0b, 0x21, 0x0f, 0xc4, 0x01, 0x7c, 0x0f, 0xd4, 0x02, 0xa0, 0x1f, 0xf8, - 0x00, 0x53, 0x11, 0xa1, 0x0f, 0xd4, 0x00, 0xa0, 0x1f, 0xf8, 0x00, 0x53, - 0x11, 0xe1, 0x08, 0x15, 0x1f, 0x39, 0x0f, 0x38, 0x0c, 0x32, 0x0b, 0x13, - 0x00, 0x08, 0x10, 0x48, 0x0f, 0x38, 0x0c, 0x32, 0x00, 0x21, 0x07, 0x04, - 0x0b, 0x94, 0x1b, 0x94, 0x1f, 0x39, 0x06, 0x45, 0x0b, 0xd5, 0x1f, 0xf9, - 0x00, 0x65, 0x0b, 0xd5, 0x1f, 0xf9, 0x00, 0x65, 0x0f, 0x39, 0x07, 0x84, - 0x0b, 0x27, 0x09, 0xa1, 0x06, 0xc5, 0x0b, 0x67, 0x09, 0x94, 0x1f, 0xf9, - 0x00, 0x6f, 0x0f, 0x38, 0x09, 0x97, 0x06, 0x44, 0x07, 0x05, 0x0b, 0xa1, - 0x0b, 0xd8, 0x0b, 0xa1, 0x0f, 0x38, 0x0b, 0xd2, 0x0f, 0xcb, 0x01, 0x39, - 0x0f, 0xf5, 0x02, 0x47, 0x0f, 0xf4, 0x02, 0x5d, 0x06, 0x0b, 0x05, 0x85, - 0x0b, 0xea, 0x0b, 0xe1, 0x02, 0xde, 0x09, 0xeb, 0x0f, 0xee, 0x01, 0xc0, - 0x0f, 0xee, 0x0a, 0x01, 0x0f, 0xcf, 0x0c, 0x80, 0x0e, 0x2a, 0x0e, 0x6b, - 0x0f, 0xec, 0x06, 0xbe, 0x09, 0x2d, 0x0d, 0xee, 0x0f, 0xc4, 0x00, 0x95, - 0x12, 0x35, 0x0f, 0xe1, 0x0d, 0xbd, 0x0e, 0x18, 0x09, 0xec, 0x0f, 0xe1, - 0x00, 0xcd, 0x0e, 0x51, 0x09, 0xed, 0x0d, 0xee, 0x0b, 0xe1, 0x02, 0xdf, - 0x09, 0xe7, 0x0f, 0xe1, 0x05, 0x6d, 0x0e, 0x18, 0x09, 0xec, 0x0f, 0xe1, - 0x02, 0x26, 0x0e, 0x51, 0x09, 0xed, 0x0d, 0xee, 0x12, 0x35, 0x0f, 0xe1, - 0x0d, 0x03, 0x0f, 0xce, 0x03, 0xd2, 0x0e, 0x18, 0x09, 0xec, 0x0d, 0xa1, - 0x0e, 0x51, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xcb, 0x0a, 0xe3, 0x0f, 0xe1, - 0x08, 0x10, 0x0f, 0xce, 0x05, 0x88, 0x0e, 0x18, 0x09, 0xec, 0x0d, 0xa1, - 0x0e, 0x51, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xca, 0x09, 0x00, 0x0f, 0xe1, - 0x00, 0x38, 0x0f, 0xce, 0x07, 0xa7, 0x0e, 0x18, 0x09, 0xec, 0x0d, 0xa1, - 0x0e, 0x51, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xe2, 0x00, 0x3f, 0x0f, 0xe1, - 0x0a, 0xb1, 0x0f, 0xce, 0x0b, 0x89, 0x0e, 0x18, 0x09, 0xec, 0x0d, 0xa1, - 0x0e, 0x51, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xc9, 0x0a, 0x75, 0x0f, 0xe1, - 0x03, 0xf3, 0x0f, 0xce, 0x07, 0x15, 0x0e, 0x18, 0x09, 0xec, 0x0d, 0xa1, - 0x0e, 0x53, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xcf, 0x07, 0xc0, 0x0d, 0xce, - 0x1f, 0xce, 0x01, 0xc0, 0x00, 0x21, 0x0d, 0xae, 0x0c, 0x6e, 0x09, 0x96, - 0x0f, 0xce, 0x05, 0x00, 0x0f, 0xcd, 0x05, 0x40, 0x0f, 0xcc, 0x03, 0x00, - 0x09, 0xab, 0x00, 0x2a, 0x0d, 0xee, 0x1d, 0xae, 0x1e, 0x18, 0x19, 0xea, - 0x1e, 0x58, 0x19, 0xeb, 0x1d, 0x6e, 0x1e, 0x18, 0x19, 0xec, 0x1e, 0x51, - 0x19, 0xed, 0x1d, 0x2e, 0x0c, 0xee, 0x0f, 0xe1, 0x1f, 0xe7, 0x0c, 0xae, - 0x05, 0x84, 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0xa4, 0x09, 0x99, 0x09, 0xe1, - 0x02, 0xdc, 0x12, 0xdd, 0x0f, 0x38, 0x09, 0xc2, 0x0f, 0xfb, 0x00, 0x7d, - 0x03, 0x37, 0x0f, 0xc4, 0x00, 0x9e, 0x05, 0xb7, 0x0f, 0xf5, 0x01, 0x39, - 0x0f, 0xfb, 0x00, 0x7d, 0x03, 0x37, 0x0f, 0xc4, 0x00, 0xa1, 0x05, 0xb7, - 0x0f, 0xf5, 0x01, 0x39, 0x05, 0x84, 0x0b, 0xaa, 0x0b, 0xab, 0x0f, 0xef, - 0x01, 0xc0, 0x0b, 0x88, 0x0c, 0x27, 0x09, 0xa6, 0x18, 0xb4, 0x05, 0x84, - 0x09, 0xa1, 0x0f, 0xd9, 0x0a, 0x69, 0x09, 0xee, 0x0f, 0xd7, 0x1f, 0xd0, - 0x18, 0xb5, 0x02, 0x97, 0x0c, 0x21, 0x1f, 0xf8, 0x01, 0x36, 0x02, 0xde, - 0x0f, 0xc4, 0x06, 0x28, 0x02, 0x34, 0x19, 0x44, 0x1f, 0xf9, 0x01, 0x45, - 0x0f, 0xee, 0x05, 0x00, 0x00, 0x21, 0x0e, 0x18, 0x09, 0xea, 0x0e, 0x58, - 0x09, 0xeb, 0x0f, 0xee, 0x05, 0x40, 0x0e, 0x18, 0x0f, 0xf8, 0x01, 0x4a, - 0x09, 0xc9, 0x0e, 0x09, 0x0f, 0xee, 0x05, 0x00, 0x0e, 0x2a, 0x0e, 0x6b, - 0x0f, 0xcf, 0x0c, 0x80, 0x0f, 0xec, 0x0e, 0x2d, 0x00, 0x2d, 0x0d, 0xee, - 0x0f, 0xe1, 0x01, 0xa4, 0x01, 0x4e, 0x0e, 0x20, 0x09, 0xec, 0x0d, 0xa1, - 0x0e, 0x59, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xe1, 0x0a, 0x35, 0x0f, 0xce, - 0x00, 0x27, 0x0e, 0x20, 0x09, 0xec, 0x0d, 0xa1, 0x0e, 0x59, 0x09, 0xed, - 0x0d, 0xee, 0x0f, 0xe1, 0x04, 0x34, 0x0f, 0xce, 0x00, 0xe3, 0x0e, 0x20, - 0x09, 0xec, 0x0d, 0xa1, 0x0e, 0x59, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xe1, - 0x0f, 0xb1, 0x0f, 0xce, 0x03, 0xd7, 0x0e, 0x20, 0x09, 0xec, 0x0d, 0xa1, - 0x0e, 0x59, 0x09, 0xed, 0x0d, 0xee, 0x0f, 0xe1, 0x02, 0x15, 0x0f, 0xce, - 0x0b, 0x17, 0x0e, 0x20, 0x09, 0xec, 0x0d, 0xa1, 0x0e, 0x59, 0x09, 0xed, - 0x0d, 0xee, 0x0f, 0xcf, 0x0a, 0xbf, 0x0f, 0xce, 0x09, 0x00, 0x0d, 0xee, - 0x0c, 0x61, 0x0d, 0xae, 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0x99, 0x09, 0xe1, - 0x12, 0xdf, 0x12, 0x34, 0x19, 0x44, 0x02, 0xdc, 0x0f, 0x38, 0x09, 0xc2, - 0x09, 0x44, 0x0f, 0xc2, 0x0f, 0xff, 0x0f, 0xc2, 0x0f, 0xff, 0x0f, 0xc2, - 0x03, 0xff, 0x0f, 0xc4, 0x00, 0x95, 0x0f, 0xc2, 0x0f, 0xff, 0x0f, 0xc2, - 0x0f, 0xff, 0x0f, 0xc2, 0x0b, 0xff, 0x0f, 0xc4, 0x00, 0x98, 0x00, 0x02, - 0x0f, 0xc2, 0x08, 0x00, 0x0f, 0xc2, 0x04, 0x00, 0x0f, 0xc4, 0x00, 0x9b, - 0x00, 0x02, 0x0f, 0xc2, 0x08, 0x00, 0x0f, 0xc2, 0x0c, 0x00, 0x0f, 0xc4, - 0x00, 0x9e, 0x0f, 0xc2, 0x08, 0xc1, 0x0f, 0xc2, 0x0c, 0x0a, 0x00, 0x42, - 0x0f, 0xc4, 0x00, 0xa1, 0x0f, 0xc2, 0x08, 0xc1, 0x0f, 0xc2, 0x0c, 0x0a, - 0x00, 0x82, 0x0f, 0xc4, 0x00, 0xa4, 0x00, 0x02, 0x0f, 0xc2, 0x0a, 0x00, - 0x00, 0xc2, 0x0f, 0xc4, 0x00, 0xa7, 0x00, 0x02, 0x0f, 0xc2, 0x0c, 0x80, - 0x0f, 0xf4, 0x04, 0xe0, 0x01, 0x82, 0x0f, 0xc4, 0x01, 0x5d, 0x0b, 0x3b, - 0x0f, 0x39, 0x04, 0x04, 0x0b, 0x21, 0x0f, 0xc4, 0x01, 0x5c, 0x0f, 0xc5, - 0x07, 0x3d, 0x0b, 0x01, 0x0b, 0x14, 0x1f, 0x39, 0x00, 0x14, 0x09, 0xc0, - 0x0f, 0xc8, 0x04, 0x18, 0x00, 0xd4, 0x1f, 0xc8, 0x1b, 0xb6, 0x00, 0x54, - 0x1f, 0xc8, 0x1c, 0xa7, 0x01, 0x14, 0x1f, 0xc8, 0x1c, 0x9f, 0x00, 0x94, - 0x1f, 0xc4, 0x01, 0x5e, 0x1b, 0x08, 0x02, 0x94, 0x1f, 0xc8, 0x04, 0x24, - 0x02, 0xd4, 0x1f, 0xc8, 0x04, 0x26, 0x03, 0x14, 0x1f, 0xc8, 0x04, 0x28, - 0x03, 0x54, 0x1f, 0xc8, 0x04, 0x2a, 0x03, 0x94, 0x1f, 0xc8, 0x04, 0x2c, - 0x03, 0xd4, 0x1f, 0xc8, 0x04, 0x2e, 0x05, 0x14, 0x1f, 0xc8, 0x04, 0x30, - 0x0f, 0xd4, 0x00, 0x28, 0x1f, 0xc8, 0x08, 0xeb, 0x0f, 0xd4, 0x00, 0x29, - 0x1f, 0xc8, 0x09, 0x49, 0x0f, 0xd4, 0x00, 0x2a, 0x1f, 0xc8, 0x09, 0xe6, - 0x0f, 0xd4, 0x00, 0x2b, 0x1f, 0xc8, 0x0b, 0x54, 0x0f, 0xd4, 0x00, 0x32, - 0x1f, 0xc8, 0x0b, 0x87, 0x0f, 0xd4, 0x00, 0x3c, 0x1f, 0xc8, 0x0b, 0xcf, - 0x0f, 0xd4, 0x00, 0x46, 0x1f, 0xc8, 0x11, 0x95, 0x0f, 0xd4, 0x00, 0x47, - 0x1f, 0xc8, 0x11, 0xb9, 0x0f, 0xd4, 0x00, 0x3f, 0x1f, 0xc8, 0x09, 0x85, - 0x0f, 0xd4, 0x00, 0x40, 0x1f, 0xc8, 0x09, 0x89, 0x0f, 0xd4, 0x00, 0x41, - 0x1f, 0xc8, 0x09, 0xcb, 0x02, 0x14, 0x1f, 0xc8, 0x04, 0x18, 0x0f, 0xd4, - 0x00, 0x50, 0x1f, 0xc8, 0x0e, 0xd9, 0x0f, 0xc4, 0x01, 0x5d, 0x0f, 0x38, - 0x0c, 0x00, 0x0f, 0xc8, 0x01, 0x00, 0x0f, 0xf7, 0x05, 0x82, 0x0f, 0xc4, - 0x01, 0x8b, 0x00, 0x00, 0x0f, 0xc4, 0x01, 0x8a, 0x00, 0x00, 0x0f, 0xf1, - 0x03, 0x39, 0x0f, 0xc5, 0x01, 0x89, 0x0f, 0xc4, 0x01, 0x8e, 0x0b, 0x21, - 0x0a, 0x48, 0x0c, 0x13, 0x1f, 0xf8, 0x02, 0x5f, 0x0c, 0x01, 0x0f, 0xc4, - 0x01, 0x90, 0x00, 0x21, 0x0b, 0x15, 0x1f, 0xc5, 0x01, 0x8b, 0x1c, 0x01, - 0x1f, 0xc5, 0x01, 0x8a, 0x1b, 0x3a, 0x1b, 0x01, 0x0f, 0xf1, 0x03, 0x39, - 0x0f, 0xc4, 0x01, 0x8e, 0x0b, 0x21, 0x0a, 0x48, 0x0c, 0x12, 0x1f, 0xf9, - 0x02, 0x4b, 0x0f, 0xc4, 0x01, 0x8c, 0x0f, 0xf6, 0x05, 0x9d, 0x0c, 0x00, - 0x0f, 0xf1, 0x03, 0x39, 0x0f, 0xc4, 0x01, 0x8d, 0x1f, 0x38, 0x0a, 0x40, - 0x0f, 0xc5, 0x01, 0x88, 0x0b, 0x01, 0x0f, 0xc4, 0x01, 0x89, 0x0f, 0xc5, - 0x07, 0x3b, 0x0b, 0x01, 0x0f, 0xc4, 0x01, 0x8b, 0x0f, 0xc5, 0x07, 0x3c, - 0x0b, 0x01, 0x0f, 0xc4, 0x01, 0x8c, 0x0f, 0xc5, 0x01, 0x87, 0x0b, 0x01, - 0x0f, 0xc4, 0x01, 0x8a, 0x0f, 0xc5, 0x01, 0x86, 0x0b, 0x01, 0x0f, 0xc4, - 0x01, 0x6a, 0x0f, 0xc5, 0x01, 0x85, 0x0b, 0x01, 0x0f, 0xc4, 0x01, 0x6b, - 0x0f, 0xc5, 0x01, 0x84, 0x0f, 0x38, 0x0b, 0x01, 0x0f, 0xc4, 0x01, 0x90, - 0x0c, 0x40, 0x0c, 0x21, 0x0f, 0xd9, 0x00, 0x67, 0x09, 0xc8, 0x00, 0xb6, - 0x00, 0x09, 0x0f, 0xf7, 0x04, 0x66, 0x0f, 0xc4, 0x06, 0x96, 0x0f, 0xc5, - 0x06, 0x2b, 0x0f, 0xf7, 0x02, 0x74, 0x07, 0x04, 0x00, 0x02, 0x0f, 0xc2, - 0x0c, 0x00, 0x0f, 0xf6, 0x02, 0x70, 0x01, 0x02, 0x05, 0x37, 0x0f, 0xf7, - 0x04, 0x6f, 0x0f, 0xf7, 0x02, 0x09, 0x0f, 0xf7, 0x01, 0x33, 0x0f, 0xc4, - 0x01, 0x8f, 0x07, 0x36, 0x0c, 0x00, 0x0f, 0xe1, 0x08, 0x0f, 0x1f, 0xe1, - 0x02, 0x0f, 0x0c, 0x11, 0x0f, 0xc4, 0x01, 0x8e, 0x0f, 0x38, 0x09, 0xc0, - 0x0f, 0xf0, 0x0f, 0x10, 0x0c, 0x32, 0x0f, 0xc4, 0x07, 0xc0, 0x0f, 0x38, - 0x0c, 0x00, 0x0f, 0xf1, 0x0f, 0x11, 0x00, 0x08, 0x0a, 0x61, 0x00, 0x15, - 0x11, 0x13, 0x10, 0x49, 0x10, 0x48, 0x0f, 0xf1, 0x0f, 0x13, 0x0f, 0xc4, - 0x07, 0xbc, 0x0b, 0x22, 0x00, 0x00, 0x0a, 0x65, 0x09, 0xb2, 0x00, 0x21, - 0x09, 0x95, 0x1c, 0x62, 0x10, 0xa5, 0x19, 0x89, 0x10, 0x48, 0x0c, 0x15, - 0x1f, 0xf0, 0x02, 0x04, 0x0c, 0x72, 0x0f, 0xf0, 0x02, 0x03, 0x00, 0x32, - 0x0f, 0x38, 0x00, 0x72, 0x0f, 0xfa, 0x02, 0xb8, 0x00, 0xc8, 0x0f, 0xf9, - 0x02, 0xbf, 0x0f, 0xc4, 0x07, 0xba, 0x0f, 0xc0, 0x00, 0x40, 0x0f, 0xc4, - 0x07, 0xbb, 0x00, 0x40, 0x0f, 0xc4, 0x07, 0xb8, 0x0f, 0xc0, 0x04, 0x00, - 0x0f, 0xc4, 0x07, 0xb9, 0x0f, 0xc0, 0x08, 0x00, 0x0f, 0xc4, 0x07, 0xbd, - 0x0f, 0xc0, 0x0f, 0xff, 0x0f, 0xc4, 0x07, 0xdd, 0x00, 0x00, 0x0f, 0xc4, - 0x07, 0xc2, 0x0f, 0x38, 0x00, 0x40, 0x0f, 0xf8, 0x03, 0x03, 0x0b, 0x22, - 0x0f, 0xf8, 0x03, 0x03, 0x0c, 0x22, 0x0f, 0xc4, 0x07, 0xbd, 0x0b, 0x24, - 0x09, 0xa2, 0x0f, 0xc4, 0x07, 0xbc, 0x0b, 0x25, 0x0f, 0x38, 0x09, 0x80, - 0x0f, 0xfa, 0x02, 0xb8, 0x00, 0x48, 0x0f, 0xf9, 0x02, 0xbf, 0x0f, 0xf0, - 0x0f, 0x10, 0x0c, 0x32, 0x0a, 0xe1, 0x0f, 0xc5, 0x07, 0xc3, 0x0f, 0xf1, - 0x0f, 0x10, 0x0a, 0x7f, 0x0f, 0xf0, 0x0f, 0x12, 0x0b, 0xf2, 0x0a, 0xd5, - 0x1f, 0xf9, 0x03, 0x1a, 0x03, 0xb9, 0x0a, 0x44, 0x0f, 0xf1, 0x0f, 0x12, - 0x0a, 0x7e, 0x0f, 0xfd, 0x03, 0x28, 0x00, 0x3f, 0x0b, 0x83, 0x07, 0x39, - 0x0a, 0x45, 0x0f, 0xf1, 0x0f, 0x12, 0x0a, 0x7e, 0x0f, 0xfd, 0x03, 0x33, - 0x00, 0x3f, 0x0f, 0xf1, 0x0f, 0x12, 0x0a, 0x43, 0x03, 0xb9, 0x0f, 0xc4, - 0x07, 0x6e, 0x00, 0x00, 0x04, 0x04, 0x00, 0x40, 0x0f, 0xc4, 0x07, 0xdd, - 0x00, 0x00, 0x0f, 0xc4, 0x07, 0xc2, 0x00, 0x40, 0x0f, 0xf0, 0x0f, 0x17, - 0x03, 0xb8, 0x00, 0x32, 0x04, 0x04, 0x00, 0xc0, 0x0f, 0xc4, 0x07, 0xdd, - 0x00, 0x40, 0x0f, 0xc4, 0x07, 0xc2, 0x03, 0xb8, 0x00, 0x40, 0x0f, 0xc4, - 0x07, 0x6e, 0x00, 0x00, 0x04, 0x04, 0x01, 0x00, 0x0f, 0xc4, 0x07, 0xdd, - 0x00, 0x00, 0x0f, 0xc4, 0x07, 0xc2, 0x03, 0xb8, 0x00, 0x40, 0x04, 0x04, - 0x02, 0x00, 0x0f, 0xc4, 0x07, 0x6e, 0x00, 0x00, 0x0f, 0xc4, 0x07, 0xdd, - 0x03, 0xb8, 0x00, 0x00, 0x0f, 0xc4, 0x01, 0x30, 0x0b, 0x83, 0x0b, 0x83, - 0x0f, 0xc4, 0x01, 0x32, 0x0b, 0x83, 0x07, 0x38, 0x0b, 0x83, 0x0f, 0xc4, - 0x06, 0x94, 0x0b, 0x83, 0x0b, 0x83, 0x0f, 0xc4, 0x01, 0x6c, 0x07, 0x38, - 0x0b, 0x83, 0x0f, 0xc4, 0x01, 0x38, 0x0b, 0x83, 0x0b, 0x83, 0x0f, 0xc4, - 0x01, 0x3a, 0x0b, 0x83, 0x0b, 0x83, 0x0f, 0xc4, 0x01, 0x3c, 0x0b, 0x83, - 0x0b, 0x83, 0x0f, 0xc4, 0x01, 0x76, 0x0b, 0x83, 0x0f, 0xc4, 0x01, 0x77, - 0x07, 0x38, 0x0b, 0x83, 0x0f, 0xc4, 0x01, 0x78, 0x0b, 0x83, 0x0f, 0xc4, - 0x01, 0x79, 0x07, 0x38, 0x0b, 0x83, 0x0f, 0xc4, 0x05, 0xe6, 0x0b, 0x83, - 0x0b, 0x83, 0x0f, 0xc4, 0x01, 0x40, 0x0b, 0x83, 0x07, 0x38, 0x0b, 0x83, - 0x0f, 0xf1, 0x0f, 0x11, 0x0a, 0x48, 0x0c, 0x21, 0x02, 0x13, 0x1f, 0xf9, - 0x02, 0xbf, 0x0f, 0xf1, 0x0f, 0x10, 0x00, 0x09, 0x02, 0x54, 0x13, 0x89, - 0x02, 0xd4, 0x1f, 0xc9, 0x03, 0x35, 0x03, 0x54, 0x1f, 0xc9, 0x03, 0x44, - 0x03, 0xd4, 0x1f, 0xc9, 0x03, 0x59, 0x0f, 0xd4, 0x00, 0x59, 0x1f, 0xc9, - 0x03, 0x4d, 0x0f, 0xd4, 0x00, 0x41, 0x1f, 0xc9, 0x03, 0x21, 0x0f, 0xd4, - 0x00, 0x49, 0x1f, 0xc9, 0x03, 0x2a, 0x0f, 0xd4, 0x00, 0x71, 0x1f, 0xc9, - 0x03, 0x62, 0x0f, 0xd4, 0x00, 0x73, 0x1f, 0xc9, 0x03, 0x6b, 0x0f, 0xd4, - 0x00, 0x80, 0x1f, 0xc9, 0x03, 0x73, 0x0f, 0xd4, 0x00, 0x81, 0x1f, 0xc9, - 0x03, 0x86, 0x0f, 0xd4, 0x00, 0x82, 0x1f, 0xc9, 0x03, 0x8d, 0x0c, 0x61, - 0x00, 0x15, 0x1f, 0xf1, 0x0f, 0x12, 0x1f, 0xc5, 0x07, 0xc3, 0x1c, 0x79, - 0x0f, 0xf9, 0x02, 0xde, 0x0f, 0xfb, 0x03, 0x96, 0x0f, 0xc4, 0x07, 0xdd, - 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xf9, 0x03, 0xd4, 0x0f, 0x39, 0x0f, 0xc8, - 0x00, 0x3c, 0x03, 0x3b, 0x1f, 0x39, 0x0f, 0xf1, 0x0a, 0x07, 0x00, 0x21, - 0x0f, 0xc4, 0x01, 0x91, 0x0b, 0x08, 0x0f, 0xc4, 0x01, 0x92, 0x0b, 0x15, - 0x1b, 0x08, 0x0c, 0x14, 0x1f, 0x39, 0x0c, 0x21, 0x0a, 0x55, 0x1f, 0xc4, - 0x01, 0x93, 0x1c, 0x00, 0x1f, 0xc8, 0x03, 0xf6, 0x15, 0x3b, 0x0f, 0x39, - 0x0f, 0xc4, 0x01, 0x93, 0x0b, 0x0f, 0x0d, 0xc8, 0x00, 0xb6, 0x00, 0x09, - 0x05, 0x37, 0x0d, 0xe1, 0x02, 0x19, 0x09, 0xc8, 0x00, 0xb6, 0x00, 0x09, - 0x0f, 0xf7, 0x02, 0x70, 0x0f, 0xc4, 0x00, 0xad, 0x00, 0x37, 0x01, 0xbb, - 0x0f, 0xc8, 0x00, 0x60, 0x00, 0xb6, 0x00, 0x09, 0x0f, 0xc4, 0x00, 0xad, - 0x0f, 0xf7, 0x02, 0x81, 0x0f, 0xf0, 0x0a, 0x07, 0x0f, 0xc4, 0x01, 0x93, - 0x0b, 0x32, 0x0f, 0xc4, 0x00, 0xaa, 0x00, 0x35, 0x02, 0x3a, 0x00, 0x08, - 0x02, 0xba, 0x00, 0x48, 0x0f, 0xfb, 0x03, 0xd4, 0x0f, 0xf6, 0x00, 0x3a, - 0x02, 0x08, 0x1f, 0xf9, 0x04, 0x1c, 0x0f, 0x39, 0x0f, 0xf5, 0x05, 0xc7, - 0x0f, 0xf5, 0x06, 0x07, 0x0f, 0xf5, 0x06, 0x14, 0x0f, 0xf5, 0x06, 0x79, - 0x0f, 0xf5, 0x06, 0x98, 0x0f, 0xf5, 0x06, 0xbc, 0x0f, 0xc4, 0x06, 0x8f, - 0x0b, 0x88, 0x00, 0xb6, 0x0b, 0x89, 0x03, 0x37, 0x02, 0x36, 0x04, 0xc4, - 0x06, 0xbb, 0x1f, 0xf7, 0x00, 0x8f, 0x0f, 0xfb, 0x00, 0x7a, 0x0f, 0xc4, - 0x00, 0xb0, 0x00, 0x37, 0x04, 0x44, 0x0f, 0xc5, 0x01, 0x94, 0x0b, 0x01, - 0x0f, 0xf7, 0x06, 0xdc, 0x0f, 0xc4, 0x00, 0xb0, 0x02, 0x37, 0x04, 0x44, - 0x0b, 0x21, 0x0f, 0xc4, 0x01, 0x94, 0x0b, 0x11, 0x01, 0x36, 0x09, 0xc8, - 0x03, 0xb7, 0x0f, 0xc4, 0x06, 0x8f, 0x0c, 0x02, 0x03, 0x36, 0x0c, 0x42, - 0x00, 0xb7, 0x05, 0x37, 0x04, 0x37, 0x06, 0xbb, 0x1f, 0xf7, 0x00, 0x8f, - 0x00, 0x34, 0x04, 0xc4, 0x01, 0x38, 0x00, 0x48, 0x07, 0x37, 0x0f, 0xc4, - 0x02, 0x0e, 0x0f, 0xc0, 0x08, 0xe1, 0x1f, 0xc0, 0x02, 0x39, 0x0f, 0xc4, - 0x07, 0x38, 0x1f, 0xc4, 0x07, 0x37, 0x0f, 0xc5, 0x01, 0x95, 0x0b, 0x01, - 0x0f, 0xc4, 0x07, 0x2e, 0x1f, 0xc4, 0x07, 0x2b, 0x02, 0x37, 0x0f, 0xc4, - 0x05, 0xf2, 0x0b, 0x21, 0x01, 0x9e, 0x0f, 0xc5, 0x01, 0x96, 0x0f, 0xc4, - 0x05, 0xea, 0x0b, 0x01, 0x1f, 0xc4, 0x05, 0xf0, 0x1b, 0x01, 0x0b, 0x61, - 0x0f, 0xc4, 0x06, 0x2b, 0x00, 0x14, 0x1f, 0xc4, 0x07, 0x31, 0x00, 0x54, - 0x1f, 0xc4, 0x07, 0x34, 0x06, 0xb7, 0x0f, 0xc4, 0x00, 0xb3, 0x00, 0x37, - 0x0f, 0xc4, 0x07, 0x39, 0x0b, 0x2a, 0x1f, 0xc4, 0x06, 0x07, 0x1b, 0x21, - 0x10, 0xd3, 0x11, 0x2a, 0x0f, 0xec, 0x00, 0x2b, 0x0f, 0xee, 0x0d, 0x40, - 0x0e, 0x21, 0x0f, 0xd9, 0x02, 0xd3, 0x0f, 0xc4, 0x02, 0x0a, 0x0f, 0xc2, - 0x02, 0xd3, 0x09, 0xc2, 0x0f, 0xc2, 0x02, 0xc7, 0x0f, 0xc2, 0x02, 0xd3, - 0x0f, 0xfb, 0x08, 0x15, 0x0f, 0xc8, 0x04, 0x60, 0x0f, 0xc9, 0x04, 0xae, - 0x0f, 0xfb, 0x02, 0x8c, 0x0f, 0xf9, 0x07, 0xed, 0x00, 0x21, 0x0f, 0xc4, - 0x04, 0x2b, 0x0b, 0x14, 0x1f, 0xc0, 0x04, 0xb6, 0x0b, 0x3b, 0x0f, 0x39, - 0x0f, 0xc0, 0x04, 0xe6, 0x0f, 0xc4, 0x04, 0x40, 0x0f, 0xc8, 0x04, 0x50, - 0x0f, 0xf7, 0x00, 0x71, 0x0f, 0xc5, 0x04, 0x2d, 0x0f, 0xfb, 0x08, 0x4d, - 0x0f, 0xfb, 0x08, 0x4d, 0x0f, 0xc4, 0x02, 0x10, 0x0b, 0x21, 0x00, 0x15, - 0x1f, 0xfa, 0x08, 0x4d, 0x00, 0x01, 0x0f, 0xc4, 0x02, 0x0e, 0x0b, 0x8f, - 0x00, 0x61, 0x0f, 0xc5, 0x04, 0x2c, 0x0b, 0x01, 0x0b, 0x19, 0x09, 0xc0, - 0x0f, 0xc5, 0x02, 0x10, 0x00, 0x41, 0x09, 0xe1, 0x0d, 0xd3, 0x1f, 0xf9, - 0x08, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x0f, 0xfa, 0x08, 0x3d, - 0x00, 0x00, 0x0f, 0xc4, 0x04, 0x2b, 0x0f, 0xc0, 0x06, 0x8f, 0x0f, 0x39, - 0x0f, 0xc0, 0x04, 0xf3, 0x0f, 0xc4, 0x01, 0x82, 0x0f, 0xc5, 0x04, 0x33, - 0x0b, 0x01, 0x0f, 0xcf, 0x04, 0x34, 0x0f, 0xfb, 0x08, 0x5f, 0x0f, 0xf9, - 0x08, 0x82, 0x0f, 0xc5, 0x01, 0x82, 0x0b, 0x4f, 0x0f, 0xc5, 0x04, 0x33, - 0x0b, 0x61, 0x0d, 0xd4, 0x1f, 0x38, 0x0d, 0xc1, 0x0f, 0xc0, 0x05, 0x04, - 0x0f, 0xcf, 0x04, 0x50, 0x0f, 0xfb, 0x08, 0x5f, 0x0f, 0xf9, 0x08, 0x82, - 0x0f, 0xc0, 0x05, 0x10, 0x0f, 0xc4, 0x04, 0x50, 0x0f, 0xcf, 0x04, 0x34, - 0x04, 0x0e, 0x0f, 0xcd, 0x04, 0x56, 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, - 0x0f, 0xc0, 0x05, 0x1c, 0x0f, 0xc4, 0x04, 0x53, 0x0f, 0xcf, 0x04, 0x37, - 0x04, 0x0e, 0x0f, 0xcd, 0x04, 0x59, 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, - 0x0f, 0xc0, 0x05, 0x27, 0x0f, 0xc4, 0x04, 0x50, 0x0a, 0x8f, 0x0f, 0xce, - 0x01, 0x39, 0x0f, 0xcd, 0x04, 0x46, 0x05, 0xb8, 0x06, 0x0c, 0x0f, 0xc0, - 0x05, 0x32, 0x0f, 0xc4, 0x04, 0x53, 0x0a, 0x8f, 0x0f, 0xce, 0x01, 0x39, - 0x0f, 0xcd, 0x04, 0x46, 0x05, 0xb8, 0x06, 0x0c, 0x0f, 0xc0, 0x05, 0x3d, - 0x0f, 0xc4, 0x04, 0x56, 0x0a, 0x8f, 0x0f, 0xce, 0x01, 0x39, 0x0f, 0xcd, - 0x04, 0x49, 0x05, 0xb8, 0x06, 0x0c, 0x0f, 0xc0, 0x05, 0x56, 0x0f, 0xc5, - 0x04, 0x4f, 0x0b, 0x61, 0x00, 0x15, 0x1f, 0xc0, 0x05, 0x81, 0x0f, 0xc5, - 0x04, 0x2c, 0x0b, 0x62, 0x00, 0xe4, 0x09, 0xa1, 0x00, 0x15, 0x1f, 0xc0, - 0x05, 0x6b, 0x0f, 0xc4, 0x04, 0x59, 0x0a, 0x8f, 0x0f, 0xce, 0x01, 0x39, - 0x0f, 0xcd, 0x04, 0x49, 0x05, 0xb8, 0x06, 0x0c, 0x0f, 0xc5, 0x04, 0x4f, - 0x0b, 0x61, 0x00, 0x59, 0x09, 0xc1, 0x0f, 0xc5, 0x01, 0x95, 0x0b, 0x52, - 0x0f, 0xc0, 0x04, 0xf3, 0x1f, 0xc0, 0x05, 0xdf, 0x0f, 0xc4, 0x04, 0x50, - 0x0f, 0xc5, 0x04, 0x34, 0x03, 0x3e, 0x0f, 0xf7, 0x00, 0x2d, 0x0f, 0xf9, - 0x08, 0x82, 0x0f, 0xc0, 0x05, 0x76, 0x0f, 0xc4, 0x04, 0x56, 0x0f, 0xcf, - 0x04, 0x40, 0x06, 0x0e, 0x0d, 0xcd, 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, - 0x0f, 0xc0, 0x05, 0x56, 0x0f, 0xc4, 0x04, 0x59, 0x0f, 0xcf, 0x04, 0x43, - 0x06, 0x0e, 0x0d, 0xcd, 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, 0x0f, 0xc0, - 0x05, 0x8e, 0x0f, 0xc4, 0x04, 0x56, 0x0f, 0xcf, 0x04, 0x3a, 0x0f, 0xce, - 0x01, 0x39, 0x0f, 0xcd, 0x04, 0x5c, 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, - 0x0f, 0xc0, 0x05, 0x9a, 0x0f, 0xc4, 0x04, 0x59, 0x0f, 0xcf, 0x04, 0x3d, - 0x0f, 0xce, 0x01, 0x39, 0x0f, 0xcd, 0x04, 0x5c, 0x05, 0xb8, 0x06, 0x0c, - 0x0f, 0xc0, 0x05, 0xa7, 0x0f, 0xc4, 0x04, 0x59, 0x0f, 0xcf, 0x04, 0x3a, - 0x0f, 0xce, 0x01, 0x39, 0x0f, 0xcd, 0x04, 0x5f, 0x0f, 0xcc, 0x00, 0xc4, - 0x05, 0xb9, 0x0f, 0xc0, 0x05, 0xb3, 0x0f, 0xc4, 0x04, 0x56, 0x0f, 0xcf, - 0x04, 0x3d, 0x0f, 0xce, 0x01, 0x39, 0x0f, 0xcd, 0x04, 0x5f, 0x05, 0xb8, - 0x04, 0x0c, 0x0f, 0xc0, 0x05, 0xbe, 0x0f, 0xc4, 0x04, 0x5c, 0x0a, 0x8f, - 0x0f, 0xce, 0x01, 0x39, 0x0f, 0xcd, 0x04, 0x4c, 0x05, 0xb8, 0x06, 0x0c, - 0x0f, 0xc0, 0x05, 0xc9, 0x0f, 0xc4, 0x04, 0x5f, 0x0a, 0x8f, 0x0f, 0xce, - 0x01, 0x39, 0x0f, 0xcd, 0x04, 0x4c, 0x05, 0xb8, 0x06, 0x0c, 0x0f, 0xc0, - 0x05, 0xd4, 0x0f, 0xc4, 0x04, 0x5c, 0x0f, 0xcf, 0x04, 0x40, 0x06, 0x0e, - 0x0d, 0xcd, 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, 0x0f, 0xc0, 0x05, 0x56, - 0x0f, 0xc4, 0x04, 0x5f, 0x0f, 0xcf, 0x04, 0x43, 0x06, 0x0e, 0x0d, 0xcd, - 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, 0x0f, 0xc0, 0x05, 0xec, 0x0f, 0xc4, - 0x04, 0x40, 0x0f, 0xcf, 0x04, 0x40, 0x0f, 0xce, 0x01, 0x39, 0x0f, 0xcd, - 0x04, 0x62, 0x0f, 0xcc, 0x00, 0xc4, 0x05, 0xb9, 0x0f, 0xc0, 0x05, 0xf8, - 0x0f, 0xc4, 0x04, 0x43, 0x0f, 0xcf, 0x04, 0x43, 0x0f, 0xce, 0x01, 0x39, - 0x0f, 0xcd, 0x04, 0x62, 0x05, 0xb8, 0x06, 0x0c, 0x0f, 0xc0, 0x06, 0x1a, - 0x0f, 0xc5, 0x04, 0x2c, 0x0b, 0x62, 0x00, 0xe4, 0x09, 0xa1, 0x00, 0x15, - 0x0f, 0xcf, 0x04, 0x6c, 0x0f, 0xce, 0x04, 0x62, 0x0f, 0xcd, 0x04, 0x6f, - 0x0f, 0xcc, 0x04, 0x4c, 0x1f, 0xcf, 0x04, 0x72, 0x1f, 0xcd, 0x04, 0x75, - 0x1f, 0xcc, 0x04, 0x49, 0x0d, 0xc4, 0x0f, 0xf6, 0x02, 0x74, 0x0d, 0x85, - 0x00, 0x36, 0x0d, 0xc4, 0x0d, 0x44, 0x0f, 0xf6, 0x02, 0x74, 0x0d, 0x05, - 0x00, 0x34, 0x0d, 0x44, 0x0f, 0xc0, 0x06, 0x2a, 0x0f, 0xc4, 0x04, 0x46, - 0x02, 0x37, 0x0f, 0xf7, 0x02, 0x99, 0x0f, 0xc4, 0x04, 0x65, 0x00, 0x37, - 0x0f, 0xc4, 0x04, 0x78, 0x02, 0xb7, 0x0f, 0xc4, 0x04, 0x78, 0x00, 0x35, - 0x0f, 0xc0, 0x06, 0x3a, 0x0f, 0xc4, 0x04, 0x49, 0x0f, 0xc5, 0x00, 0xaa, - 0x08, 0x3b, 0x0f, 0xc4, 0x04, 0x49, 0x00, 0x37, 0x0f, 0xc4, 0x04, 0x65, - 0x06, 0xb7, 0x0f, 0xc4, 0x04, 0x68, 0x00, 0x35, 0x0f, 0xc0, 0x06, 0x57, - 0x0f, 0xc4, 0x04, 0x68, 0x0f, 0xf7, 0x00, 0xbd, 0x0f, 0xc4, 0x00, 0xb3, - 0x05, 0xb7, 0x0f, 0xfb, 0x00, 0x58, 0x00, 0x08, 0x10, 0x48, 0x0f, 0xc4, - 0x04, 0x6b, 0x0c, 0x00, 0x0f, 0xc4, 0x04, 0x87, 0x0b, 0x21, 0x0c, 0x19, - 0x09, 0xc0, 0x0f, 0xc5, 0x04, 0x2d, 0x0f, 0xfb, 0x08, 0x1b, 0x0f, 0xfb, - 0x08, 0x1b, 0x0f, 0xf9, 0x08, 0x1b, 0x0f, 0xc0, 0x06, 0x7a, 0x0f, 0xc4, - 0x04, 0x6b, 0x0b, 0x21, 0x00, 0x14, 0x0f, 0xcf, 0x04, 0x7b, 0x1f, 0xcf, - 0x04, 0x7e, 0x0f, 0xce, 0x06, 0x28, 0x1f, 0xce, 0x04, 0x49, 0x0f, 0xc4, - 0x04, 0x46, 0x02, 0x37, 0x0f, 0xc4, 0x02, 0xc4, 0x00, 0x37, 0x0d, 0xc4, - 0x0f, 0xc5, 0x04, 0x46, 0x0f, 0xf7, 0x02, 0x74, 0x00, 0x36, 0x0d, 0xc4, - 0x0f, 0xcf, 0x04, 0x81, 0x0d, 0xc4, 0x0f, 0xf6, 0x02, 0x74, 0x0d, 0x85, - 0x00, 0x34, 0x0d, 0xc4, 0x0f, 0xc0, 0x04, 0xb6, 0x0f, 0xc4, 0x04, 0x6b, - 0x0b, 0x21, 0x00, 0x14, 0x1f, 0x39, 0x0f, 0xc4, 0x04, 0x84, 0x0f, 0xf7, - 0x00, 0xbd, 0x0f, 0xc4, 0x04, 0x46, 0x05, 0xb7, 0x0f, 0xfb, 0x00, 0x58, - 0x1f, 0x39, 0x0f, 0xc4, 0x04, 0x84, 0x0f, 0xf5, 0x00, 0xb2, 0x0f, 0xc0, - 0x04, 0xe6, 0x0f, 0xc4, 0x04, 0x6c, 0x0f, 0xc5, 0x04, 0x88, 0x07, 0x3e, - 0x0f, 0xf7, 0x00, 0x2d, 0x0f, 0xfb, 0x08, 0x15, 0x0f, 0xc8, 0x06, 0x9f, - 0x05, 0x3b, 0x0f, 0xf9, 0x08, 0x82, 0x0f, 0xc4, 0x02, 0x0e, 0x0b, 0x08, - 0x00, 0xb6, 0x00, 0x09, 0x0f, 0xf7, 0x02, 0x99, 0x0f, 0xc4, 0x00, 0xb6, - 0x00, 0x37, 0x01, 0xbb, 0x0f, 0xc4, 0x04, 0x97, 0x0f, 0xc5, 0x04, 0x9a, - 0x0f, 0xf7, 0x02, 0x74, 0x0f, 0xc4, 0x00, 0xc2, 0x00, 0x37, 0x01, 0xbb, - 0x0f, 0xc4, 0x00, 0xc2, 0x0f, 0xc5, 0x04, 0x94, 0x08, 0x3b, 0x0f, 0xc4, - 0x00, 0xb6, 0x06, 0xb7, 0x0f, 0xc4, 0x00, 0xb6, 0x06, 0xb7, 0x0f, 0xc4, - 0x00, 0xc5, 0x00, 0x37, 0x01, 0xbb, 0x0f, 0xc4, 0x04, 0xa3, 0x0b, 0x08, - 0x00, 0xb6, 0x00, 0x09, 0x0f, 0xc4, 0x00, 0xb9, 0x00, 0x37, 0x0f, 0xc4, - 0x00, 0xb6, 0x06, 0xb7, 0x0f, 0xc4, 0x00, 0xce, 0x00, 0x37, 0x01, 0xbb, - 0x0f, 0xc4, 0x02, 0x0e, 0x0b, 0x21, 0x0f, 0xc4, 0x04, 0xa3, 0x0b, 0x11, - 0x09, 0xc8, 0x00, 0xb6, 0x00, 0x09, 0x0f, 0xc4, 0x00, 0xbc, 0x00, 0x37, - 0x0f, 0xc4, 0x04, 0x97, 0x06, 0xb7, 0x0f, 0xc4, 0x00, 0xbf, 0x00, 0x37, - 0x01, 0xbb, 0x0f, 0xc4, 0x00, 0xbf, 0x0f, 0xc5, 0x04, 0x9a, 0x0f, 0xf7, - 0x02, 0x7d, 0x0f, 0xc4, 0x00, 0xb9, 0x0f, 0xf7, 0x02, 0x81, 0x0f, 0xc4, - 0x00, 0xc8, 0x00, 0x37, 0x01, 0xbb, 0x0f, 0xc4, 0x04, 0xa0, 0x0f, 0xc5, - 0x04, 0x9a, 0x0f, 0xf7, 0x02, 0x7d, 0x0f, 0xc4, 0x00, 0xbc, 0x06, 0xb7, - 0x0f, 0xc4, 0x00, 0xcb, 0x00, 0x37, 0x01, 0xbb, 0x0f, 0xc4, 0x04, 0x8e, - 0x0f, 0xc5, 0x04, 0x91, 0x0f, 0xf7, 0x02, 0x7d, 0x0f, 0xc4, 0x00, 0xd1, - 0x00, 0x37, 0x01, 0xbb, 0x0f, 0xc4, 0x04, 0x88, 0x0f, 0xc5, 0x04, 0x8b, - 0x0f, 0xf7, 0x02, 0x7d, 0x0f, 0xc4, 0x00, 0xd4, 0x00, 0x37, 0x01, 0xbb, - 0x0f, 0xcf, 0x0f, 0xff, 0x0f, 0xce, 0x02, 0xbb, 0x0f, 0xc4, 0x00, 0xce, - 0x0f, 0xc9, 0x0f, 0x5c, 0x0f, 0xca, 0x07, 0xf8, 0x0f, 0xcc, 0x0f, 0xf8, - 0x06, 0x3a, 0x01, 0xcd, 0x0f, 0xc4, 0x00, 0xce, 0x0f, 0xc9, 0x09, 0x9a, - 0x0f, 0xca, 0x07, 0xfe, 0x07, 0xcc, 0x0f, 0xcd, 0x0f, 0xe7, 0x06, 0x3b, - 0x0f, 0xc4, 0x00, 0xcb, 0x0f, 0xc9, 0x0a, 0x66, 0x00, 0x0a, 0x0f, 0xcc, - 0x00, 0x3f, 0x0f, 0xcd, 0x0f, 0xdf, 0x06, 0x3b, 0x0f, 0xc4, 0x00, 0xc8, - 0x0f, 0xc9, 0x0b, 0x33, 0x0f, 0xca, 0x07, 0xff, 0x0f, 0xcc, 0x00, 0x7f, - 0x0f, 0xcd, 0x0f, 0xbf, 0x06, 0x3b, 0x0f, 0xc4, 0x00, 0xbf, 0x01, 0xba, - 0x0d, 0xc0, 0x0f, 0xc4, 0x00, 0xbf, 0x0b, 0x0f, 0x0f, 0xce, 0x02, 0xbf, - 0x0f, 0xc4, 0x00, 0xc5, 0x0f, 0xc9, 0x08, 0xcd, 0x00, 0x0a, 0x0f, 0xcc, - 0x0f, 0x7e, 0x0f, 0xcd, 0x00, 0xf9, 0x06, 0x3b, 0x0f, 0xc4, 0x00, 0xc5, - 0x0f, 0xc9, 0x0b, 0x00, 0x00, 0xca, 0x0f, 0xcc, 0x07, 0xff, 0x0f, 0xcd, - 0x0b, 0xff, 0x06, 0x3b, 0x0f, 0xc4, 0x00, 0xd1, 0x0f, 0xc9, 0x08, 0x00, - 0x00, 0x0a, 0x1f, 0xc9, 0x0c, 0x00, 0x1f, 0xca, 0x07, 0xff, 0x0f, 0xcc, - 0x01, 0xef, 0x0f, 0xcd, 0x0e, 0xff, 0x06, 0x3b, 0x0f, 0xc4, 0x00, 0xd4, - 0x0f, 0xc9, 0x0c, 0x00, 0x00, 0x4a, 0x1f, 0xc9, 0x0e, 0x00, 0x0f, 0xcc, - 0x03, 0xef, 0x0f, 0xcd, 0x0d, 0xff, 0x06, 0x3b, 0x0f, 0xc4, 0x00, 0xd1, - 0x0f, 0xc9, 0x08, 0x00, 0x00, 0x0a, 0x1f, 0xca, 0x07, 0xff, 0x0f, 0xcc, - 0x0f, 0xfb, 0x0f, 0xcd, 0x0f, 0xfd, 0x06, 0x3b, 0x0f, 0xc4, 0x01, 0x99, - 0x0f, 0xc5, 0x01, 0x97, 0x0b, 0x61, 0x0d, 0xd5, 0x1f, 0xf8, 0x07, 0x93, - 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x00, 0xd2, 0x0f, 0xf8, 0x07, 0x99, - 0x10, 0xc0, 0x00, 0x00, 0x00, 0xd2, 0x1f, 0xf9, 0x07, 0x99, 0x0f, 0xfb, - 0x07, 0xab, 0x0f, 0xc4, 0x01, 0x98, 0x0f, 0xfa, 0x07, 0xa2, 0x0b, 0x0e, - 0x0f, 0xc5, 0x01, 0x81, 0x0f, 0x38, 0x00, 0x41, 0x0f, 0xf1, 0x0f, 0x15, - 0x0f, 0xe2, 0x0f, 0xf8, 0x0a, 0x64, 0x09, 0xa2, 0x0d, 0xa5, 0x0f, 0x38, - 0x09, 0xb2, 0x0f, 0xc4, 0x01, 0x97, 0x0d, 0xc0, 0x00, 0x0e, 0x07, 0x36, - 0x04, 0x0d, 0x01, 0x0a, 0x12, 0x8a, 0x02, 0x09, 0x12, 0x09, 0x00, 0x4c, - 0x00, 0x0b, 0x0d, 0xe2, 0x00, 0x21, 0x0f, 0xe4, 0x00, 0x81, 0x09, 0x95, - 0x10, 0x4e, 0x10, 0x8d, 0x10, 0x0c, 0x0f, 0xe4, 0x00, 0x50, 0x09, 0x95, - 0x10, 0x8e, 0x10, 0x8d, 0x10, 0x0c, 0x08, 0x24, 0x09, 0x95, 0x10, 0xce, - 0x1c, 0x8d, 0x10, 0x4b, 0x0f, 0xe4, 0x08, 0x04, 0x09, 0x95, 0x11, 0x0e, - 0x11, 0x0d, 0x10, 0x0c, 0x0f, 0xe4, 0x03, 0x0a, 0x09, 0x95, 0x14, 0x24, - 0x19, 0x94, 0x11, 0x4e, 0x0f, 0xe4, 0x04, 0x00, 0x09, 0x95, 0x11, 0x8e, - 0x1c, 0x4d, 0x10, 0x4c, 0x0f, 0xc4, 0x07, 0x3a, 0x0b, 0x21, 0x00, 0x15, - 0x0f, 0xc4, 0x01, 0x98, 0x0d, 0x80, 0x1f, 0xc4, 0x01, 0x91, 0x1d, 0x40, - 0x1f, 0xc4, 0x01, 0x83, 0x1d, 0x00, 0x1f, 0xf0, 0x0a, 0x11, 0x0f, 0x38, - 0x1c, 0xf2, 0x01, 0xe2, 0x0f, 0xc4, 0x07, 0xf5, 0x0b, 0x24, 0x09, 0xa1, - 0x00, 0x0f, 0x00, 0x54, 0x10, 0x4f, 0x00, 0x94, 0x14, 0x0f, 0x01, 0x14, - 0x11, 0x0f, 0x01, 0x54, 0x10, 0x8f, 0x01, 0x94, 0x1f, 0xcf, 0x04, 0x00, - 0x0d, 0xe1, 0x00, 0x14, 0x1f, 0x39, 0x0f, 0xf9, 0x07, 0xab, 0x0f, 0xf7, - 0x00, 0xbd, 0x07, 0x04, 0x00, 0x02, 0x0c, 0x42, 0x0f, 0xfa, 0x00, 0x58, - 0x0c, 0x82, 0x0d, 0xe2, 0x0d, 0x64, 0x1d, 0x24, 0x09, 0x8f, 0x0d, 0x84, - 0x0d, 0x48, 0x1d, 0x08, 0x0c, 0x02, 0x07, 0x34, 0x0a, 0x8e, 0x0f, 0xc4, - 0x04, 0x6c, 0x0f, 0xc8, 0x04, 0x88, 0x0f, 0xf5, 0x00, 0x71, 0x0b, 0xc9, - 0x0b, 0xca, 0x00, 0x21, 0x0c, 0x54, 0x1f, 0x39, 0x0c, 0x9f, 0x09, 0xe2, - 0x0c, 0x44, 0x0b, 0x8b, 0x0b, 0x25, 0x09, 0x82, 0x09, 0x8c, 0x0c, 0x14, - 0x10, 0x22, 0x0b, 0x25, 0x09, 0x82, 0x09, 0x8d, 0x0f, 0xc4, 0x01, 0x80, - 0x0b, 0x21, 0x00, 0x14, 0x0f, 0xe1, 0x0f, 0xff, 0x0c, 0xd9, 0x0c, 0xce, - 0x19, 0xce, 0x0d, 0x14, 0x1f, 0xf0, 0x0a, 0x12, 0x1d, 0xb2, 0x1f, 0xf0, - 0x0a, 0x13, 0x0f, 0x38, 0x1d, 0x72, 0x0b, 0x0f, 0x0f, 0xc4, 0x02, 0x0c, - 0x0b, 0x21, 0x00, 0xd9, 0x09, 0xc0, 0x09, 0xe1, 0x0f, 0xd2, 0x02, 0xd3, - 0x1f, 0xc0, 0x02, 0xc7, 0x0b, 0x04, 0x0d, 0xc2, 0x00, 0x02, 0x0f, 0x38, - 0x00, 0x02, 0x0f, 0xc4, 0x02, 0x0c, 0x0b, 0x03, 0x0f, 0xc4, 0x02, 0x11, - 0x0b, 0x03, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x03, 0x13, - 0x1f, 0x39, 0x00, 0x02, 0x0b, 0x21, 0x00, 0x59, 0x0f, 0xf8, 0x08, 0x3d, - 0x09, 0xc0, 0x0f, 0xf1, 0x0a, 0x1f, 0x0f, 0xc4, 0x04, 0x2c, 0x07, 0x36, - 0x0b, 0x08, 0x1a, 0x66, 0x19, 0xa6, 0x19, 0xa6, 0x19, 0xa6, 0x19, 0xaa, - 0x1f, 0xec, 0x02, 0x39, 0x1f, 0xee, 0x0d, 0x40, 0x1e, 0x21, 0x1c, 0x19, - 0x0f, 0xf6, 0x0b, 0x3f, 0x19, 0xc8, 0x0c, 0x4d, 0x0c, 0x8e, 0x0f, 0xfa, - 0x08, 0x7a, 0x0c, 0x09, 0x0a, 0x8f, 0x0d, 0x49, 0x00, 0xb6, 0x00, 0x08, - 0x0d, 0xa1, 0x05, 0xd1, 0x01, 0x36, 0x09, 0xc8, 0x00, 0x34, 0x0d, 0xc4, - 0x0f, 0xc4, 0x02, 0x0a, 0x0a, 0x8f, 0x0b, 0x85, 0x0b, 0x0e, 0x0f, 0xc4, - 0x04, 0x2b, 0x0f, 0xfb, 0x08, 0x94, 0x0d, 0xc4, 0x0a, 0xc0, 0x0a, 0xe1, - 0x0d, 0x92, 0x1f, 0xc0, 0x02, 0xd3, 0x0b, 0x04, 0x0f, 0xc5, 0x04, 0x2b, - 0x0f, 0xfe, 0x00, 0x2b, 0x0f, 0xf5, 0x00, 0x2d, 0x0f, 0xf7, 0x00, 0xbd, - 0x05, 0xb6, 0x0d, 0xc4, 0x0d, 0xb7, 0x05, 0x37, 0x0f, 0xf6, 0x00, 0xbd, - 0x0d, 0x44, 0x0d, 0x37, 0x00, 0x34, 0x0d, 0x44, 0x00, 0x0a, 0x00, 0x0b, - 0x01, 0x3e, 0x0f, 0xfd, 0x08, 0xb4, 0x00, 0x3f, 0x0b, 0x88, 0x00, 0x09, - 0x0c, 0x21, 0x02, 0xdf, 0x1f, 0xc9, 0x0f, 0xff, 0x0c, 0xa0, 0x09, 0xca, - 0x0c, 0x61, 0x0c, 0xd9, 0x09, 0xcb, 0x0c, 0xaa, 0x0c, 0xeb, 0x0f, 0xee, - 0x02, 0x40, 0x0c, 0xe1, 0x02, 0xdf, 0x0f, 0xc8, 0x0a, 0x7e, 0x1f, 0xc8, - 0x0a, 0xbe, 0x0c, 0x2e, 0x0f, 0x38, 0x0e, 0x01, 0x0f, 0xc4, 0x00, 0x5c, - 0x0f, 0xc5, 0x01, 0xb8, 0x0f, 0xfb, 0x08, 0xa4, 0x0f, 0xc4, 0x00, 0x60, - 0x0f, 0xc5, 0x01, 0xb9, 0x0f, 0xfb, 0x08, 0xa4, 0x0f, 0xc4, 0x00, 0x64, - 0x0f, 0xc5, 0x01, 0xba, 0x0f, 0xfb, 0x08, 0xa4, 0x0f, 0xc4, 0x00, 0x68, - 0x0f, 0xc5, 0x01, 0xbb, 0x0f, 0xfb, 0x08, 0xa4, 0x0f, 0xc5, 0x05, 0x60, - 0x0f, 0xc4, 0x01, 0xb8, 0x0b, 0x03, 0x0f, 0xc4, 0x01, 0xb9, 0x0b, 0x03, - 0x0f, 0xc5, 0x05, 0x62, 0x0f, 0xc4, 0x01, 0xba, 0x0b, 0x03, 0x0f, 0xc4, - 0x01, 0xbb, 0x0f, 0x38, 0x0b, 0x03, 0x07, 0xb7, 0x1f, 0xf9, 0x08, 0xf8, - 0x0f, 0xc4, 0x01, 0x34, 0x00, 0x02, 0x00, 0x02, 0x0f, 0xc4, 0x01, 0x61, - 0x0f, 0xc0, 0x00, 0x2d, 0x0f, 0xf9, 0x09, 0x02, 0x0f, 0xc4, 0x01, 0x34, - 0x00, 0x02, 0x00, 0x02, 0x0f, 0xc4, 0x01, 0x61, 0x0f, 0xc0, 0x00, 0xd9, - 0x0f, 0xf9, 0x09, 0x02, 0x0f, 0xc4, 0x01, 0x34, 0x0f, 0xf0, 0x05, 0x01, - 0x0b, 0xb2, 0x0f, 0xf0, 0x05, 0x00, 0x0b, 0xb2, 0x0f, 0xc4, 0x01, 0x60, - 0x0f, 0xf0, 0x05, 0x02, 0x00, 0x00, 0x00, 0x32, 0x0f, 0xf0, 0x0a, 0x03, - 0x00, 0x32, 0x0f, 0xc4, 0x01, 0x61, 0x0f, 0xf0, 0x0a, 0x02, 0x0b, 0x32, - 0x0f, 0xc4, 0x01, 0xb0, 0x0f, 0xc0, 0x00, 0x64, 0x00, 0x08, 0x0f, 0xfa, - 0x19, 0x6d, 0x00, 0x09, 0x0f, 0xf7, 0x02, 0xb6, 0x0f, 0xfb, 0x12, 0xcf, - 0x0f, 0xc4, 0x06, 0x8d, 0x0b, 0x21, 0x0f, 0xd3, 0x00, 0x30, 0x0f, 0xc4, - 0x06, 0x94, 0x09, 0xe1, 0x0b, 0xa0, 0x0f, 0xf0, 0x03, 0x2a, 0x09, 0xf2, - 0x00, 0x21, 0x1f, 0xe1, 0x1f, 0xff, 0x0b, 0x99, 0x0f, 0xf0, 0x03, 0x29, - 0x09, 0xf2, 0x0f, 0xc4, 0x01, 0x9e, 0x00, 0x02, 0x0f, 0xc4, 0x01, 0xac, - 0x00, 0x00, 0x0f, 0xc4, 0x01, 0xaf, 0x00, 0x00, 0x0f, 0xc4, 0x05, 0x86, - 0x00, 0x00, 0x04, 0x05, 0x0f, 0xc1, 0x00, 0x29, 0x02, 0xba, 0x00, 0x08, - 0x0f, 0x39, 0x0f, 0xc4, 0x06, 0x94, 0x0f, 0xf0, 0x03, 0x2a, 0x0b, 0xb2, - 0x0f, 0xf0, 0x03, 0x29, 0x0b, 0xb2, 0x0f, 0xc4, 0x06, 0x8d, 0x0f, 0xf0, - 0x03, 0x2b, 0x0f, 0xc0, 0x00, 0x30, 0x0f, 0xf2, 0x00, 0x30, 0x0f, 0xf7, - 0x0b, 0xc3, 0x0f, 0xc8, 0x0a, 0xa1, 0x07, 0x36, 0x00, 0x49, 0x1f, 0xc8, - 0x06, 0xa9, 0x00, 0xb6, 0x10, 0x09, 0x0f, 0xc8, 0x1f, 0xe7, 0x01, 0x37, - 0x0f, 0xc4, 0x05, 0x5c, 0x00, 0x37, 0x09, 0x36, 0x04, 0x08, 0x0f, 0xc4, - 0x06, 0x01, 0x04, 0x00, 0x04, 0x04, 0x0f, 0xc0, 0x00, 0x2a, 0x0f, 0xc4, - 0x01, 0xa0, 0x00, 0x00, 0x08, 0xc4, 0x00, 0x80, 0x0f, 0xc8, 0x00, 0x3f, - 0x0f, 0xf7, 0x05, 0x23, 0x0f, 0x39, 0x08, 0xc4, 0x0b, 0x21, 0x00, 0x54, - 0x1f, 0xf9, 0x09, 0x82, 0x0f, 0x38, 0x09, 0xc0, 0x0f, 0xf7, 0x05, 0x37, - 0x0f, 0x39, 0x04, 0x3b, 0x0f, 0xfb, 0x09, 0x7b, 0x0f, 0x39, 0x04, 0x3b, - 0x07, 0x37, 0x1f, 0xf9, 0x09, 0x90, 0x0f, 0xf6, 0x05, 0x5c, 0x00, 0x48, - 0x0f, 0xfb, 0x0d, 0xb2, 0x0f, 0xc4, 0x01, 0xa2, 0x00, 0x21, 0x0b, 0x15, - 0x1f, 0xf9, 0x09, 0xae, 0x0f, 0xc4, 0x01, 0x5f, 0x0b, 0x21, 0x00, 0x59, - 0x09, 0xc0, 0x06, 0x53, 0x1f, 0xf9, 0x09, 0xa4, 0x0f, 0xf7, 0x05, 0x37, - 0x01, 0x38, 0x00, 0xc8, 0x09, 0xe2, 0x00, 0x64, 0x09, 0xa2, 0x00, 0x63, - 0x02, 0x3a, 0x09, 0x88, 0x0f, 0xf7, 0x0c, 0x13, 0x0f, 0xf5, 0x0c, 0x97, - 0x08, 0xc4, 0x0b, 0x21, 0x00, 0x54, 0x09, 0xe2, 0x00, 0x64, 0x09, 0xa2, - 0x00, 0x63, 0x02, 0x3a, 0x09, 0x88, 0x0f, 0xf7, 0x0c, 0x13, 0x0f, 0xf7, - 0x0c, 0x97, 0x0f, 0xfb, 0x09, 0x7b, 0x04, 0x04, 0x0f, 0xc5, 0x01, 0x5f, - 0x0b, 0x21, 0x0f, 0xd5, 0x00, 0x40, 0x1f, 0xf8, 0x09, 0xc7, 0x10, 0x01, - 0x0f, 0x39, 0x0f, 0xf0, 0x05, 0x0c, 0x0f, 0x38, 0x00, 0xb2, 0x04, 0x3b, - 0x0f, 0xf7, 0x0c, 0x13, 0x0f, 0xf7, 0x0c, 0x97, 0x07, 0x37, 0x1f, 0xf9, - 0x09, 0xd6, 0x0f, 0xf6, 0x05, 0x5c, 0x00, 0x48, 0x09, 0x3b, 0x04, 0x04, - 0x0f, 0xc0, 0x00, 0x41, 0x08, 0xc4, 0x0b, 0x21, 0x00, 0x54, 0x09, 0xe2, - 0x00, 0x64, 0x09, 0xa2, 0x00, 0x63, 0x02, 0x3a, 0x09, 0x88, 0x0f, 0xfb, - 0x09, 0x7b, 0x0f, 0x39, 0x04, 0x3b, 0x07, 0xba, 0x00, 0xc8, 0x0f, 0xc4, - 0x01, 0xa0, 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xf9, 0x09, 0xf3, 0x0f, 0xfb, - 0x0d, 0xf5, 0x0f, 0xf9, 0x0a, 0x38, 0x0f, 0xfb, 0x0d, 0xb2, 0x0f, 0xfb, - 0x0e, 0x05, 0x0f, 0xc4, 0x01, 0xb6, 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xf9, - 0x0a, 0xc3, 0x0f, 0xc4, 0x01, 0x9f, 0x0b, 0x22, 0x0f, 0xe4, 0x00, 0xc0, - 0x09, 0xa1, 0x0f, 0xd4, 0x00, 0xc0, 0x1f, 0xf9, 0x0a, 0x15, 0x0f, 0xd4, - 0x00, 0x40, 0x1f, 0xf9, 0x0a, 0x15, 0x00, 0x14, 0x1f, 0x39, 0x0f, 0xc4, - 0x01, 0xa1, 0x0b, 0x21, 0x00, 0x55, 0x1f, 0x38, 0x09, 0xc0, 0x0f, 0xf9, - 0x0a, 0x38, 0x0f, 0xc4, 0x01, 0x42, 0x0b, 0x08, 0x0f, 0xc4, 0x01, 0xa7, - 0x0b, 0x21, 0x0f, 0xd4, 0x08, 0x00, 0x1f, 0xf9, 0x0a, 0x2c, 0x0c, 0x14, - 0x1f, 0xf9, 0x0a, 0x99, 0x0f, 0xc4, 0x01, 0xa8, 0x0b, 0x21, 0x0f, 0xd4, - 0x08, 0x00, 0x1f, 0xf9, 0x0a, 0x2c, 0x0c, 0x14, 0x1f, 0xf9, 0x0a, 0x99, - 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0xa6, 0x0b, 0x21, 0x00, 0x54, 0x1f, 0xf8, - 0x0a, 0x38, 0x09, 0xc0, 0x0f, 0xc4, 0x01, 0xa1, 0x0f, 0x38, 0x01, 0x00, - 0x0f, 0xc4, 0x01, 0xa3, 0x00, 0x00, 0x0f, 0xc4, 0x01, 0xa2, 0x00, 0x00, - 0x0f, 0xc4, 0x01, 0xa1, 0x01, 0x00, 0x0f, 0xc4, 0x01, 0xa6, 0x00, 0xc0, - 0x0f, 0xc4, 0x01, 0xa7, 0x0f, 0xc0, 0x08, 0x00, 0x0f, 0xc4, 0x01, 0xa8, - 0x0f, 0xc0, 0x08, 0x00, 0x07, 0xb7, 0x01, 0x48, 0x13, 0xc8, 0x0f, 0xc4, - 0x01, 0xa0, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x09, 0xcb, 0x09, 0xe1, - 0x0c, 0x16, 0x1f, 0xf9, 0x0a, 0xda, 0x00, 0x54, 0x10, 0x08, 0x00, 0x94, - 0x16, 0x48, 0x00, 0xd4, 0x1f, 0xc8, 0x1f, 0xe7, 0x01, 0x14, 0x1f, 0xc8, - 0x00, 0x32, 0x01, 0x54, 0x1f, 0xc8, 0x1f, 0xce, 0x01, 0x94, 0x1f, 0xc8, - 0x00, 0x4b, 0x01, 0xd4, 0x1f, 0xc8, 0x1f, 0xb5, 0x02, 0x14, 0x1f, 0xc8, - 0x00, 0x64, 0x02, 0x54, 0x1f, 0xc8, 0x1f, 0x9c, 0x02, 0x94, 0x1f, 0xc8, - 0x00, 0x7d, 0x02, 0xd4, 0x1f, 0xc8, 0x1f, 0x83, 0x03, 0x14, 0x1f, 0xc8, - 0x00, 0x96, 0x03, 0x54, 0x1f, 0xc8, 0x1f, 0x6a, 0x03, 0x94, 0x1f, 0xc8, - 0x00, 0xaf, 0x03, 0xd4, 0x1f, 0xc8, 0x1f, 0x51, 0x0f, 0xfb, 0x19, 0x85, - 0x07, 0xb7, 0x0f, 0xc9, 0x00, 0x2d, 0x1f, 0xc9, 0x00, 0xd9, 0x0c, 0x61, - 0x0c, 0x1b, 0x09, 0xc8, 0x0c, 0x21, 0x0f, 0xd7, 0x1f, 0xff, 0x10, 0x08, - 0x0f, 0xf0, 0x0a, 0x02, 0x0c, 0x32, 0x0f, 0xc4, 0x01, 0x61, 0x0f, 0x38, - 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0x42, 0x0f, 0xf6, 0x0d, 0x7c, 0x00, 0x48, - 0x04, 0xc4, 0x0f, 0xc5, 0x05, 0x6e, 0x04, 0xb7, 0x0f, 0xc4, 0x01, 0xaa, - 0x00, 0x00, 0x0f, 0xc4, 0x06, 0x96, 0x0f, 0xc5, 0x05, 0x71, 0x04, 0xb7, - 0x0f, 0xc4, 0x01, 0xab, 0x00, 0x00, 0x04, 0x04, 0x0f, 0xc0, 0x00, 0x2b, - 0x08, 0xc4, 0x02, 0x80, 0x0f, 0xc8, 0x00, 0x40, 0x0f, 0xf7, 0x05, 0x23, - 0x07, 0xb7, 0x0f, 0xc8, 0x00, 0x2d, 0x1f, 0xc8, 0x00, 0xd9, 0x0f, 0xf0, - 0x0a, 0x02, 0x0c, 0x32, 0x00, 0x08, 0x0f, 0xfa, 0x19, 0x6d, 0x00, 0x09, - 0x0f, 0x39, 0x0f, 0xc4, 0x01, 0x62, 0x0b, 0x22, 0x00, 0x63, 0x09, 0x80, - 0x02, 0x36, 0x04, 0xc4, 0x0f, 0xf7, 0x00, 0x8f, 0x05, 0x84, 0x0f, 0xf6, - 0x0d, 0x7c, 0x00, 0x08, 0x08, 0xc4, 0x01, 0x80, 0x0f, 0xc8, 0x00, 0x3f, - 0x0f, 0xf7, 0x05, 0x23, 0x0f, 0xc4, 0x01, 0xa0, 0x0f, 0x38, 0x00, 0x00, - 0x01, 0x3a, 0x00, 0x88, 0x0f, 0x39, 0x00, 0x44, 0x0c, 0x00, 0x04, 0x3b, - 0x0f, 0xf7, 0x0c, 0x13, 0x0f, 0xf7, 0x0c, 0x97, 0x0f, 0xc8, 0x00, 0x2b, - 0x03, 0x3b, 0x1f, 0xf9, 0x0b, 0x02, 0x0f, 0xf0, 0x0a, 0x07, 0x01, 0x32, - 0x0f, 0xc4, 0x06, 0xe9, 0x0f, 0xc5, 0x07, 0x51, 0x04, 0xb7, 0x0f, 0xc4, - 0x06, 0xec, 0x0f, 0xc5, 0x07, 0x54, 0x04, 0xb7, 0x0f, 0xc4, 0x06, 0xe3, - 0x0f, 0xc5, 0x07, 0x3f, 0x04, 0xb7, 0x0f, 0xc4, 0x06, 0xe6, 0x0f, 0xc5, - 0x07, 0x42, 0x04, 0xb7, 0x0f, 0xf9, 0x0b, 0x16, 0x0f, 0xc4, 0x06, 0xf5, - 0x0f, 0xc5, 0x07, 0x51, 0x04, 0xb7, 0x0f, 0xc4, 0x06, 0xf8, 0x0f, 0xc5, - 0x07, 0x54, 0x04, 0xb7, 0x0f, 0xc4, 0x06, 0xef, 0x0f, 0xc5, 0x07, 0x3f, - 0x04, 0xb7, 0x0f, 0xc4, 0x06, 0xf2, 0x0f, 0xc5, 0x07, 0x42, 0x04, 0xb7, - 0x07, 0x37, 0x1f, 0xf9, 0x0b, 0x2d, 0x0f, 0xf7, 0x09, 0x2f, 0x0f, 0xf7, - 0x09, 0x62, 0x0f, 0xf7, 0x09, 0xc3, 0x0f, 0xc8, 0x00, 0x2b, 0x03, 0x3b, - 0x1f, 0xfb, 0x0b, 0xfa, 0x00, 0x44, 0x0f, 0xfa, 0x0c, 0x0e, 0x0b, 0x08, - 0x0f, 0xf6, 0x05, 0x5c, 0x00, 0x48, 0x0f, 0xf9, 0x0b, 0x4b, 0x0f, 0xf7, - 0x09, 0x2f, 0x0f, 0xf7, 0x09, 0xc3, 0x0f, 0xfb, 0x0b, 0xff, 0x0f, 0xf7, - 0x09, 0x2f, 0x0f, 0xf7, 0x09, 0x62, 0x0f, 0xc8, 0x00, 0x2b, 0x03, 0x3b, - 0x1f, 0xf7, 0x0a, 0x0a, 0x0f, 0xfb, 0x0b, 0xff, 0x0f, 0xc8, 0x00, 0x2b, - 0x03, 0x3b, 0x1f, 0xf7, 0x0a, 0x72, 0x0f, 0xfb, 0x17, 0x68, 0x0f, 0xfb, - 0x0b, 0xff, 0x00, 0x44, 0x0f, 0xfa, 0x0c, 0x0e, 0x0b, 0x08, 0x0f, 0xc4, - 0x01, 0x9e, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x00, 0x14, - 0x10, 0x40, 0x0f, 0x39, 0x0f, 0xc8, 0x00, 0x50, 0x08, 0xbb, 0x07, 0xba, - 0x01, 0x08, 0x0f, 0xc8, 0x00, 0x50, 0x03, 0x3b, 0x1f, 0xf9, 0x0b, 0x7e, - 0x0f, 0xc4, 0x01, 0x9e, 0x07, 0x36, 0x0b, 0x08, 0x1c, 0x27, 0x19, 0xa7, - 0x19, 0x88, 0x0c, 0x21, 0x0f, 0xd2, 0x00, 0x6f, 0x1f, 0xc4, 0x01, 0xb7, - 0x1f, 0xf8, 0x0b, 0x75, 0x10, 0x40, 0x0f, 0xc4, 0x05, 0xe8, 0x0b, 0x21, - 0x00, 0x14, 0x14, 0x04, 0x1f, 0xc0, 0x00, 0x2b, 0x1f, 0x39, 0x07, 0xba, - 0x01, 0x48, 0x0f, 0xf0, 0x0a, 0x07, 0x00, 0x32, 0x0f, 0xc4, 0x01, 0x9e, - 0x0f, 0x38, 0x00, 0x02, 0x0f, 0xc4, 0x01, 0x9e, 0x0f, 0xc5, 0x07, 0x5e, - 0x0b, 0xa1, 0x0b, 0xd2, 0x11, 0x3a, 0x11, 0x08, 0x0f, 0x39, 0x0f, 0xc8, - 0x00, 0x3c, 0x08, 0xbb, 0x0f, 0xc4, 0x01, 0x7f, 0x0b, 0x21, 0x00, 0x00, - 0x00, 0x15, 0x0f, 0xc4, 0x01, 0xbc, 0x0b, 0x21, 0x00, 0x19, 0x10, 0x59, - 0x09, 0xc0, 0x09, 0xe1, 0x00, 0x93, 0x14, 0x04, 0x1f, 0xc0, 0x00, 0x32, - 0x0f, 0xc8, 0x00, 0x3c, 0x03, 0x3b, 0x1f, 0x39, 0x0f, 0xc4, 0x01, 0xb0, - 0x0f, 0xc0, 0x00, 0x96, 0x0f, 0xc4, 0x01, 0x80, 0x0b, 0x21, 0x00, 0x15, - 0x1f, 0xc4, 0x01, 0x83, 0x1f, 0xfa, 0x04, 0x60, 0x10, 0x40, 0x0f, 0x39, - 0x0f, 0xc4, 0x01, 0x78, 0x0b, 0x21, 0x0f, 0xd3, 0x00, 0xfa, 0x1f, 0xf9, - 0x0b, 0xcd, 0x0f, 0xc5, 0x01, 0xbe, 0x0f, 0xc4, 0x01, 0xbd, 0x0b, 0x21, - 0x00, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x0f, 0xd3, 0x00, 0x28, 0x1f, 0x39, - 0x0f, 0xd2, 0x00, 0x3c, 0x1f, 0xc0, 0x00, 0x28, 0x10, 0x01, 0x0f, 0xc4, - 0x05, 0x86, 0x0b, 0x21, 0x00, 0x93, 0x1b, 0x61, 0x10, 0x59, 0x19, 0xc1, - 0x0b, 0x61, 0x02, 0x93, 0x1f, 0x39, 0x01, 0x38, 0x01, 0x08, 0x0f, 0xc8, - 0x00, 0x3c, 0x08, 0xbb, 0x0f, 0xfb, 0x0b, 0xac, 0x07, 0x37, 0x00, 0x48, - 0x11, 0x08, 0x0c, 0x21, 0x0f, 0xc4, 0x01, 0x2e, 0x0b, 0x20, 0x09, 0xc2, - 0x09, 0xc8, 0x00, 0x21, 0x0b, 0x19, 0x09, 0xc2, 0x07, 0xba, 0x00, 0x88, - 0x0f, 0xc8, 0x00, 0x3c, 0x0f, 0xf7, 0x00, 0x3a, 0x1f, 0xf9, 0x0b, 0xed, - 0x0f, 0xd5, 0x00, 0x32, 0x1f, 0xf9, 0x0b, 0xf2, 0x0f, 0x39, 0x02, 0x3a, - 0x00, 0x48, 0x0f, 0xfb, 0x11, 0x41, 0x0f, 0x39, 0x01, 0x3a, 0x01, 0x08, - 0x02, 0x3a, 0x00, 0x08, 0x02, 0xba, 0x00, 0x08, 0x0f, 0x39, 0x0f, 0x39, - 0x0f, 0xf7, 0x0a, 0x0a, 0x0f, 0xf7, 0x0a, 0x72, 0x0f, 0x39, 0x09, 0x3b, - 0x0f, 0xfb, 0x0c, 0xf8, 0x0f, 0xfb, 0x13, 0xae, 0x0f, 0xfb, 0x0c, 0x26, - 0x0f, 0xfb, 0x02, 0x35, 0x04, 0x3b, 0x0f, 0xf7, 0x0c, 0x13, 0x0f, 0xf7, - 0x0c, 0x97, 0x0f, 0x39, 0x00, 0x04, 0x0c, 0x00, 0x09, 0x3b, 0x0f, 0xf6, - 0x00, 0x3a, 0x00, 0x48, 0x1f, 0x39, 0x02, 0x14, 0x1f, 0x39, 0x0f, 0xc4, - 0x05, 0x86, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc8, 0x09, 0xe1, 0x02, 0x96, - 0x1f, 0xf9, 0x0c, 0x22, 0x0f, 0x38, 0x0c, 0x00, 0x04, 0x04, 0x00, 0x05, - 0x0b, 0x40, 0x0f, 0x39, 0x0f, 0xc4, 0x00, 0x56, 0x02, 0x37, 0x0f, 0xc5, - 0x00, 0x56, 0x04, 0xb7, 0x0f, 0xc4, 0x00, 0x74, 0x04, 0xb7, 0x0f, 0xc4, - 0x00, 0xe9, 0x00, 0x37, 0x03, 0x37, 0x0f, 0xc4, 0x05, 0xd7, 0x07, 0x05, - 0x0b, 0x83, 0x0b, 0x83, 0x0f, 0xc3, 0x07, 0xff, 0x0f, 0xf7, 0x01, 0x39, - 0x0f, 0xc4, 0x00, 0xec, 0x0f, 0xc5, 0x00, 0xef, 0x04, 0xb7, 0x0f, 0xc4, - 0x00, 0xec, 0x00, 0x37, 0x0f, 0xc4, 0x00, 0xe9, 0x0f, 0xf7, 0x02, 0x93, - 0x0f, 0xc4, 0x00, 0xef, 0x02, 0xb7, 0x0f, 0xc4, 0x00, 0xf2, 0x00, 0x37, - 0x0f, 0xc4, 0x06, 0xb1, 0x0f, 0xf7, 0x02, 0x81, 0x01, 0x36, 0x03, 0x08, - 0x03, 0xb7, 0x0f, 0xc4, 0x01, 0x64, 0x0f, 0x38, 0x0c, 0x00, 0x0f, 0xc4, - 0x01, 0xa2, 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xfb, 0x0d, 0xa1, 0x0f, 0xf1, - 0x05, 0x0d, 0x0a, 0x48, 0x0f, 0xf1, 0x05, 0x0e, 0x0f, 0xc4, 0x01, 0x9a, - 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0x9b, 0x0a, 0x49, 0x0f, 0xf6, 0x03, 0xcd, - 0x0c, 0x40, 0x0f, 0xc4, 0x01, 0x72, 0x0c, 0x00, 0x0f, 0xc4, 0x07, 0x06, - 0x0b, 0x21, 0x00, 0x14, 0x1f, 0xc4, 0x01, 0x64, 0x1c, 0x21, 0x1b, 0x19, - 0x19, 0xc8, 0x0f, 0xf6, 0x00, 0x47, 0x00, 0x4b, 0x10, 0x08, 0x0f, 0xc4, - 0x01, 0x83, 0x0b, 0x21, 0x00, 0x15, 0x10, 0x08, 0x0f, 0xc4, 0x01, 0x9c, - 0x0c, 0x21, 0x0b, 0x19, 0x09, 0xc0, 0x09, 0xc9, 0x0f, 0xc4, 0x01, 0x9d, - 0x0b, 0x21, 0x0c, 0x51, 0x09, 0xca, 0x0f, 0xc4, 0x01, 0xbf, 0x0b, 0x21, - 0x0c, 0x91, 0x09, 0xc8, 0x0c, 0x80, 0x0f, 0xf0, 0x05, 0x02, 0x07, 0x36, - 0x0c, 0xb2, 0x1f, 0xc4, 0x00, 0xd7, 0x1a, 0x85, 0x1b, 0x8b, 0x1b, 0x83, - 0x1b, 0x83, 0x1c, 0x83, 0x1c, 0xca, 0x0f, 0xf6, 0x00, 0x42, 0x01, 0xcb, - 0x1f, 0xf0, 0x05, 0x08, 0x1c, 0xb2, 0x0f, 0xc4, 0x01, 0xa9, 0x0c, 0x00, - 0x0f, 0xfb, 0x0e, 0x59, 0x0f, 0xfb, 0x13, 0x6f, 0x0f, 0xfb, 0x0e, 0xd8, - 0x0f, 0xc4, 0x01, 0xa9, 0x0b, 0x09, 0x00, 0xb6, 0x00, 0x08, 0x0f, 0xc8, - 0x1f, 0xe8, 0x01, 0x37, 0x0f, 0xc4, 0x00, 0xda, 0x00, 0x37, 0x03, 0x37, - 0x0f, 0xc4, 0x06, 0xb1, 0x05, 0xb7, 0x0f, 0xf7, 0x01, 0x39, 0x0f, 0xc4, - 0x00, 0xdd, 0x00, 0x37, 0x0f, 0xc4, 0x01, 0xa9, 0x0b, 0x08, 0x00, 0x09, - 0x0c, 0x21, 0x02, 0xdf, 0x1f, 0xc9, 0x0f, 0xff, 0x0f, 0xc4, 0x01, 0x44, - 0x0b, 0x21, 0x0c, 0x20, 0x09, 0xc2, 0x09, 0xc8, 0x0b, 0x21, 0x0c, 0x59, - 0x09, 0xc0, 0x09, 0xc9, 0x0f, 0xc5, 0x02, 0x1f, 0x0f, 0xc4, 0x02, 0x21, - 0x02, 0xbe, 0x0f, 0xf7, 0x00, 0x2d, 0x0c, 0x03, 0x0c, 0x43, 0x0f, 0xf1, - 0x0a, 0x18, 0x08, 0x84, 0x0b, 0x21, 0x0f, 0xd9, 0x00, 0x5c, 0x09, 0xc4, - 0x0a, 0x40, 0x0f, 0xf1, 0x0a, 0x19, 0x0f, 0xd9, 0x00, 0x60, 0x09, 0xc4, - 0x0a, 0x40, 0x0f, 0xf1, 0x0a, 0x1a, 0x0f, 0xd9, 0x00, 0x64, 0x09, 0xc4, - 0x0a, 0x40, 0x0f, 0xf1, 0x0a, 0x1b, 0x0f, 0xd9, 0x00, 0x68, 0x09, 0xc4, - 0x0a, 0x40, 0x0f, 0x39, 0x0f, 0xc4, 0x01, 0x34, 0x0b, 0x88, 0x0b, 0x89, - 0x0f, 0xf0, 0x05, 0x01, 0x0c, 0x32, 0x0f, 0xf0, 0x05, 0x00, 0x0c, 0x72, - 0x0f, 0xf0, 0x05, 0x07, 0x0c, 0x32, 0x0f, 0xf0, 0x05, 0x06, 0x0f, 0x38, - 0x0c, 0x72, 0x0f, 0xfb, 0x0d, 0xb2, 0x0f, 0xc4, 0x01, 0x9f, 0x0b, 0x22, - 0x0f, 0xf1, 0x0a, 0x04, 0x0a, 0x62, 0x00, 0x48, 0x00, 0x09, 0x00, 0x21, - 0x0f, 0xc4, 0x01, 0xad, 0x0b, 0x21, 0x00, 0xd9, 0x09, 0xca, 0x09, 0xe1, - 0x03, 0x12, 0x19, 0xca, 0x0c, 0x80, 0x04, 0x24, 0x00, 0x21, 0x09, 0x94, - 0x1f, 0xf9, 0x0d, 0x46, 0x00, 0x49, 0x08, 0x24, 0x09, 0x94, 0x1f, 0xf8, - 0x0d, 0x46, 0x10, 0x08, 0x03, 0xe4, 0x0c, 0xa1, 0x09, 0x95, 0x09, 0x80, - 0x10, 0x08, 0x0f, 0xe4, 0x00, 0x80, 0x09, 0x94, 0x1f, 0xf9, 0x0d, 0x46, - 0x00, 0x49, 0x0f, 0xe4, 0x00, 0x40, 0x09, 0x94, 0x10, 0x08, 0x0f, 0xc4, - 0x01, 0x42, 0x00, 0x21, 0x0b, 0x95, 0x10, 0x08, 0x0b, 0x95, 0x10, 0x08, - 0x08, 0x84, 0x0b, 0x0a, 0x0c, 0xa1, 0x0f, 0xc4, 0x01, 0xa4, 0x0b, 0x15, - 0x10, 0x08, 0x1c, 0x80, 0x00, 0x21, 0x0c, 0x54, 0x1f, 0xf9, 0x0d, 0x57, - 0x0c, 0x14, 0x1f, 0xf9, 0x0d, 0x57, 0x0f, 0xc4, 0x01, 0xaf, 0x0b, 0x0b, - 0x0f, 0xc5, 0x01, 0xae, 0x0c, 0xe1, 0x0b, 0x56, 0x00, 0x00, 0x0f, 0x38, - 0x1c, 0xc1, 0x0f, 0xc4, 0x01, 0xaf, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, - 0x09, 0xe1, 0x0f, 0xc4, 0x01, 0xb0, 0x0b, 0x17, 0x1f, 0x39, 0x0f, 0xc4, - 0x01, 0xa5, 0x0c, 0x67, 0x09, 0xa2, 0x0c, 0x25, 0x09, 0x80, 0x0c, 0x21, - 0x00, 0x15, 0x01, 0x48, 0x01, 0x38, 0x11, 0x88, 0x0f, 0x39, 0x0f, 0xc5, - 0x01, 0xa4, 0x08, 0x84, 0x00, 0x61, 0x00, 0xe2, 0x0b, 0x19, 0x09, 0xe4, - 0x09, 0x80, 0x09, 0x81, 0x0f, 0xf1, 0x0a, 0x04, 0x0f, 0xc5, 0x01, 0xb1, - 0x0f, 0xc4, 0x01, 0x9f, 0x0a, 0x48, 0x0c, 0x01, 0x0c, 0x22, 0x0f, 0xe4, - 0x00, 0xf0, 0x09, 0x80, 0x0f, 0xe4, 0x00, 0xc0, 0x09, 0xa1, 0x0f, 0xd5, - 0x00, 0xc0, 0x0f, 0x39, 0x00, 0x61, 0x00, 0xe2, 0x0f, 0xc4, 0x01, 0xa4, - 0x0b, 0x19, 0x09, 0xe4, 0x09, 0x80, 0x08, 0x84, 0x09, 0x80, 0x09, 0xa1, - 0x00, 0x14, 0x1f, 0xc4, 0x01, 0x82, 0x1b, 0x21, 0x10, 0x59, 0x19, 0xc0, - 0x0f, 0xc4, 0x01, 0x9f, 0x0f, 0xc0, 0x00, 0xf0, 0x0f, 0xe1, 0x00, 0xc0, - 0x0f, 0xd5, 0x00, 0xc0, 0x0f, 0x39, 0x00, 0x61, 0x00, 0xe2, 0x08, 0x84, - 0x0b, 0x19, 0x09, 0xe4, 0x0f, 0xf0, 0x0a, 0x05, 0x07, 0xb6, 0x09, 0xb2, - 0x0f, 0xcb, 0x00, 0xac, 0x1f, 0xcb, 0x02, 0xb0, 0x0f, 0xf0, 0x0a, 0x06, - 0x0c, 0xf2, 0x0f, 0x39, 0x0f, 0xc4, 0x01, 0xa2, 0x0b, 0x21, 0x00, 0x15, - 0x1f, 0xf9, 0x0d, 0xf2, 0x0f, 0xfb, 0x0d, 0x6d, 0x1f, 0x39, 0x07, 0xb7, - 0x0f, 0xcb, 0x00, 0xac, 0x1f, 0xcb, 0x02, 0xb0, 0x0f, 0xf1, 0x0a, 0x06, - 0x0a, 0x4a, 0x0c, 0xa1, 0x0c, 0xd8, 0x09, 0xca, 0x00, 0x21, 0x00, 0x11, - 0x09, 0xcb, 0x0f, 0xc4, 0x01, 0x42, 0x0c, 0x82, 0x0c, 0xc2, 0x00, 0x21, - 0x0c, 0x95, 0x1f, 0xf9, 0x0d, 0xe1, 0x0c, 0xd5, 0x1f, 0xf9, 0x0d, 0xe1, - 0x0f, 0xf1, 0x0a, 0x05, 0x08, 0x84, 0x00, 0xe2, 0x0a, 0x64, 0x09, 0x80, - 0x08, 0x84, 0x0b, 0x21, 0x0f, 0xc4, 0x01, 0xa4, 0x0b, 0x14, 0x1f, 0xf9, - 0x0d, 0xe5, 0x0f, 0xc4, 0x01, 0xa3, 0x0f, 0x38, 0x00, 0x00, 0x0f, 0xc4, - 0x01, 0xa3, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x00, 0xd5, - 0x1f, 0x39, 0x0f, 0xc4, 0x01, 0xa2, 0x0f, 0xc0, 0x0a, 0xaa, 0x0f, 0x39, - 0x0f, 0xf9, 0x0d, 0x88, 0x0f, 0x39, 0x0f, 0xc4, 0x01, 0xb6, 0x00, 0x00, - 0x0f, 0xc4, 0x01, 0xb3, 0x00, 0x00, 0x0f, 0xc4, 0x01, 0xb5, 0x00, 0x00, - 0x0f, 0xc4, 0x01, 0xb2, 0x08, 0x00, 0x0f, 0xc4, 0x01, 0xb4, 0x0f, 0x38, - 0x08, 0x00, 0x0f, 0xc4, 0x01, 0xb2, 0x0b, 0x21, 0x00, 0xd9, 0x09, 0xc8, - 0x09, 0xe1, 0x03, 0x12, 0x19, 0xc8, 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0xb4, - 0x0b, 0x21, 0x00, 0xd3, 0x09, 0xc8, 0x19, 0xe1, 0x13, 0x19, 0x19, 0xc8, - 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0xb1, 0x0b, 0x22, 0x0f, 0xe4, 0x00, 0x30, - 0x09, 0xa1, 0x0f, 0xd5, 0x00, 0x30, 0x1f, 0x39, 0x03, 0xe4, 0x09, 0xa1, - 0x0f, 0xc4, 0x01, 0xb2, 0x0b, 0x14, 0x09, 0x80, 0x0f, 0xc4, 0x01, 0xb3, - 0x0b, 0x21, 0x00, 0x19, 0x10, 0x59, 0x09, 0xc0, 0x09, 0xc8, 0x09, 0xa1, - 0x0f, 0xc4, 0x01, 0xb4, 0x0b, 0x14, 0x09, 0x80, 0x0f, 0xc4, 0x01, 0xb5, - 0x0b, 0x21, 0x00, 0x19, 0x10, 0x59, 0x09, 0xc0, 0x09, 0xc9, 0x0c, 0x61, - 0x03, 0x17, 0x1f, 0x39, 0x0c, 0x17, 0x1f, 0xf9, 0x0d, 0xf5, 0x0f, 0xc4, - 0x01, 0xb6, 0x00, 0x40, 0x0f, 0x39, 0x00, 0xe2, 0x0c, 0x24, 0x09, 0xa1, - 0x09, 0xa7, 0x09, 0x99, 0x09, 0xc9, 0x0f, 0xc4, 0x01, 0xa4, 0x0b, 0x19, - 0x09, 0xe4, 0x09, 0x80, 0x08, 0x84, 0x09, 0x80, 0x0f, 0xc4, 0x01, 0xad, - 0x0b, 0x21, 0x0c, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x03, 0x12, 0x0f, 0x38, - 0x19, 0xc0, 0x0f, 0xf1, 0x05, 0x0f, 0x00, 0x04, 0x0f, 0x00, 0x05, 0x84, - 0x0f, 0xc2, 0x08, 0x00, 0x0a, 0x42, 0x0f, 0xf1, 0x05, 0x10, 0x0f, 0xf6, - 0x02, 0x99, 0x00, 0x02, 0x05, 0x21, 0x0a, 0x51, 0x01, 0x36, 0x09, 0xc8, - 0x0f, 0xc4, 0x00, 0xe6, 0x00, 0x37, 0x05, 0x84, 0x0b, 0xaa, 0x0b, 0xab, - 0x0f, 0xee, 0x01, 0xc0, 0x0b, 0xa7, 0x09, 0xa6, 0x09, 0x89, 0x0c, 0x21, - 0x0f, 0xd7, 0x1f, 0xff, 0x0f, 0xd0, 0x1f, 0xfd, 0x1f, 0xd9, 0x1f, 0xfd, - 0x10, 0x09, 0x09, 0xe1, 0x0f, 0xd7, 0x1f, 0xf4, 0x1f, 0xe1, 0x1f, 0xf5, - 0x0f, 0xd9, 0x0a, 0x80, 0x09, 0xee, 0x0e, 0x48, 0x0c, 0x2a, 0x00, 0x2b, - 0x0f, 0xee, 0x01, 0xc0, 0x03, 0x61, 0x0c, 0x57, 0x1c, 0x61, 0x0f, 0xd9, - 0x0a, 0x00, 0x09, 0xee, 0x0f, 0xc4, 0x01, 0x46, 0x0b, 0xa1, 0x0e, 0x18, - 0x09, 0xca, 0x0b, 0xa1, 0x0e, 0x53, 0x09, 0xcb, 0x10, 0x21, 0x1c, 0x98, - 0x19, 0xca, 0x1c, 0xd1, 0x19, 0xcb, 0x0f, 0xc4, 0x01, 0x48, 0x0c, 0xa1, - 0x0b, 0x98, 0x0c, 0xe1, 0x0b, 0x93, 0x1f, 0xf9, 0x0e, 0xd6, 0x0f, 0xc4, - 0x01, 0x46, 0x0e, 0x02, 0x0e, 0x42, 0x0f, 0xf6, 0x00, 0x47, 0x01, 0x8b, - 0x1f, 0xf9, 0x0e, 0xd5, 0x0f, 0xf0, 0x05, 0x04, 0x0c, 0x32, 0x0f, 0xf0, - 0x05, 0x05, 0x07, 0x36, 0x0c, 0x72, 0x1f, 0xf9, 0x0e, 0xc2, 0x0f, 0xf6, - 0x00, 0x42, 0x01, 0xcb, 0x1f, 0xf0, 0x05, 0x0a, 0x1c, 0x32, 0x1f, 0xf0, - 0x05, 0x0b, 0x0f, 0xf8, 0x0e, 0xd5, 0x1c, 0x72, 0x0f, 0xf6, 0x00, 0x42, - 0x01, 0xcb, 0x0f, 0xc4, 0x00, 0x50, 0x0a, 0x85, 0x1f, 0xf0, 0x05, 0x0a, - 0x1b, 0xb2, 0x1f, 0xf0, 0x05, 0x0b, 0x1b, 0xb2, 0x0f, 0xc4, 0x00, 0x52, - 0x01, 0x3e, 0x0f, 0xf7, 0x00, 0x2d, 0x0c, 0x03, 0x0c, 0x43, 0x00, 0x3f, - 0x00, 0x04, 0x0b, 0x39, 0x0f, 0x39, 0x0f, 0xc8, 0x00, 0x80, 0x0f, 0xf7, - 0x05, 0x5c, 0x0f, 0xf1, 0x03, 0x2d, 0x0f, 0xc4, 0x01, 0xc2, 0x0a, 0x40, - 0x0f, 0xf0, 0x04, 0x00, 0x00, 0x72, 0x0f, 0xf0, 0x05, 0x11, 0x00, 0x72, - 0x0f, 0xf1, 0x0a, 0x1f, 0x03, 0xe2, 0x00, 0x61, 0x0f, 0xc4, 0x01, 0xc0, - 0x0a, 0x64, 0x09, 0x80, 0x0f, 0xc4, 0x05, 0x46, 0x09, 0x99, 0x09, 0xc0, - 0x0f, 0xc4, 0x05, 0x47, 0x00, 0x00, 0x02, 0xba, 0x00, 0x08, 0x0f, 0xf7, - 0x0a, 0xc2, 0x0f, 0xf7, 0x0b, 0xb6, 0x0f, 0xfb, 0x0f, 0x73, 0x09, 0x36, - 0x00, 0x48, 0x0f, 0xf6, 0x05, 0x5c, 0x00, 0x48, 0x0f, 0xf1, 0x03, 0x2d, - 0x0f, 0xc4, 0x01, 0xc3, 0x0a, 0x40, 0x0f, 0xc4, 0x06, 0x94, 0x0f, 0xc5, - 0x01, 0x4a, 0x0b, 0xa1, 0x0b, 0xe0, 0x0f, 0xf0, 0x03, 0x2a, 0x09, 0xf2, - 0x0b, 0xa1, 0x0b, 0xd9, 0x0f, 0xf0, 0x03, 0x29, 0x09, 0xf2, 0x0f, 0xf6, - 0x05, 0x5c, 0x00, 0x48, 0x0f, 0xc4, 0x06, 0x94, 0x0f, 0xf0, 0x03, 0x2a, - 0x0b, 0xb2, 0x0f, 0xf0, 0x03, 0x29, 0x0b, 0xb2, 0x0f, 0xf0, 0x05, 0x11, - 0x00, 0x32, 0x0f, 0xf0, 0x04, 0x00, 0x00, 0x32, 0x0f, 0xf6, 0x05, 0x5c, - 0x00, 0x48, 0x0f, 0xf0, 0x0a, 0x07, 0x04, 0x32, 0x0f, 0xc4, 0x04, 0xc8, - 0x0b, 0x21, 0x00, 0x92, 0x1f, 0xf9, 0x0f, 0x3b, 0x04, 0x04, 0x0f, 0xc0, - 0x00, 0x32, 0x09, 0x04, 0x0f, 0xf8, 0x0f, 0x42, 0x00, 0x80, 0x04, 0x04, - 0x0f, 0xc0, 0x00, 0x47, 0x0f, 0xfb, 0x16, 0x6c, 0x09, 0x04, 0x00, 0x00, - 0x08, 0xc4, 0x02, 0xc0, 0x0f, 0xc8, 0x00, 0x41, 0x0f, 0xf7, 0x05, 0x23, - 0x0f, 0xc4, 0x01, 0xaf, 0x00, 0x00, 0x0f, 0xc4, 0x05, 0x86, 0x00, 0x00, - 0x02, 0x36, 0x04, 0xc4, 0x0f, 0xc4, 0x05, 0x6e, 0x00, 0x37, 0x0f, 0xc4, - 0x06, 0x96, 0x02, 0x37, 0x0f, 0xc4, 0x05, 0x71, 0x00, 0x37, 0x0f, 0xf7, - 0x0b, 0xdb, 0x0f, 0xf7, 0x05, 0xb9, 0x0f, 0xc4, 0x01, 0x71, 0x0b, 0x21, - 0x00, 0x15, 0x0f, 0xc4, 0x01, 0xc3, 0x0b, 0x21, 0x0f, 0xc4, 0x01, 0xc2, - 0x0b, 0x11, 0x09, 0xe1, 0x00, 0xd9, 0x10, 0xd9, 0x0f, 0xc4, 0x01, 0xc4, - 0x09, 0xc0, 0x0f, 0xfa, 0x0e, 0x43, 0x09, 0xc8, 0x07, 0xba, 0x01, 0x88, - 0x0f, 0x39, 0x0f, 0xfb, 0x10, 0x36, 0x0f, 0xc4, 0x01, 0x07, 0x0f, 0xc5, - 0x01, 0x04, 0x0b, 0x83, 0x0b, 0x83, 0x0f, 0xfa, 0x10, 0xa4, 0x0b, 0x83, - 0x0f, 0xfb, 0x10, 0x36, 0x0f, 0xc4, 0x05, 0x49, 0x0b, 0x08, 0x0f, 0xe1, - 0x07, 0x55, 0x0c, 0x17, 0x1f, 0xf9, 0x0f, 0x8f, 0x00, 0x21, 0x0c, 0x18, - 0x09, 0xc8, 0x00, 0x11, 0x0f, 0xf8, 0x0f, 0x94, 0x09, 0xc9, 0x00, 0x09, - 0x0f, 0xe1, 0x08, 0x00, 0x0c, 0x11, 0x09, 0xc8, 0x00, 0xb7, 0x0f, 0xc4, - 0x01, 0x0a, 0x02, 0xb7, 0x07, 0x04, 0x0f, 0xc2, 0x0a, 0xab, 0x0f, 0xc2, - 0x0a, 0xaa, 0x0f, 0xc2, 0x07, 0xfe, 0x0f, 0xf7, 0x02, 0x70, 0x04, 0x44, - 0x00, 0x08, 0x03, 0x61, 0x0b, 0x14, 0x01, 0x36, 0x10, 0x88, 0x0f, 0xc4, - 0x00, 0xf5, 0x00, 0x37, 0x01, 0x08, 0x00, 0xb6, 0x00, 0x09, 0x0f, 0xc4, - 0x00, 0xf5, 0x0f, 0xf7, 0x02, 0x93, 0x03, 0xb7, 0x0f, 0xc4, 0x01, 0x4a, - 0x0c, 0x02, 0x00, 0xb6, 0x0c, 0x42, 0x05, 0x37, 0x04, 0x37, 0x03, 0x37, - 0x00, 0x08, 0x00, 0xb6, 0x00, 0x09, 0x05, 0x37, 0x04, 0x37, 0x0f, 0xc4, - 0x00, 0xf8, 0x00, 0x37, 0x03, 0xb7, 0x0f, 0xc4, 0x01, 0x63, 0x03, 0x36, - 0x0c, 0x00, 0x00, 0xb7, 0x05, 0x37, 0x04, 0x37, 0x0f, 0xc4, 0x06, 0xae, - 0x00, 0x37, 0x0f, 0xc4, 0x05, 0x74, 0x00, 0x37, 0x0f, 0xc4, 0x00, 0xf8, - 0x02, 0x37, 0x04, 0x44, 0x02, 0xc8, 0x02, 0xe1, 0x0b, 0x14, 0x01, 0x36, - 0x13, 0x48, 0x03, 0xb7, 0x0f, 0xc4, 0x01, 0x34, 0x0c, 0x02, 0x0f, 0xfa, - 0x0c, 0xf8, 0x0c, 0x42, 0x0f, 0x39, 0x0f, 0xf0, 0x05, 0x16, 0x0c, 0x32, - 0x0f, 0xc4, 0x01, 0x4c, 0x0c, 0x00, 0x0f, 0xf0, 0x05, 0x18, 0x0f, 0x38, - 0x0c, 0x32, 0x0f, 0xf0, 0x05, 0x32, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x33, - 0x0f, 0x38, 0x00, 0x32, 0x0f, 0xf1, 0x05, 0x12, 0x0f, 0xc4, 0x01, 0x4c, - 0x0c, 0x21, 0x0b, 0x15, 0x1f, 0xfb, 0x0f, 0xe1, 0x1f, 0xf1, 0x05, 0x12, - 0x0a, 0x49, 0x0f, 0xf1, 0x05, 0x13, 0x0f, 0xc4, 0x01, 0x4c, 0x00, 0x61, - 0x0b, 0x19, 0x09, 0xc0, 0x0f, 0x38, 0x0a, 0x48, 0x0f, 0xfb, 0x0f, 0xf2, - 0x0c, 0x2a, 0x0c, 0x6b, 0x0f, 0xee, 0x02, 0x40, 0x03, 0xe2, 0x0c, 0x24, - 0x0f, 0xee, 0x0a, 0x7e, 0x09, 0x8a, 0x0f, 0xe2, 0x0f, 0xfc, 0x0c, 0x64, - 0x09, 0x89, 0x0e, 0x24, 0x09, 0x88, 0x00, 0x2a, 0x00, 0x2c, 0x0c, 0x0b, - 0x00, 0x21, 0x0c, 0x16, 0x19, 0xcb, 0x0c, 0xeb, 0x0c, 0xed, 0x0f, 0xee, - 0x0c, 0x80, 0x0f, 0xc4, 0x01, 0x0d, 0x0c, 0x02, 0x0c, 0x42, 0x0c, 0x56, - 0x19, 0xc9, 0x0c, 0x6b, 0x0c, 0x6d, 0x0f, 0xee, 0x0c, 0xc0, 0x0c, 0x82, - 0x0c, 0xa7, 0x09, 0xa1, 0x05, 0x84, 0x0f, 0xee, 0x0a, 0xd3, 0x0e, 0x02, - 0x0e, 0x42, 0x0e, 0x99, 0x0f, 0x38, 0x09, 0xc2, 0x04, 0x44, 0x0b, 0x21, - 0x03, 0x54, 0x1f, 0xf9, 0x10, 0x54, 0x0f, 0xc4, 0x05, 0x49, 0x0b, 0x08, - 0x0f, 0xfa, 0x0f, 0xe1, 0x00, 0x09, 0x0f, 0xfb, 0x10, 0x06, 0x0f, 0xc4, - 0x01, 0x07, 0x00, 0x37, 0x0f, 0xc4, 0x00, 0xfe, 0x00, 0x37, 0x0f, 0xc4, - 0x00, 0xfb, 0x01, 0xb7, 0x0f, 0xc4, 0x01, 0x01, 0x01, 0xb7, 0x0f, 0xc4, - 0x01, 0x0a, 0x01, 0xb7, 0x0f, 0xf9, 0x0f, 0xeb, 0x0f, 0xc4, 0x05, 0x49, - 0x0b, 0x21, 0x00, 0x51, 0x09, 0xc8, 0x00, 0x09, 0x00, 0x04, 0x0c, 0x00, - 0x0f, 0xfb, 0x0f, 0xe1, 0x0f, 0xfb, 0x10, 0x06, 0x0f, 0xf7, 0x04, 0x66, - 0x03, 0x37, 0x0f, 0xc4, 0x00, 0xfb, 0x00, 0x37, 0x0f, 0xfb, 0x10, 0x99, - 0x0f, 0xfb, 0x10, 0x06, 0x05, 0x37, 0x0f, 0xc4, 0x00, 0xfe, 0x00, 0x37, - 0x06, 0x37, 0x03, 0x37, 0x0f, 0xfb, 0x10, 0x99, 0x0f, 0xfb, 0x10, 0x06, - 0x0f, 0xf7, 0x04, 0x66, 0x05, 0x37, 0x0f, 0xc4, 0x01, 0x01, 0x00, 0x37, - 0x06, 0x37, 0x0f, 0xc4, 0x01, 0x07, 0x00, 0x37, 0x0f, 0xf7, 0x04, 0x72, - 0x0f, 0xf7, 0x04, 0x6f, 0x04, 0x37, 0x0f, 0xc4, 0x01, 0x07, 0x0f, 0xf7, - 0x02, 0x81, 0x07, 0x04, 0x0f, 0xc2, 0x05, 0x3b, 0x0f, 0xc2, 0x08, 0x8c, - 0x0f, 0xf6, 0x02, 0x70, 0x00, 0x02, 0x0f, 0xc4, 0x01, 0x0a, 0x00, 0x37, - 0x0f, 0xc4, 0x00, 0xfe, 0x0f, 0xc5, 0x01, 0x07, 0x04, 0xb7, 0x0f, 0xf9, - 0x0f, 0xeb, 0x00, 0x04, 0x00, 0x61, 0x0f, 0xe2, 0x07, 0xff, 0x0b, 0x19, - 0x09, 0xe4, 0x09, 0x88, 0x0c, 0x00, 0x0f, 0x38, 0x00, 0x09, 0x0f, 0x39, - 0x01, 0x84, 0x0f, 0xc0, 0x07, 0xf8, 0x0f, 0xc4, 0x01, 0x04, 0x02, 0x37, - 0x00, 0x21, 0x0f, 0xc4, 0x07, 0x26, 0x0b, 0x11, 0x01, 0x36, 0x09, 0xc8, - 0x0f, 0xc4, 0x01, 0x10, 0x00, 0x37, 0x00, 0x36, 0x00, 0x44, 0x0f, 0xc4, - 0x05, 0x48, 0x0b, 0x08, 0x01, 0xc4, 0x0c, 0x00, 0x01, 0x44, 0x0c, 0x00, - 0x00, 0x04, 0x00, 0x40, 0x0c, 0x21, 0x01, 0x19, 0x09, 0xe2, 0x0f, 0xe4, - 0x07, 0xff, 0x09, 0x88, 0x00, 0x09, 0x01, 0x04, 0x0f, 0xfa, 0x0f, 0xe1, - 0x0c, 0x00, 0x0f, 0xc4, 0x04, 0xc8, 0x00, 0x00, 0x0f, 0xc4, 0x04, 0xc9, - 0x00, 0x00, 0x0f, 0xc4, 0x04, 0xca, 0x00, 0x00, 0x0f, 0xfb, 0x10, 0x06, - 0x03, 0x37, 0x0f, 0xc4, 0x01, 0x10, 0x05, 0xb7, 0x0f, 0xfb, 0x00, 0x58, - 0x1f, 0xf9, 0x10, 0xe7, 0x00, 0x04, 0x0b, 0x21, 0x00, 0x14, 0x1f, 0xf9, - 0x10, 0xe3, 0x0f, 0xfb, 0x11, 0x1b, 0x01, 0xb6, 0x00, 0x44, 0x0f, 0xf9, - 0x10, 0xfc, 0x05, 0xb6, 0x00, 0x44, 0x0f, 0xfb, 0x00, 0x58, 0x1f, 0xf9, - 0x10, 0xf4, 0x00, 0x04, 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xfb, 0x11, 0x1b, - 0x0f, 0xf9, 0x10, 0xf9, 0x01, 0x04, 0x01, 0x45, 0x0b, 0x01, 0x00, 0x04, - 0x00, 0x40, 0x0f, 0xf6, 0x00, 0xaf, 0x00, 0x44, 0x01, 0x84, 0x0b, 0x21, - 0x00, 0x54, 0x1f, 0xf8, 0x11, 0x0d, 0x09, 0xc0, 0x01, 0x04, 0x00, 0x61, - 0x0f, 0xe2, 0x07, 0xff, 0x0b, 0x19, 0x09, 0xe4, 0x09, 0x88, 0x0c, 0x00, - 0x0f, 0xf8, 0x10, 0xd2, 0x00, 0x09, 0x0f, 0xfb, 0x0f, 0xeb, 0x0f, 0xc4, - 0x04, 0xca, 0x0b, 0x21, 0x0f, 0xd9, 0x04, 0xb8, 0x09, 0xc4, 0x0f, 0xc5, - 0x05, 0x49, 0x0f, 0xfa, 0x12, 0x20, 0x0b, 0x01, 0x0f, 0x39, 0x01, 0x44, - 0x01, 0xc5, 0x0b, 0x0f, 0x0d, 0xc1, 0x00, 0x04, 0x00, 0x00, 0x0f, 0xc4, - 0x04, 0xc8, 0x0b, 0x21, 0x04, 0x12, 0x1f, 0x39, 0x0f, 0xd9, 0x04, 0xb8, - 0x09, 0xc5, 0x0d, 0xc1, 0x00, 0x59, 0x09, 0xc0, 0x00, 0x14, 0x1f, 0x38, - 0x09, 0xce, 0x0f, 0xc4, 0x04, 0xb8, 0x0d, 0xe1, 0x0b, 0x13, 0x19, 0xe1, - 0x1f, 0xd9, 0x08, 0x00, 0x09, 0xe1, 0x0f, 0xd2, 0x02, 0x00, 0x1f, 0x39, - 0x0f, 0xc4, 0x04, 0xc9, 0x0d, 0x80, 0x0f, 0xc4, 0x04, 0xca, 0x0f, 0x38, - 0x0d, 0x80, 0x0f, 0xc4, 0x04, 0xc9, 0x0b, 0x08, 0x0c, 0x21, 0x0f, 0xc5, - 0x04, 0xca, 0x0b, 0x49, 0x0c, 0x54, 0x1f, 0x39, 0x0c, 0x40, 0x0c, 0x53, - 0x0f, 0xe1, 0x04, 0xb8, 0x0c, 0x19, 0x09, 0xc4, 0x0b, 0x0a, 0x0c, 0x59, - 0x09, 0xc4, 0x0b, 0x0b, 0x0c, 0xa1, 0x1c, 0xe1, 0x0c, 0xd1, 0x1c, 0x91, - 0x09, 0xcc, 0x09, 0xe1, 0x0f, 0xd2, 0x08, 0x00, 0x19, 0xcc, 0x00, 0x0d, - 0x0c, 0x21, 0x0c, 0x53, 0x10, 0x21, 0x1d, 0x11, 0x19, 0xcc, 0x1f, 0xcd, - 0x0f, 0xff, 0x0f, 0xc4, 0x04, 0xcb, 0x0d, 0x00, 0x0d, 0x08, 0x00, 0xb6, - 0x0d, 0x49, 0x07, 0x04, 0x0f, 0xc2, 0x0a, 0xab, 0x0f, 0xc2, 0x0a, 0xaa, - 0x0f, 0xc2, 0x07, 0xfe, 0x0f, 0xf7, 0x02, 0x70, 0x07, 0xb7, 0x11, 0x36, - 0x10, 0x88, 0x03, 0xb7, 0x0f, 0xc4, 0x01, 0x4e, 0x0c, 0x02, 0x0c, 0x42, - 0x0f, 0xc4, 0x06, 0x94, 0x0b, 0x8a, 0x0b, 0x8b, 0x0f, 0xc4, 0x01, 0x50, - 0x0c, 0x82, 0x0c, 0xc2, 0x0c, 0xa1, 0x0c, 0x20, 0x09, 0xc8, 0x0c, 0xe1, - 0x0c, 0x59, 0x0f, 0xf6, 0x09, 0x24, 0x09, 0xc9, 0x04, 0x04, 0x0f, 0xc0, - 0x00, 0x46, 0x0f, 0xc4, 0x06, 0x01, 0x0f, 0xf6, 0x05, 0xb9, 0x00, 0x40, - 0x0f, 0x39, 0x0f, 0xc4, 0x01, 0x50, 0x0b, 0x88, 0x0f, 0xf6, 0x09, 0x24, - 0x0b, 0x89, 0x0f, 0xf6, 0x05, 0x5c, 0x00, 0x48, 0x09, 0x04, 0x00, 0xa1, - 0x0b, 0x16, 0x04, 0x04, 0x0f, 0xc0, 0x00, 0x32, 0x1f, 0xc0, 0x00, 0x47, - 0x1f, 0xfb, 0x16, 0x6c, 0x07, 0x37, 0x02, 0xc8, 0x12, 0xc8, 0x08, 0xc4, - 0x0c, 0x00, 0x0f, 0xc8, 0x00, 0x41, 0x0f, 0xf7, 0x05, 0x23, 0x0f, 0xfa, - 0x0e, 0x43, 0x00, 0x88, 0x0f, 0xc4, 0x06, 0x01, 0x0f, 0xf4, 0x05, 0xb9, - 0x04, 0x00, 0x00, 0x21, 0x0f, 0xc4, 0x06, 0xfe, 0x0b, 0x15, 0x1f, 0xf9, - 0x11, 0xdb, 0x0f, 0xc4, 0x01, 0xb7, 0x0b, 0x15, 0x1f, 0xf9, 0x11, 0xdb, - 0x0f, 0xc4, 0x01, 0xc5, 0x0f, 0xc0, 0x00, 0x47, 0x0f, 0xc4, 0x05, 0xe8, - 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xf9, 0x11, 0xe2, 0x0f, 0xc4, 0x01, 0xc6, - 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x0f, 0xd2, 0x00, 0x46, 0x11, 0x38, - 0x11, 0x88, 0x0f, 0xc8, 0x00, 0x47, 0x08, 0xbb, 0x0f, 0x39, 0x04, 0x04, - 0x0f, 0xc0, 0x00, 0x32, 0x0f, 0xc8, 0x00, 0x3c, 0x08, 0xbb, 0x0f, 0x39, - 0x04, 0x3b, 0x0f, 0xf7, 0x0c, 0x13, 0x0f, 0xf7, 0x0c, 0x97, 0x0f, 0xc4, - 0x01, 0x70, 0x0b, 0x21, 0x0f, 0xc4, 0x06, 0xff, 0x0b, 0x12, 0x1f, 0xf9, - 0x12, 0x07, 0x0f, 0xc4, 0x01, 0xc5, 0x0b, 0x21, 0x0f, 0xd5, 0x00, 0x47, - 0x1f, 0xf9, 0x12, 0x07, 0x0f, 0xfb, 0x16, 0x8b, 0x09, 0x3b, 0x0f, 0xfb, - 0x0c, 0xf8, 0x0f, 0xfb, 0x13, 0xae, 0x04, 0x04, 0x0f, 0xc5, 0x01, 0xc5, - 0x0b, 0x01, 0x0f, 0xc0, 0x00, 0x47, 0x0f, 0xf7, 0x05, 0x9d, 0x0f, 0xf9, - 0x11, 0xe2, 0x07, 0xb7, 0x1f, 0xf6, 0x05, 0x5c, 0x10, 0x48, 0x09, 0x3b, - 0x0f, 0xe1, 0x00, 0x47, 0x04, 0x04, 0x0b, 0x15, 0x19, 0x45, 0x1f, 0xc4, - 0x00, 0x80, 0x1f, 0xf7, 0x00, 0xa4, 0x0f, 0xc4, 0x01, 0xc5, 0x0b, 0x15, - 0x19, 0x45, 0x1f, 0xc4, 0x00, 0x80, 0x1f, 0xf7, 0x00, 0xa4, 0x0f, 0xfb, - 0x12, 0x46, 0x0f, 0x39, 0x09, 0x04, 0x00, 0x00, 0x0f, 0xc4, 0x04, 0xc9, - 0x0f, 0xc5, 0x04, 0xce, 0x0b, 0x01, 0x0f, 0xc5, 0x04, 0xcf, 0x0b, 0x01, - 0x0f, 0xc5, 0x04, 0xcc, 0x00, 0x01, 0x0f, 0xc5, 0x04, 0xcd, 0x00, 0x01, - 0x0f, 0xc5, 0x04, 0xd0, 0x00, 0x41, 0x0f, 0xc5, 0x04, 0xd5, 0x00, 0x01, - 0x0f, 0xc5, 0x04, 0xd1, 0x0b, 0x01, 0x02, 0x36, 0x09, 0x44, 0x0f, 0xc8, - 0x1f, 0xfc, 0x01, 0x37, 0x0f, 0xc4, 0x04, 0xd2, 0x00, 0x37, 0x0f, 0xfb, - 0x16, 0x2f, 0x0f, 0xfb, 0x16, 0x6c, 0x0f, 0x39, 0x0f, 0xc4, 0x00, 0x80, - 0x02, 0x37, 0x0f, 0xc4, 0x04, 0xc9, 0x0b, 0x21, 0x0b, 0x27, 0x09, 0x99, - 0x09, 0xe1, 0x0f, 0xd9, 0x04, 0xd6, 0x00, 0x36, 0x09, 0xc4, 0x0f, 0xc4, - 0x04, 0xd2, 0x0f, 0xf7, 0x00, 0xbd, 0x0f, 0xc4, 0x00, 0x80, 0x05, 0xb7, - 0x0f, 0xfb, 0x00, 0x58, 0x0f, 0xc4, 0x04, 0xd0, 0x0b, 0x0c, 0x1f, 0xf8, - 0x12, 0x65, 0x00, 0x21, 0x0f, 0xf8, 0x12, 0x75, 0x0d, 0x15, 0x0f, 0xc4, - 0x04, 0xd2, 0x0f, 0xf7, 0x00, 0xb2, 0x0f, 0xc4, 0x04, 0xd1, 0x0f, 0xc5, - 0x04, 0xc9, 0x0b, 0x40, 0x0f, 0xc4, 0x04, 0xd5, 0x0b, 0x14, 0x1f, 0xf8, - 0x12, 0x7a, 0x10, 0x40, 0x0d, 0x14, 0x0f, 0xc5, 0x04, 0xcc, 0x1f, 0xc5, - 0x04, 0xcd, 0x00, 0x41, 0x0f, 0xc4, 0x04, 0xcc, 0x0b, 0x88, 0x0b, 0x89, - 0x0b, 0x8a, 0x0b, 0x8b, 0x00, 0x21, 0x0c, 0x15, 0x1f, 0xf9, 0x12, 0x8c, - 0x0c, 0xa1, 0x00, 0x51, 0x09, 0xca, 0x09, 0xe1, 0x0f, 0xd7, 0x1f, 0xff, - 0x10, 0x0a, 0x10, 0x48, 0x00, 0x21, 0x0c, 0x55, 0x1f, 0xf9, 0x12, 0x9a, - 0x0c, 0xe1, 0x00, 0x59, 0x09, 0xe1, 0x0f, 0xc4, 0x04, 0xc8, 0x0b, 0x12, - 0x00, 0x11, 0x10, 0x51, 0x09, 0xcb, 0x10, 0x49, 0x00, 0x21, 0x0d, 0x15, - 0x1f, 0xf9, 0x12, 0xa4, 0x0c, 0x0d, 0x0d, 0x55, 0x10, 0x4c, 0x0f, 0xf8, - 0x12, 0xa8, 0x1c, 0x4d, 0x0c, 0x4d, 0x0d, 0x55, 0x10, 0x0c, 0x1c, 0x0d, - 0x0f, 0xc4, 0x04, 0xcc, 0x0c, 0x02, 0x0c, 0x42, 0x0f, 0xc4, 0x04, 0xd0, - 0x0d, 0x00, 0x0d, 0x54, 0x1f, 0xf9, 0x12, 0xbf, 0x0f, 0xc4, 0x04, 0xca, - 0x0f, 0xc5, 0x04, 0xd1, 0x0b, 0x40, 0x04, 0x04, 0x0f, 0xc0, 0x00, 0x32, - 0x09, 0x04, 0x0f, 0xfa, 0x11, 0x41, 0x00, 0x80, 0x0f, 0x39, 0x0d, 0x15, - 0x0c, 0x8d, 0x0f, 0xc4, 0x04, 0xce, 0x1c, 0xcd, 0x1f, 0xc4, 0x04, 0xcf, - 0x0d, 0x40, 0x0f, 0xc4, 0x04, 0xca, 0x0f, 0xfa, 0x11, 0x41, 0x0d, 0x40, - 0x09, 0x04, 0x0f, 0x38, 0x00, 0x00, 0x07, 0x37, 0x0f, 0xf0, 0x0b, 0x08, - 0x0f, 0xf2, 0x00, 0x3f, 0x0f, 0xf0, 0x0b, 0x09, 0x0f, 0xf2, 0x0d, 0x59, - 0x1f, 0xf2, 0x07, 0x4d, 0x0f, 0xf0, 0x0b, 0x10, 0x0f, 0xf2, 0x00, 0x87, - 0x1f, 0xf2, 0x01, 0x47, 0x0f, 0xf0, 0x0b, 0x11, 0x0f, 0xf2, 0x03, 0x12, - 0x0f, 0xf0, 0x0b, 0x12, 0x0f, 0xf2, 0x06, 0x61, 0x0f, 0xf0, 0x0b, 0x13, - 0x0f, 0xf2, 0x0b, 0xbf, 0x0f, 0xc4, 0x06, 0xc9, 0x0f, 0xc2, 0x0c, 0xcd, - 0x0f, 0xc2, 0x07, 0xfe, 0x1f, 0xc4, 0x06, 0xc9, 0x1f, 0xc2, 0x0a, 0xe1, - 0x1f, 0xc2, 0x07, 0xfd, 0x0f, 0x39, 0x0f, 0xc4, 0x01, 0xd9, 0x08, 0x02, - 0x00, 0x02, 0x0f, 0xc2, 0x0b, 0xb5, 0x0f, 0xc2, 0x07, 0xf0, 0x00, 0x02, - 0x0f, 0xc2, 0x0b, 0xb4, 0x0f, 0xc2, 0x07, 0xf0, 0x00, 0x02, 0x0f, 0xc2, - 0x0a, 0x5b, 0x0f, 0xc2, 0x07, 0xff, 0x00, 0x02, 0x0f, 0xc2, 0x0d, 0xdf, - 0x0f, 0xc2, 0x07, 0xfa, 0x00, 0x02, 0x0f, 0xc2, 0x0a, 0x22, 0x00, 0x02, - 0x00, 0x02, 0x0f, 0xc2, 0x0a, 0x2f, 0x0f, 0xc2, 0x07, 0xf2, 0x00, 0x02, - 0x0f, 0xc2, 0x0b, 0x40, 0x0f, 0xc2, 0x07, 0xfa, 0x00, 0x02, 0x0f, 0xc2, - 0x0c, 0x52, 0x00, 0x02, 0x00, 0x02, 0x0f, 0xc2, 0x08, 0x00, 0x00, 0x42, - 0x00, 0x02, 0x0f, 0xc2, 0x0c, 0xb5, 0x0f, 0xc2, 0x07, 0xfb, 0x00, 0x02, - 0x0f, 0xc2, 0x0f, 0x98, 0x0f, 0xc2, 0x07, 0xfa, 0x00, 0x02, 0x0f, 0xc2, - 0x0b, 0x23, 0x0f, 0xc2, 0x07, 0xfa, 0x00, 0x02, 0x0f, 0xc2, 0x08, 0x40, - 0x0f, 0xc2, 0x07, 0xfa, 0x00, 0x02, 0x0f, 0xc2, 0x0d, 0x4e, 0x0f, 0xc2, - 0x07, 0xf9, 0x00, 0x02, 0x0f, 0xc2, 0x0d, 0xc5, 0x00, 0x02, 0x00, 0x02, - 0x0f, 0xc2, 0x09, 0x06, 0x00, 0x42, 0x07, 0xc4, 0x0a, 0x8f, 0x0f, 0xc2, - 0x04, 0xf3, 0x0f, 0xc2, 0x0b, 0x50, 0x00, 0x02, 0x0d, 0xc4, 0x08, 0x3a, - 0x0d, 0xc5, 0x0f, 0xc4, 0x06, 0xcb, 0x00, 0x37, 0x06, 0xb6, 0x0d, 0xc4, - 0x0f, 0xc4, 0x06, 0xce, 0x00, 0x37, 0x06, 0xb6, 0x0d, 0xc4, 0x0f, 0xc4, - 0x06, 0xd1, 0x00, 0x37, 0x06, 0xb6, 0x0d, 0xc4, 0x0f, 0xc4, 0x06, 0xd4, - 0x00, 0x37, 0x06, 0xb6, 0x0d, 0xc4, 0x0f, 0xc4, 0x06, 0xd7, 0x00, 0x37, - 0x0f, 0xc4, 0x06, 0xda, 0x00, 0x02, 0x0f, 0xc2, 0x0c, 0x00, 0x0f, 0x38, - 0x00, 0xc2, 0x0f, 0xf1, 0x0a, 0x36, 0x0f, 0xc5, 0x01, 0x52, 0x0f, 0xc4, - 0x01, 0xd9, 0x07, 0x36, 0x0b, 0x0a, 0x0a, 0x43, 0x0f, 0xf1, 0x0a, 0x37, - 0x1c, 0xa7, 0x19, 0xa7, 0x19, 0x8a, 0x0f, 0xc4, 0x01, 0xc9, 0x0c, 0x80, - 0x0f, 0xc4, 0x01, 0xc8, 0x0b, 0x0c, 0x0d, 0x21, 0x00, 0x59, 0x09, 0xcb, - 0x0a, 0x43, 0x0c, 0x97, 0x1c, 0xcc, 0x0f, 0xc5, 0x01, 0xc7, 0x00, 0x21, - 0x0b, 0x55, 0x00, 0x01, 0x10, 0x0c, 0x0f, 0xc5, 0x01, 0x6e, 0x0b, 0x55, - 0x00, 0x01, 0x1f, 0xc5, 0x01, 0xcb, 0x10, 0x41, 0x1f, 0xc5, 0x01, 0xcc, - 0x10, 0x01, 0x1f, 0xc5, 0x01, 0xc7, 0x10, 0x41, 0x1c, 0xa1, 0x10, 0x59, - 0x19, 0xcc, 0x0d, 0x00, 0x0d, 0x21, 0x0c, 0x92, 0x0f, 0xc4, 0x01, 0xca, - 0x0b, 0x22, 0x00, 0xe4, 0x09, 0xa2, 0x03, 0x25, 0x10, 0x25, 0x0f, 0xf0, - 0x0a, 0x2f, 0x09, 0xb2, 0x0f, 0x38, 0x09, 0x80, 0x0f, 0xc4, 0x01, 0xc8, - 0x0b, 0x21, 0x0f, 0xc4, 0x01, 0xc9, 0x0b, 0x16, 0x1f, 0xf9, 0x14, 0x13, - 0x0f, 0xc4, 0x01, 0xcb, 0x00, 0x00, 0x00, 0x15, 0x0f, 0xc5, 0x01, 0x52, - 0x1f, 0xf9, 0x13, 0xc2, 0x0f, 0xc4, 0x05, 0x0b, 0x0f, 0x38, 0x0b, 0xc0, - 0x0b, 0xc8, 0x0c, 0x2a, 0x00, 0x2b, 0x0c, 0x2c, 0x00, 0x2d, 0x0f, 0xee, - 0x0c, 0x80, 0x0f, 0xe1, 0x0a, 0x00, 0x0b, 0xc9, 0x0c, 0x59, 0x09, 0xe1, - 0x0c, 0x59, 0x09, 0xee, 0x0f, 0xce, 0x05, 0x06, 0x0d, 0x84, 0x0b, 0xaa, - 0x0b, 0xab, 0x0b, 0xac, 0x0b, 0xad, 0x0f, 0xef, 0x08, 0x40, 0x1f, 0xf9, - 0x13, 0xe9, 0x0d, 0x84, 0x0f, 0xee, 0x05, 0x00, 0x0e, 0x02, 0x0e, 0x42, - 0x0f, 0xee, 0x05, 0x40, 0x0e, 0x02, 0x0e, 0x42, 0x0f, 0xc4, 0x05, 0x0a, - 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x0f, 0xf1, 0x05, 0x0f, 0x0f, 0xee, - 0x03, 0x80, 0x0f, 0xe1, 0x09, 0xf8, 0x00, 0x2d, 0x0f, 0xcf, 0x05, 0x10, - 0x0a, 0x6c, 0x0d, 0xf1, 0x0f, 0xee, 0x02, 0x80, 0x0f, 0xce, 0x05, 0x0c, - 0x0d, 0x84, 0x0b, 0xaa, 0x0b, 0xab, 0x0b, 0xac, 0x0b, 0xad, 0x0a, 0x59, - 0x09, 0xee, 0x0f, 0xcd, 0x05, 0x00, 0x0f, 0xcc, 0x05, 0x40, 0x0f, 0xef, - 0x08, 0x40, 0x1f, 0x39, 0x0d, 0x84, 0x0d, 0x6e, 0x0e, 0x02, 0x0e, 0x42, - 0x0d, 0x2e, 0x0e, 0x02, 0x0e, 0x42, 0x0f, 0xc4, 0x05, 0x10, 0x0b, 0x21, - 0x00, 0x59, 0x0f, 0x38, 0x09, 0xc0, 0x0f, 0xc4, 0x01, 0xcb, 0x0b, 0x21, - 0x00, 0x15, 0x1f, 0x39, 0x00, 0x40, 0x0f, 0xc4, 0x01, 0xcc, 0x0b, 0x21, - 0x00, 0x59, 0x09, 0xc8, 0x09, 0xe1, 0x01, 0x17, 0x1c, 0x00, 0x00, 0x54, - 0x1f, 0xc8, 0x14, 0x26, 0x15, 0x3b, 0x0f, 0x39, 0x0f, 0xc4, 0x01, 0xcc, - 0x0b, 0x21, 0x00, 0x14, 0x1f, 0x39, 0x0f, 0xc4, 0x05, 0x06, 0x0f, 0xc5, - 0x05, 0x11, 0x0b, 0x03, 0x00, 0x02, 0x0b, 0x03, 0x00, 0x02, 0x0b, 0x03, - 0x00, 0x02, 0x0b, 0x03, 0x00, 0x02, 0x0f, 0xc4, 0x05, 0x0a, 0x0f, 0xc5, - 0x05, 0x15, 0x0b, 0x03, 0x00, 0x02, 0x0f, 0xc4, 0x05, 0x0b, 0x0f, 0xc5, - 0x05, 0x16, 0x0b, 0x03, 0x00, 0x02, 0x0f, 0xc4, 0x05, 0x0c, 0x0f, 0xc5, - 0x05, 0x17, 0x0b, 0x03, 0x00, 0x02, 0x0b, 0x03, 0x00, 0x02, 0x0b, 0x03, - 0x00, 0x02, 0x0b, 0x03, 0x00, 0x02, 0x0f, 0xc4, 0x05, 0x10, 0x0f, 0xc5, - 0x05, 0x1b, 0x0b, 0x03, 0x00, 0x02, 0x0f, 0xc4, 0x01, 0xc7, 0x00, 0x40, - 0x0f, 0xc4, 0x05, 0x11, 0x0b, 0xaa, 0x0b, 0xab, 0x0b, 0xac, 0x0b, 0xad, - 0x0f, 0xee, 0x03, 0x00, 0x0f, 0xee, 0x0a, 0xef, 0x0f, 0xee, 0x09, 0x00, - 0x07, 0xc4, 0x0f, 0xe2, 0x00, 0x3f, 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0xa4, - 0x09, 0x82, 0x0f, 0xf6, 0x00, 0xbd, 0x07, 0xc4, 0x0f, 0xc4, 0x05, 0x16, - 0x0b, 0x2a, 0x0b, 0x2c, 0x0f, 0xee, 0x0d, 0x40, 0x0e, 0x2a, 0x0e, 0x6b, - 0x0f, 0xc4, 0x05, 0x15, 0x0b, 0x2c, 0x00, 0x2d, 0x0f, 0xee, 0x0c, 0x80, - 0x0f, 0xee, 0x0a, 0xef, 0x0f, 0xee, 0x09, 0x00, 0x07, 0x04, 0x0f, 0xe2, - 0x00, 0x3f, 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0xa4, 0x0f, 0xf6, 0x02, 0x09, - 0x09, 0x82, 0x0f, 0xc4, 0x00, 0x7d, 0x00, 0x37, 0x0f, 0xc4, 0x01, 0xcc, - 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xc4, 0x01, 0x6f, 0x01, 0xba, 0x10, 0x40, - 0x0f, 0xc4, 0x00, 0x7d, 0x02, 0x37, 0x07, 0x37, 0x0f, 0xc4, 0x01, 0xda, - 0x1f, 0xc4, 0x01, 0xdd, 0x06, 0xb7, 0x0f, 0xc4, 0x01, 0x1c, 0x00, 0x37, - 0x0f, 0xf1, 0x0a, 0x07, 0x0f, 0xc4, 0x01, 0xe0, 0x06, 0xb7, 0x04, 0x21, - 0x0a, 0x54, 0x0f, 0xf1, 0x0a, 0x10, 0x1f, 0xf9, 0x14, 0xc6, 0x00, 0x2a, - 0x09, 0xeb, 0x0f, 0xee, 0x01, 0xc0, 0x0f, 0xee, 0x0a, 0xcb, 0x0f, 0xf7, - 0x04, 0x66, 0x05, 0x84, 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0x82, 0x0f, 0xc4, - 0x01, 0xe3, 0x06, 0xb7, 0x0f, 0xc4, 0x00, 0x9e, 0x0f, 0xf7, 0x02, 0x81, - 0x0f, 0xfb, 0x01, 0x1c, 0x0f, 0xf7, 0x04, 0x72, 0x0f, 0xf7, 0x02, 0x70, - 0x0f, 0xf9, 0x14, 0xd0, 0x07, 0xb7, 0x1f, 0xf9, 0x14, 0xd0, 0x0a, 0x61, - 0x00, 0x14, 0x1f, 0xf9, 0x14, 0xd0, 0x0f, 0xc4, 0x01, 0xe6, 0x06, 0xb7, - 0x0f, 0xc4, 0x01, 0x13, 0x00, 0x37, 0x0f, 0xc4, 0x01, 0x1c, 0x02, 0x37, - 0x0f, 0xfb, 0x01, 0x0c, 0x0f, 0xf7, 0x00, 0x8f, 0x0f, 0xc4, 0x01, 0x22, - 0x00, 0x37, 0x0f, 0xc4, 0x01, 0x22, 0x0f, 0xc5, 0x00, 0xa7, 0x08, 0x3b, - 0x03, 0xb7, 0x00, 0x21, 0x0c, 0x55, 0x1f, 0xc8, 0x0f, 0xff, 0x0f, 0xc4, - 0x01, 0x79, 0x01, 0xba, 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0x13, 0x02, 0x37, - 0x0f, 0xfb, 0x01, 0x0c, 0x0f, 0xf7, 0x00, 0x8f, 0x0f, 0xc4, 0x06, 0xdd, - 0x00, 0x37, 0x0f, 0xc4, 0x00, 0xa7, 0x06, 0xb7, 0x03, 0xb7, 0x00, 0x21, - 0x0c, 0x55, 0x1f, 0xc8, 0x0f, 0xff, 0x0f, 0xf0, 0x0f, 0x16, 0x0c, 0x32, - 0x0f, 0xc4, 0x01, 0x78, 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0x7f, 0x0c, 0x00, - 0x0f, 0xfa, 0x03, 0x00, 0x08, 0x08, 0x0f, 0xc4, 0x05, 0x17, 0x0b, 0xaa, - 0x0b, 0xab, 0x0b, 0xac, 0x0b, 0xad, 0x0f, 0xee, 0x03, 0x00, 0x0f, 0xee, - 0x0a, 0xef, 0x0f, 0xf1, 0x05, 0x04, 0x0a, 0x4f, 0x0f, 0xf1, 0x05, 0x05, - 0x0f, 0xee, 0x09, 0x00, 0x0f, 0xe2, 0x00, 0x3f, 0x02, 0x21, 0x07, 0xc4, - 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0xa4, 0x09, 0x99, 0x09, 0xc2, 0x0f, 0xc4, - 0x01, 0x54, 0x0d, 0xc2, 0x01, 0xba, 0x0a, 0x42, 0x0f, 0xf6, 0x00, 0xbd, - 0x07, 0xc4, 0x0f, 0xc4, 0x05, 0x1b, 0x00, 0x2a, 0x0b, 0x2b, 0x0f, 0xee, - 0x01, 0xc0, 0x0f, 0xee, 0x0a, 0xcb, 0x07, 0x04, 0x00, 0x02, 0x0e, 0x42, - 0x0f, 0xf6, 0x02, 0x09, 0x0e, 0x82, 0x0f, 0xc4, 0x01, 0x54, 0x0b, 0x8f, - 0x00, 0x21, 0x0d, 0xd5, 0x10, 0x2a, 0x1d, 0xeb, 0x1f, 0xee, 0x01, 0xc0, - 0x1f, 0xe1, 0x0b, 0x02, 0x1b, 0x99, 0x19, 0xee, 0x17, 0x04, 0x1e, 0x02, - 0x1e, 0x42, 0x1e, 0xa2, 0x1f, 0xe4, 0x07, 0xff, 0x1f, 0xf6, 0x02, 0x70, - 0x19, 0x82, 0x0f, 0xc4, 0x01, 0xe9, 0x06, 0xb7, 0x07, 0x37, 0x11, 0x36, - 0x10, 0x88, 0x0f, 0xc4, 0x01, 0x1f, 0x00, 0x37, 0x01, 0xbb, 0x0f, 0xc4, - 0x06, 0xc7, 0x0b, 0x21, 0x00, 0x15, 0x1f, 0xf9, 0x15, 0x68, 0x0f, 0xc4, - 0x01, 0x1f, 0x02, 0x37, 0x0f, 0xfb, 0x01, 0x14, 0x0f, 0xc4, 0x06, 0xe0, - 0x0f, 0xf9, 0x15, 0x72, 0x0f, 0xc4, 0x06, 0xe0, 0x0f, 0xc5, 0x00, 0xa1, - 0x0f, 0xf7, 0x02, 0x7d, 0x0f, 0xfb, 0x01, 0x1c, 0x0f, 0xc4, 0x01, 0x1f, - 0x00, 0x37, 0x0f, 0xc4, 0x01, 0x1f, 0x02, 0x37, 0x0f, 0xc4, 0x01, 0xec, - 0x06, 0xb7, 0x0f, 0xc4, 0x01, 0x16, 0x00, 0x37, 0x0f, 0xc4, 0x01, 0x6c, - 0x0b, 0x22, 0x0f, 0xe4, 0x00, 0x38, 0x09, 0xa1, 0x0f, 0xc4, 0x01, 0xf5, - 0x02, 0x14, 0x1f, 0xc4, 0x01, 0xf8, 0x04, 0x14, 0x1f, 0xc4, 0x01, 0xfb, - 0x06, 0x14, 0x1f, 0xc4, 0x01, 0xfe, 0x08, 0x14, 0x1f, 0xc4, 0x02, 0x01, - 0x0f, 0xe4, 0x0c, 0x00, 0x09, 0xa1, 0x0f, 0xc5, 0x06, 0x2b, 0x0f, 0xd4, - 0x04, 0x00, 0x1f, 0xc5, 0x02, 0x04, 0x00, 0x14, 0x1f, 0xc5, 0x02, 0x07, - 0x08, 0x3b, 0x0f, 0xc4, 0x01, 0x7e, 0x0b, 0x21, 0x00, 0x15, 0x11, 0x36, - 0x10, 0x88, 0x0f, 0xc4, 0x01, 0x25, 0x00, 0x37, 0x0f, 0xc4, 0x01, 0x16, - 0x06, 0xb7, 0x0f, 0xc4, 0x01, 0x16, 0x06, 0xb7, 0x07, 0x37, 0x0f, 0xc4, - 0x01, 0xef, 0x1f, 0xc4, 0x01, 0xf2, 0x06, 0xb7, 0x0f, 0xc4, 0x01, 0x19, - 0x00, 0x37, 0x01, 0xbb, 0x0f, 0xc4, 0x01, 0xcd, 0x0f, 0xc0, 0x06, 0xc8, - 0x0f, 0xc4, 0x01, 0xce, 0x0f, 0xc0, 0x05, 0x1c, 0x04, 0xbb, 0x04, 0xbb, - 0x04, 0xbb, 0x04, 0xbb, 0x04, 0xbb, 0x04, 0xbb, 0x01, 0xbb, 0x04, 0xbb, - 0x0f, 0xc4, 0x05, 0x1c, 0x0f, 0xc8, 0x0a, 0x24, 0x00, 0x61, 0x01, 0xfe, - 0x0f, 0xfd, 0x15, 0xd2, 0x00, 0x3f, 0x0c, 0x30, 0x0b, 0xb2, 0x0c, 0x19, - 0x09, 0xc8, 0x0f, 0xc4, 0x01, 0xcc, 0x0b, 0x21, 0x00, 0x14, 0x1f, 0x39, - 0x00, 0x54, 0x1f, 0x38, 0x09, 0xc0, 0x01, 0xbb, 0x0f, 0xf8, 0x14, 0x26, - 0x0f, 0xc4, 0x01, 0xcd, 0x0b, 0x05, 0x0b, 0xc8, 0x0b, 0xc9, 0x0b, 0xca, - 0x0a, 0xc0, 0x05, 0x84, 0x0c, 0x02, 0x0c, 0x42, 0x0c, 0x82, 0x0f, 0xc4, - 0x01, 0x19, 0x06, 0xb7, 0x0f, 0xc4, 0x01, 0x80, 0x0b, 0x21, 0x00, 0x15, - 0x1f, 0xf9, 0x16, 0x0c, 0x05, 0x84, 0x0b, 0xaa, 0x0b, 0xab, 0x0f, 0xee, - 0x01, 0xc0, 0x0f, 0xee, 0x0a, 0x7a, 0x0b, 0xa7, 0x09, 0xa6, 0x09, 0xa1, - 0x01, 0x51, 0x09, 0xc8, 0x01, 0x16, 0x1f, 0xf9, 0x16, 0x24, 0x0c, 0x21, - 0x0f, 0xd7, 0x1f, 0xfa, 0x1f, 0xe1, 0x1f, 0xfa, 0x0f, 0xd9, 0x0a, 0x80, - 0x09, 0xee, 0x0f, 0xf8, 0x16, 0x24, 0x00, 0x08, 0x05, 0x84, 0x0b, 0xaa, - 0x0b, 0xab, 0x0f, 0xee, 0x01, 0xc0, 0x0f, 0xee, 0x0a, 0x7b, 0x0b, 0xa7, - 0x09, 0xa6, 0x09, 0xa1, 0x01, 0x91, 0x09, 0xc8, 0x01, 0x56, 0x1f, 0xf9, - 0x16, 0x24, 0x0c, 0x21, 0x0f, 0xd7, 0x1f, 0xf9, 0x1f, 0xe1, 0x1f, 0xf9, - 0x0f, 0xd9, 0x0a, 0x80, 0x09, 0xee, 0x00, 0x08, 0x0f, 0xf6, 0x00, 0x26, - 0x0c, 0x27, 0x09, 0xa2, 0x0e, 0x65, 0x0f, 0xc4, 0x01, 0xce, 0x0b, 0x05, - 0x09, 0x83, 0x0f, 0x38, 0x0a, 0xc0, 0x0f, 0xc4, 0x01, 0xcf, 0x00, 0x00, - 0x02, 0x04, 0x0f, 0xc2, 0x00, 0x28, 0x0f, 0xc2, 0x00, 0x29, 0x0f, 0xc2, - 0x00, 0x2b, 0x0f, 0xc2, 0x00, 0x2d, 0x0f, 0xc2, 0x00, 0x2f, 0x0f, 0xc2, - 0x00, 0x33, 0x0f, 0xc2, 0x00, 0x37, 0x0f, 0xc2, 0x00, 0x3b, 0x0f, 0xc4, - 0x00, 0x28, 0x0f, 0xc2, 0x00, 0x88, 0x0f, 0xc2, 0x00, 0x3d, 0x0f, 0xc2, - 0x00, 0xb6, 0x0f, 0xc2, 0x00, 0x56, 0x0f, 0xc2, 0x00, 0xac, 0x0f, 0xc2, - 0x00, 0x6b, 0x0f, 0xc2, 0x00, 0xa0, 0x07, 0x82, 0x0f, 0xc2, 0x00, 0x59, - 0x0f, 0xc2, 0x00, 0x94, 0x0f, 0xc2, 0x00, 0xcf, 0x0f, 0xc2, 0x00, 0x32, - 0x0f, 0xc2, 0x00, 0x63, 0x0f, 0xc2, 0x00, 0x95, 0x0f, 0xc2, 0x00, 0xc6, - 0x0f, 0xc2, 0x00, 0x4a, 0x0f, 0xc2, 0x00, 0x6f, 0x0f, 0xc2, 0x00, 0x94, - 0x0f, 0xc2, 0x00, 0xb9, 0x0f, 0x38, 0x00, 0x02, 0x0f, 0xc4, 0x01, 0x70, - 0x00, 0x00, 0x0f, 0xc4, 0x00, 0x6c, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, - 0x0f, 0x38, 0x00, 0x02, 0x00, 0x21, 0x0c, 0x16, 0x19, 0xc8, 0x0d, 0x09, - 0x0c, 0x84, 0x0c, 0xfe, 0x0f, 0xfd, 0x16, 0x86, 0x0b, 0xa1, 0x0c, 0x17, - 0x09, 0xce, 0x10, 0x21, 0x1d, 0x91, 0x19, 0xce, 0x0c, 0x61, 0x0d, 0x96, - 0x1d, 0x89, 0x0c, 0x6a, 0x0c, 0x6c, 0x0f, 0x38, 0x0d, 0x6e, 0x0f, 0xc4, - 0x05, 0xeb, 0x0b, 0x08, 0x0f, 0xc4, 0x05, 0xea, 0x0b, 0x09, 0x00, 0x0a, - 0x0c, 0x61, 0x00, 0x14, 0x1f, 0xf9, 0x16, 0xaa, 0x00, 0x55, 0x1f, 0xf9, - 0x16, 0xa1, 0x00, 0x4a, 0x0c, 0x21, 0x00, 0x94, 0x10, 0x8a, 0x00, 0xd4, - 0x0f, 0xf8, 0x16, 0xaa, 0x10, 0xca, 0x00, 0x55, 0x1f, 0xf9, 0x16, 0xaa, - 0x01, 0x0a, 0x0c, 0x21, 0x00, 0x94, 0x11, 0x4a, 0x00, 0xd4, 0x11, 0x8a, - 0x0f, 0xc4, 0x01, 0xcf, 0x0c, 0x80, 0x0f, 0xf0, 0x0a, 0x0d, 0x00, 0x32, - 0x0f, 0xf6, 0x05, 0x5c, 0x01, 0x08, 0x0f, 0xc4, 0x00, 0x6c, 0x0b, 0xaa, - 0x0b, 0xab, 0x0b, 0xac, 0x0b, 0xad, 0x0f, 0xee, 0x03, 0x00, 0x0f, 0xc5, - 0x01, 0xcf, 0x0b, 0x61, 0x02, 0x19, 0x09, 0xc5, 0x0b, 0xca, 0x0b, 0xe1, - 0x0c, 0x91, 0x09, 0xcb, 0x0f, 0xcc, 0x07, 0xff, 0x0f, 0xcd, 0x0c, 0xc0, - 0x00, 0x2b, 0x00, 0x2d, 0x0f, 0xf1, 0x03, 0x39, 0x0f, 0xce, 0x00, 0xc2, - 0x0f, 0xcf, 0x07, 0x68, 0x07, 0x37, 0x1f, 0xce, 0x00, 0x41, 0x1f, 0xcf, - 0x01, 0xe9, 0x0a, 0x61, 0x0f, 0xf1, 0x03, 0x39, 0x0d, 0x93, 0x1f, 0xf9, - 0x16, 0xd5, 0x0f, 0xf1, 0x0a, 0x22, 0x0a, 0x48, 0x0f, 0xf1, 0x0a, 0x23, - 0x0f, 0xfb, 0x16, 0x76, 0x0a, 0x48, 0x0f, 0xf1, 0x0a, 0x22, 0x0f, 0xfb, - 0x16, 0x76, 0x0a, 0x48, 0x0f, 0xf1, 0x03, 0x39, 0x0f, 0xc4, 0x01, 0x70, - 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x0f, 0xc4, 0x06, 0xff, - 0x0b, 0x12, 0x1f, 0xf9, 0x17, 0x04, 0x0a, 0x61, 0x0d, 0xd3, 0x1f, 0xf9, - 0x16, 0xde, 0x0f, 0xc4, 0x00, 0x6c, 0x0f, 0xee, 0x05, 0x00, 0x0e, 0x02, - 0x0e, 0x42, 0x0f, 0xee, 0x05, 0x40, 0x0e, 0x02, 0x0f, 0x38, 0x0e, 0x42, - 0x0f, 0xee, 0x0a, 0xef, 0x0f, 0xe2, 0x00, 0x3f, 0x0f, 0xe1, 0x1f, 0xf6, - 0x0f, 0xc4, 0x00, 0x80, 0x0f, 0xee, 0x09, 0x00, 0x0e, 0x02, 0x0e, 0x42, - 0x0e, 0xa4, 0x09, 0x99, 0x09, 0xe2, 0x0f, 0xe4, 0x07, 0xff, 0x0f, 0x38, - 0x09, 0x82, 0x0f, 0xfb, 0x17, 0x68, 0x0f, 0xfb, 0x0c, 0x26, 0x0f, 0xfb, - 0x0c, 0xf8, 0x0f, 0xf7, 0x0d, 0xa3, 0x0f, 0xfb, 0x18, 0x62, 0x0f, 0xfb, - 0x1f, 0x0b, 0x0f, 0xfb, 0x13, 0xae, 0x0f, 0xf7, 0x05, 0x92, 0x0f, 0xf6, - 0x05, 0x8d, 0x02, 0x48, 0x1f, 0xf9, 0x17, 0x33, 0x0f, 0xc4, 0x01, 0x69, - 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x0f, 0xfb, 0x1a, 0xa8, 0x0f, 0xf6, - 0x05, 0x8d, 0x02, 0x88, 0x1f, 0xf9, 0x17, 0x45, 0x00, 0x61, 0x0f, 0xc4, - 0x01, 0x67, 0x0b, 0x19, 0x09, 0xc0, 0x0f, 0xc4, 0x01, 0x66, 0x0b, 0x19, - 0x09, 0xc0, 0x02, 0xba, 0x00, 0x48, 0x0f, 0xf9, 0x17, 0x47, 0x02, 0xba, - 0x00, 0x08, 0x0f, 0xf6, 0x05, 0x8d, 0x02, 0xc8, 0x1f, 0xf9, 0x17, 0x54, - 0x0f, 0xc4, 0x01, 0x68, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x0f, 0xc4, - 0x07, 0xbf, 0x00, 0x40, 0x0f, 0xc8, 0x0e, 0x00, 0x0f, 0xf7, 0x05, 0x94, - 0x0f, 0xfb, 0x03, 0x96, 0x0f, 0xc4, 0x01, 0x6c, 0x0f, 0xf1, 0x0c, 0x06, - 0x0a, 0x40, 0x0f, 0xfb, 0x1a, 0xcf, 0x0f, 0xfb, 0x03, 0xdd, 0x0f, 0xfb, - 0x18, 0xd3, 0x0f, 0xfb, 0x19, 0x16, 0x0f, 0x39, 0x0f, 0xc4, 0x06, 0x92, - 0x0b, 0x22, 0x0f, 0xe4, 0x0d, 0xff, 0x09, 0x80, 0x07, 0x64, 0x09, 0xa2, - 0x0f, 0xe5, 0x1f, 0xe2, 0x09, 0xa2, 0x04, 0x84, 0x0b, 0x24, 0x09, 0x80, - 0x04, 0x84, 0x0b, 0x21, 0x01, 0x1e, 0x1f, 0xf9, 0x17, 0x87, 0x0f, 0xc4, - 0x06, 0xa7, 0x02, 0x37, 0x0f, 0xc4, 0x06, 0xae, 0x00, 0x37, 0x0f, 0xc4, - 0x07, 0x5a, 0x06, 0xb7, 0x0f, 0xc4, 0x00, 0x77, 0x00, 0x37, 0x04, 0x84, - 0x0b, 0x21, 0x00, 0xde, 0x1f, 0xf9, 0x17, 0x9b, 0x0f, 0xc4, 0x06, 0xaa, - 0x02, 0x37, 0x0f, 0xc4, 0x07, 0x0b, 0x02, 0xb7, 0x0f, 0xc4, 0x00, 0x7a, - 0x00, 0x37, 0x0f, 0xc4, 0x07, 0x57, 0x06, 0xb7, 0x0f, 0xc4, 0x00, 0x74, - 0x00, 0x37, 0x04, 0x84, 0x0b, 0x21, 0x00, 0x9e, 0x1f, 0xf9, 0x17, 0xb5, - 0x00, 0x21, 0x01, 0x9f, 0x09, 0xe1, 0x01, 0xdf, 0x09, 0xe2, 0x0b, 0x25, - 0x09, 0x80, 0x0f, 0xc4, 0x06, 0xa4, 0x02, 0x37, 0x0f, 0xc4, 0x00, 0x77, - 0x02, 0xb7, 0x0f, 0xc4, 0x07, 0x67, 0x02, 0xb7, 0x0f, 0xc4, 0x06, 0x96, - 0x00, 0x37, 0x0f, 0xf7, 0x0d, 0x69, 0x04, 0x84, 0x0b, 0x21, 0x00, 0x1e, - 0x1f, 0xf9, 0x17, 0xef, 0x00, 0x21, 0x01, 0x9f, 0x09, 0xe2, 0x0b, 0x25, - 0x09, 0x80, 0x0f, 0xc4, 0x01, 0x5c, 0x0b, 0x21, 0x03, 0x95, 0x1f, 0xf9, - 0x17, 0xd3, 0x04, 0xc4, 0x0f, 0xc5, 0x06, 0x9f, 0x0f, 0xf7, 0x02, 0x74, - 0x03, 0x37, 0x03, 0xb7, 0x00, 0xb7, 0x05, 0x37, 0x04, 0x37, 0x00, 0x36, - 0x04, 0xc4, 0x0f, 0xf9, 0x17, 0xef, 0x0f, 0xc4, 0x01, 0x44, 0x0b, 0x88, - 0x00, 0xb6, 0x0b, 0x89, 0x0f, 0xc8, 0x1f, 0xf4, 0x01, 0x37, 0x0f, 0xc4, - 0x00, 0x86, 0x00, 0x37, 0x0f, 0xc4, 0x07, 0x08, 0x06, 0xb7, 0x0f, 0xc4, - 0x00, 0x89, 0x00, 0x37, 0x0f, 0xc4, 0x06, 0x9f, 0x02, 0xb7, 0x0f, 0xc4, - 0x00, 0x74, 0x02, 0xb7, 0x0f, 0xc4, 0x07, 0x64, 0x02, 0xb7, 0x00, 0x36, - 0x04, 0xc4, 0x04, 0x84, 0x0b, 0x21, 0x00, 0x5e, 0x1f, 0xf9, 0x18, 0x0c, - 0x00, 0x21, 0x01, 0x9f, 0x09, 0xe2, 0x0b, 0x25, 0x09, 0x80, 0x00, 0x21, - 0x0f, 0xc4, 0x06, 0xa2, 0x0b, 0x88, 0x06, 0xba, 0x0b, 0x89, 0x10, 0x21, - 0x1c, 0x18, 0x19, 0xc8, 0x1c, 0x51, 0x19, 0xc9, 0x0f, 0xc4, 0x06, 0x8f, - 0x0b, 0x21, 0x0c, 0x20, 0x09, 0xc2, 0x0b, 0x21, 0x0c, 0x59, 0x09, 0xc2, - 0x04, 0x84, 0x0b, 0x21, 0x01, 0x9e, 0x1f, 0xf9, 0x18, 0x33, 0x0f, 0xc4, - 0x06, 0x8f, 0x0b, 0x88, 0x00, 0xb6, 0x0b, 0x89, 0x06, 0xbb, 0x1f, 0xf7, - 0x00, 0x8f, 0x02, 0xb6, 0x04, 0xc4, 0x0f, 0xc4, 0x00, 0x92, 0x00, 0x37, - 0x0f, 0xc4, 0x06, 0x9c, 0x06, 0xb7, 0x03, 0xb7, 0x06, 0xbb, 0x0f, 0xe1, - 0x04, 0x00, 0x1f, 0xe1, 0x0c, 0x00, 0x0c, 0x59, 0x09, 0xc9, 0x0f, 0xc4, - 0x01, 0x30, 0x0c, 0x02, 0x0c, 0x42, 0x0f, 0xf0, 0x03, 0x0a, 0x0c, 0x32, - 0x0f, 0xf0, 0x03, 0x09, 0x0c, 0x72, 0x04, 0x84, 0x0b, 0x21, 0x01, 0xde, - 0x1f, 0xf9, 0x18, 0x4e, 0x0f, 0xc4, 0x06, 0x96, 0x02, 0x37, 0x01, 0x36, - 0x06, 0x08, 0x03, 0xb7, 0x0f, 0xc4, 0x01, 0x32, 0x0c, 0x02, 0x0c, 0x42, - 0x0c, 0x61, 0x02, 0xdf, 0x11, 0x3a, 0x12, 0x08, 0x1f, 0xf9, 0x18, 0x50, - 0x0f, 0xf0, 0x03, 0x1a, 0x0c, 0x32, 0x0f, 0xf0, 0x03, 0x19, 0x0c, 0x72, - 0x04, 0x84, 0x00, 0x00, 0x0f, 0x39, 0x0f, 0xf1, 0x03, 0x3a, 0x0f, 0xc4, - 0x07, 0xe2, 0x0a, 0x48, 0x0c, 0x00, 0x0f, 0xc4, 0x07, 0xe3, 0x0c, 0x00, - 0x0f, 0xf1, 0x03, 0x03, 0x0f, 0xc4, 0x07, 0xe4, 0x0f, 0xc2, 0x08, 0x00, - 0x0f, 0x38, 0x0a, 0x42, 0x0f, 0xc4, 0x07, 0xe1, 0x00, 0x21, 0x0b, 0x14, - 0x1f, 0xf9, 0x18, 0xd2, 0x0f, 0xc4, 0x07, 0xea, 0x0b, 0x15, 0x0f, 0xc8, - 0x03, 0x03, 0x1f, 0xc8, 0x03, 0x06, 0x0c, 0x31, 0x0f, 0xc4, 0x07, 0xe5, - 0x0a, 0x40, 0x0f, 0xf1, 0x03, 0x3a, 0x0f, 0xc4, 0x07, 0xe2, 0x0a, 0x48, - 0x0c, 0x00, 0x0f, 0xc4, 0x07, 0xe3, 0x0c, 0x00, 0x0f, 0xc4, 0x07, 0xe1, - 0x0b, 0x09, 0x0c, 0x61, 0x0c, 0x13, 0x1c, 0x21, 0x1c, 0x51, 0x09, 0xe1, - 0x0f, 0xc4, 0x07, 0xf1, 0x0b, 0x13, 0x1f, 0xf9, 0x18, 0xd2, 0x0c, 0x61, - 0x0c, 0x12, 0x0f, 0xcb, 0x18, 0xa4, 0x1f, 0xcb, 0x18, 0xb2, 0x09, 0xca, - 0x00, 0x21, 0x0c, 0x91, 0x19, 0xd1, 0x09, 0xe1, 0x0f, 0xc4, 0x07, 0xf2, - 0x0b, 0x16, 0x0f, 0xc4, 0x07, 0xe6, 0x1f, 0xc4, 0x07, 0xe8, 0x0b, 0x88, - 0x0b, 0x89, 0x0f, 0xc4, 0x07, 0xf0, 0x0b, 0x21, 0x0f, 0xc4, 0x07, 0xe4, - 0x0c, 0xf8, 0x00, 0x15, 0x1f, 0xf9, 0x18, 0xb4, 0x0b, 0xa1, 0x0c, 0x18, - 0x09, 0xc8, 0x0b, 0xa1, 0x0c, 0x51, 0x09, 0xc9, 0x00, 0x21, 0x0c, 0x56, - 0x10, 0x08, 0x0f, 0xf8, 0x18, 0xc1, 0x10, 0x09, 0x1f, 0xf9, 0x18, 0xa6, - 0x0b, 0xa1, 0x0c, 0x20, 0x09, 0xc8, 0x0b, 0xa1, 0x0c, 0x59, 0x09, 0xc9, - 0x0c, 0x61, 0x0f, 0xd6, 0x00, 0xff, 0x1f, 0xc8, 0x0f, 0xff, 0x1f, 0xc9, - 0x00, 0xff, 0x0f, 0xc4, 0x07, 0xe4, 0x0c, 0x02, 0x0c, 0x42, 0x00, 0x21, - 0x0f, 0xc4, 0x07, 0xea, 0x0b, 0x14, 0x1f, 0xf0, 0x03, 0x03, 0x1c, 0x72, - 0x0f, 0xc4, 0x07, 0xeb, 0x0b, 0x14, 0x1f, 0xf0, 0x03, 0x06, 0x1c, 0x72, - 0x0f, 0x39, 0x0f, 0xc5, 0x01, 0x65, 0x0f, 0xc4, 0x01, 0x81, 0x0b, 0x21, - 0x00, 0x14, 0x1f, 0x38, 0x10, 0x01, 0x0f, 0xc4, 0x07, 0x6c, 0x0b, 0x21, - 0x00, 0x14, 0x09, 0xcb, 0x1f, 0x38, 0x10, 0x01, 0x0f, 0xc4, 0x07, 0x6a, - 0x0b, 0x08, 0x0f, 0xc4, 0x07, 0x6b, 0x0b, 0x09, 0x0c, 0x21, 0x0c, 0x59, - 0x09, 0xc9, 0x0f, 0xc4, 0x01, 0x65, 0x0f, 0xc5, 0x01, 0x66, 0x0b, 0x21, - 0x00, 0x59, 0x09, 0xc0, 0x0c, 0x14, 0x1f, 0x38, 0x10, 0x01, 0x0c, 0x55, - 0x1f, 0x39, 0x0c, 0x00, 0x0b, 0x61, 0x0c, 0xd6, 0x1f, 0x39, 0x01, 0x38, - 0x01, 0xc8, 0x0b, 0x21, 0x0f, 0xd9, 0x00, 0x48, 0x09, 0xc5, 0x00, 0x59, - 0x09, 0xc0, 0x09, 0xe1, 0x02, 0x12, 0x0f, 0x38, 0x10, 0x00, 0x0f, 0xc4, - 0x01, 0xd2, 0x0b, 0x21, 0x02, 0x13, 0x1f, 0xf9, 0x19, 0x0e, 0x0f, 0x39, - 0x00, 0x59, 0x09, 0xc0, 0x0f, 0xc4, 0x01, 0xd0, 0x0f, 0xfb, 0x18, 0xfd, - 0x0f, 0x38, 0x0c, 0x01, 0x0f, 0xf1, 0x03, 0x39, 0x0f, 0xc4, 0x01, 0x6a, - 0x00, 0x00, 0x0f, 0xc4, 0x01, 0x6b, 0x0a, 0x40, 0x0f, 0xc4, 0x01, 0xd2, - 0x0b, 0x21, 0x00, 0x17, 0x1f, 0x38, 0x10, 0x00, 0x00, 0x51, 0x09, 0xc0, - 0x0f, 0xc4, 0x01, 0xd1, 0x0f, 0xfb, 0x18, 0xfd, 0x0b, 0x48, 0x0f, 0xc4, - 0x01, 0x6a, 0x0c, 0x38, 0x0c, 0x00, 0x05, 0x38, 0x0f, 0x08, 0x0d, 0x30, - 0x0d, 0x21, 0x00, 0x59, 0x09, 0xcc, 0x0d, 0x61, 0x0c, 0xa0, 0x09, 0xea, - 0x00, 0x21, 0x0c, 0xd9, 0x09, 0xeb, 0x0f, 0xee, 0x01, 0xc0, 0x1f, 0xee, - 0x0a, 0x7e, 0x0c, 0x21, 0x0e, 0x20, 0x09, 0xce, 0x0c, 0x61, 0x0e, 0x59, - 0x09, 0xf2, 0x0d, 0x83, 0x09, 0xc3, 0x0d, 0x21, 0x00, 0x59, 0x0d, 0x30, - 0x0d, 0xb2, 0x0f, 0x38, 0x09, 0xcc, 0x0f, 0xc4, 0x07, 0x0e, 0x00, 0x02, - 0x00, 0x02, 0x0f, 0xc2, 0x01, 0x90, 0x00, 0x02, 0x0f, 0xc2, 0x00, 0x83, - 0x00, 0x42, 0x0f, 0xc2, 0x04, 0x07, 0x0f, 0x38, 0x00, 0x42, 0x0f, 0xc4, - 0x07, 0x0e, 0x0b, 0x8a, 0x0f, 0xfa, 0x19, 0x31, 0x0b, 0x8b, 0x0b, 0x8a, - 0x0f, 0xfa, 0x19, 0x31, 0x0b, 0x8b, 0x0b, 0x8a, 0x0f, 0xfa, 0x19, 0x31, - 0x0b, 0x8b, 0x0b, 0x8a, 0x0f, 0xf8, 0x19, 0x31, 0x0b, 0x8b, 0x0f, 0xc5, - 0x04, 0xa8, 0x07, 0x37, 0x0f, 0xcc, 0x05, 0x38, 0x0f, 0xcd, 0x02, 0xb0, - 0x0f, 0xfb, 0x19, 0x5b, 0x0f, 0xcc, 0x0a, 0x38, 0x0f, 0xfa, 0x19, 0x5b, - 0x00, 0x0d, 0x0f, 0xf0, 0x05, 0x2e, 0x00, 0xf2, 0x0f, 0xf1, 0x0a, 0x2e, - 0x0a, 0x62, 0x0f, 0xe5, 0x01, 0xc0, 0x0f, 0x38, 0x09, 0xb2, 0x00, 0x04, - 0x0c, 0x00, 0x0c, 0x21, 0x02, 0xdf, 0x1f, 0xf9, 0x19, 0x94, 0x0c, 0x27, - 0x0c, 0x21, 0x09, 0x99, 0x09, 0xc8, 0x0f, 0xfa, 0x19, 0x6d, 0x00, 0x09, - 0x0f, 0xf9, 0x19, 0xa1, 0x00, 0x21, 0x0c, 0x11, 0x09, 0xe7, 0x09, 0xe1, - 0x09, 0x99, 0x09, 0xc8, 0x00, 0x21, 0x0c, 0x11, 0x09, 0xc8, 0x0f, 0xc9, - 0x1f, 0xff, 0x0f, 0xfb, 0x19, 0x6d, 0x00, 0x04, 0x0f, 0x38, 0x0b, 0x08, - 0x0f, 0xf1, 0x0a, 0x33, 0x0f, 0xc4, 0x05, 0xe8, 0x0a, 0x48, 0x0c, 0x02, - 0x0f, 0xee, 0x0a, 0x7f, 0x0c, 0x2a, 0x00, 0x2b, 0x0f, 0xee, 0x02, 0x40, - 0x0f, 0xee, 0x0a, 0x01, 0x08, 0x36, 0x02, 0x08, 0x0f, 0xc4, 0x05, 0xe9, - 0x0b, 0x21, 0x00, 0x14, 0x1f, 0xc4, 0x01, 0x41, 0x1b, 0x22, 0x1f, 0xe4, - 0x0f, 0xef, 0x19, 0x80, 0x00, 0x1e, 0x0f, 0xc5, 0x01, 0x7d, 0x1f, 0x38, - 0x1c, 0x41, 0x00, 0x2b, 0x0c, 0x6a, 0x0f, 0xee, 0x01, 0xc0, 0x0f, 0xee, - 0x0a, 0x78, 0x0b, 0x6a, 0x0f, 0xee, 0x02, 0x40, 0x0f, 0xee, 0x0a, 0x08, - 0x0f, 0xc4, 0x01, 0x40, 0x04, 0x22, 0x0e, 0x02, 0x0e, 0x65, 0x0f, 0x38, - 0x09, 0x82, 0x0f, 0xc4, 0x05, 0xf3, 0x0f, 0xc2, 0x0f, 0x80, 0x0f, 0xc2, - 0x0f, 0xff, 0x0f, 0xc2, 0x07, 0xff, 0x00, 0x02, 0x0f, 0xc2, 0x0f, 0xc0, - 0x01, 0x82, 0x0f, 0xc4, 0x00, 0x3c, 0x00, 0x42, 0x00, 0x82, 0x01, 0x82, - 0x03, 0x02, 0x07, 0x02, 0x0f, 0xc2, 0x00, 0x30, 0x0f, 0xc2, 0x00, 0x70, - 0x0f, 0xc2, 0x00, 0xf0, 0x0f, 0xc2, 0x01, 0xd0, 0x0f, 0xc2, 0x03, 0x50, - 0x0f, 0xc2, 0x07, 0x50, 0x0f, 0xc2, 0x0e, 0x50, 0x0f, 0x39, 0x0f, 0xc4, - 0x01, 0xd4, 0x0f, 0x00, 0x0f, 0xc4, 0x05, 0xf9, 0x02, 0x37, 0x0f, 0xc4, - 0x06, 0x34, 0x02, 0xb7, 0x0f, 0xc4, 0x05, 0xf6, 0x0f, 0xf7, 0x02, 0x85, - 0x0f, 0xf7, 0x01, 0x33, 0x0f, 0xc4, 0x01, 0xd3, 0x0c, 0x21, 0x00, 0x51, - 0x09, 0xc0, 0x09, 0xcf, 0x09, 0xe1, 0x0f, 0xd9, 0x00, 0x3c, 0x09, 0xc4, - 0x0b, 0x0d, 0x0f, 0xc4, 0x05, 0xf9, 0x0f, 0xc5, 0x01, 0x2b, 0x04, 0xb7, - 0x0f, 0xc4, 0x00, 0x70, 0x0d, 0x42, 0x0d, 0x82, 0x01, 0xba, 0x0d, 0xc2, - 0x0f, 0xc4, 0x00, 0x70, 0x0b, 0x8d, 0x0b, 0x8e, 0x0b, 0x8f, 0x0d, 0xe1, - 0x00, 0x2a, 0x00, 0x59, 0x09, 0xeb, 0x0f, 0xee, 0x01, 0xc0, 0x0f, 0xee, - 0x0a, 0xcb, 0x05, 0x84, 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0x82, 0x0f, 0xc4, - 0x01, 0x28, 0x00, 0x37, 0x0f, 0xc4, 0x05, 0xf9, 0x06, 0xb7, 0x0f, 0xf7, - 0x01, 0x33, 0x0c, 0x21, 0x0d, 0xe7, 0x09, 0x91, 0x09, 0xce, 0x0d, 0xa1, - 0x0f, 0xd2, 0x00, 0x80, 0x1f, 0xce, 0x00, 0x7f, 0x0d, 0xa1, 0x09, 0x99, - 0x00, 0x2a, 0x09, 0xeb, 0x0f, 0xee, 0x01, 0xc0, 0x0f, 0xee, 0x0a, 0xcb, - 0x05, 0x84, 0x0e, 0x02, 0x0e, 0x42, 0x0e, 0x82, 0x0f, 0xc4, 0x01, 0x28, - 0x0f, 0xf7, 0x02, 0x81, 0x0f, 0xc4, 0x05, 0xf9, 0x0f, 0xf7, 0x02, 0x93, - 0x0f, 0xf7, 0x02, 0x05, 0x02, 0xdf, 0x1f, 0xf9, 0x1a, 0x69, 0x0f, 0xc4, - 0x01, 0x2b, 0x0f, 0xf7, 0x02, 0x90, 0x0f, 0xf7, 0x02, 0x05, 0x1f, 0xf9, - 0x1a, 0x69, 0x06, 0x44, 0x0f, 0xc5, 0x01, 0x2b, 0x04, 0xb7, 0x0f, 0xc4, - 0x05, 0xfc, 0x0d, 0x80, 0x0f, 0xc4, 0x05, 0xfd, 0x0d, 0xc0, 0x0d, 0xe1, - 0x00, 0x53, 0x1f, 0xf9, 0x1a, 0x74, 0x09, 0xcf, 0x0d, 0x61, 0x0d, 0xdf, - 0x1f, 0xf9, 0x1a, 0x16, 0x0f, 0xf9, 0x1a, 0x69, 0x0f, 0xc4, 0x01, 0xd4, - 0x0b, 0x39, 0x0f, 0xc4, 0x05, 0xff, 0x0b, 0x0f, 0x0d, 0xe1, 0x00, 0x2b, - 0x0f, 0xea, 0x0c, 0xe5, 0x00, 0xd4, 0x1f, 0xea, 0x05, 0xac, 0x01, 0x14, - 0x1f, 0xea, 0x03, 0x44, 0x01, 0x94, 0x1f, 0xea, 0x01, 0x56, 0x02, 0x14, - 0x1f, 0xea, 0x00, 0x83, 0x0f, 0xc4, 0x05, 0xf0, 0x0b, 0x0e, 0x0d, 0xa1, - 0x00, 0x2c, 0x03, 0x2d, 0x00, 0x54, 0x11, 0xad, 0x00, 0x94, 0x11, 0x2d, - 0x0f, 0xee, 0x0c, 0x80, 0x00, 0xa1, 0x0f, 0xc4, 0x01, 0x73, 0x0e, 0x19, - 0x09, 0xc0, 0x0f, 0xc4, 0x01, 0x75, 0x00, 0x40, 0x0d, 0xa1, 0x00, 0x94, - 0x10, 0x00, 0x00, 0x54, 0x0d, 0xe1, 0x10, 0x96, 0x10, 0x00, 0x00, 0xd6, - 0x0f, 0x38, 0x10, 0x00, 0x0f, 0xc8, 0x1a, 0xab, 0x05, 0x39, 0x0f, 0xf7, - 0x0d, 0xf7, 0x0f, 0xfb, 0x19, 0xa4, 0x0f, 0xc4, 0x07, 0xba, 0x0f, 0xfb, - 0x02, 0xfd, 0x01, 0xbb, 0x0f, 0xf7, 0x0e, 0x2a, 0x01, 0xbb, 0x0f, 0xf7, - 0x0e, 0x7e, 0x01, 0xbb, 0x0f, 0xfb, 0x19, 0xf7, 0x01, 0xbb, 0x0f, 0xf7, - 0x0e, 0xff, 0x01, 0xbb, 0x0f, 0xfb, 0x1a, 0x77, 0x0f, 0xf6, 0x00, 0x42, - 0x02, 0x8b, 0x1f, 0xf7, 0x0f, 0x52, 0x0f, 0xc4, 0x06, 0x00, 0x0f, 0xf0, - 0x0a, 0x01, 0x0f, 0x38, 0x0b, 0x32, 0x0f, 0xff, 0x0f, 0x6b, 0x0f, 0xf1, - 0x0c, 0x0a, 0x0f, 0xc4, 0x01, 0x6d, 0x0a, 0x49, 0x0c, 0x61, 0x00, 0x1e, - 0x1f, 0xf8, 0x1b, 0x0b, 0x0c, 0x40, 0x0f, 0xf1, 0x0c, 0x07, 0x0f, 0xc4, - 0x01, 0x36, 0x0f, 0xc5, 0x07, 0x60, 0x00, 0x2b, 0x0a, 0x6a, 0x0f, 0xf1, - 0x0c, 0x08, 0x0f, 0xee, 0x01, 0xc0, 0x0f, 0xee, 0x0a, 0x06, 0x0e, 0x22, - 0x0a, 0x65, 0x09, 0x82, 0x0e, 0x42, 0x0f, 0xc4, 0x01, 0x56, 0x0b, 0x21, - 0x09, 0xa0, 0x09, 0xc2, 0x0b, 0x21, 0x0e, 0x59, 0x09, 0xc2, 0x0f, 0xc4, - 0x01, 0xd5, 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x0b, 0x53, - 0x1f, 0xf9, 0x1b, 0x0b, 0x0f, 0xc5, 0x01, 0x76, 0x0b, 0x01, 0x00, 0x00, - 0x0f, 0xc5, 0x01, 0x38, 0x0f, 0xc4, 0x01, 0x56, 0x0b, 0x03, 0x00, 0x02, - 0x0b, 0x03, 0x00, 0x02, 0x0f, 0xfa, 0x03, 0x00, 0x02, 0x08, 0x0c, 0x61, - 0x00, 0x5e, 0x1f, 0x39, 0x0f, 0xf1, 0x0c, 0x0c, 0x0f, 0xc4, 0x01, 0x5a, - 0x0b, 0x21, 0x0a, 0x60, 0x09, 0xc2, 0x0b, 0x21, 0x00, 0x19, 0x09, 0xc0, - 0x0f, 0xf1, 0x0c, 0x09, 0x0f, 0xc4, 0x01, 0x58, 0x0b, 0x21, 0x0f, 0xc5, - 0x07, 0x61, 0x0a, 0x48, 0x0c, 0x20, 0x09, 0xc2, 0x0b, 0x21, 0x00, 0x19, - 0x09, 0xc2, 0x0f, 0xc4, 0x01, 0x74, 0x0c, 0x00, 0x0f, 0xc4, 0x01, 0xd6, - 0x0b, 0x21, 0x00, 0x59, 0x09, 0xc0, 0x09, 0xe1, 0x0b, 0x53, 0x1f, 0x39, - 0x0f, 0xc5, 0x01, 0x77, 0x0b, 0x01, 0x00, 0x00, 0x0f, 0xc5, 0x01, 0x3a, - 0x0f, 0xc4, 0x01, 0x58, 0x0b, 0x03, 0x00, 0x02, 0x0b, 0x03, 0x00, 0x02, - 0x0f, 0xc5, 0x01, 0x3c, 0x0f, 0xc4, 0x01, 0x5a, 0x0b, 0x03, 0x00, 0x02, - 0x0b, 0x03, 0x00, 0x02, 0x0f, 0xf8, 0x03, 0x00, 0x04, 0x08, 0x0f, 0xf1, - 0x0f, 0x17, 0x0f, 0xe2, 0x0f, 0xf0, 0x0c, 0x21, 0x0a, 0x64, 0x09, 0x99, - 0x09, 0xf2, 0x00, 0x09, 0x0c, 0x22, 0x03, 0xe4, 0x09, 0xa1, 0x00, 0x94, - 0x11, 0x09, 0x00, 0x54, 0x10, 0x49, 0x01, 0x54, 0x10, 0x89, 0x0c, 0x61, - 0x00, 0x14, 0x1f, 0x39, 0x01, 0x14, 0x0f, 0xc4, 0x01, 0xd7, 0x0b, 0x21, - 0x10, 0x40, 0x10, 0x15, 0x1f, 0x39, 0x0f, 0xf8, 0x03, 0x00, 0x0c, 0x48, - 0x0f, 0x39, 0x00, 0x04, 0x0f, 0x00, 0x04, 0x04, 0x0b, 0x27, 0x09, 0xa7, - 0x09, 0xa7, 0x09, 0xa7, 0x09, 0xa2, 0x0c, 0x25, 0x0f, 0xc5, 0x07, 0x6e, - 0x09, 0x81, 0x07, 0xba, 0x04, 0x48, 0x0f, 0xc4, 0x07, 0x6d, 0x0b, 0x21, - 0x00, 0x15, 0x00, 0x48, 0x12, 0x08, 0x04, 0x04, 0x0c, 0x00, 0x00, 0x04, - 0x0b, 0x39, 0x00, 0x04, 0x0f, 0x00, 0x0f, 0xc4, 0x07, 0x80, 0x0f, 0xc8, - 0x08, 0x00, 0x0f, 0xf7, 0x00, 0x71, 0x0f, 0xf1, 0x0f, 0x14, 0x0f, 0xc4, - 0x07, 0xf4, 0x0a, 0x42, 0x0f, 0xf1, 0x0f, 0x15, 0x0a, 0x42, 0x0f, 0xf1, - 0x03, 0x0a, 0x0f, 0xc4, 0x07, 0xf6, 0x0a, 0x42, 0x0f, 0xf1, 0x03, 0x09, - 0x0a, 0x42, 0x0f, 0xf1, 0x03, 0x1a, 0x0f, 0xc4, 0x07, 0xf8, 0x0a, 0x42, - 0x0f, 0xf1, 0x03, 0x19, 0x0a, 0x42, 0x0f, 0xf1, 0x03, 0x38, 0x0f, 0xc4, - 0x07, 0xfa, 0x0a, 0x40, 0x0f, 0xf1, 0x03, 0x11, 0x0f, 0xc4, 0x07, 0xfb, - 0x0a, 0x40, 0x0f, 0xf1, 0x0c, 0x05, 0x0f, 0xc4, 0x07, 0xfc, 0x0a, 0x40, - 0x0f, 0xc4, 0x07, 0xfe, 0x0f, 0xc2, 0x07, 0x06, 0x0f, 0xc2, 0x00, 0x80, - 0x00, 0x04, 0x0b, 0x39, 0x0f, 0xc4, 0x07, 0xf3, 0x0f, 0x00, 0x0f, 0xc4, - 0x06, 0xc0, 0x0f, 0xc8, 0x07, 0x80, 0x0f, 0xf7, 0x00, 0x71, 0x0f, 0xf0, - 0x0f, 0x17, 0x00, 0x32, 0x0f, 0xf0, 0x02, 0x04, 0x00, 0x32, 0x0f, 0xfa, - 0x01, 0x92, 0x0e, 0xff, 0x0f, 0xc8, 0x08, 0x89, 0x0f, 0xc9, 0x08, 0x88, - 0x0f, 0xca, 0x07, 0xfc, 0x0f, 0xcb, 0x07, 0xfe, 0x0f, 0xc4, 0x06, 0xe3, - 0x0c, 0x02, 0x0c, 0x42, 0x0c, 0xc2, 0x0c, 0x02, 0x0c, 0x42, 0x0c, 0xc2, - 0x0f, 0xc2, 0x07, 0x0a, 0x0f, 0xc2, 0x0a, 0x3d, 0x0f, 0xc2, 0x07, 0xf6, - 0x0f, 0xc2, 0x03, 0x9c, 0x0f, 0xc2, 0x0c, 0x95, 0x0f, 0xc2, 0x07, 0xed, - 0x0c, 0x02, 0x0c, 0x42, 0x0c, 0x82, 0x0c, 0x02, 0x0c, 0x42, 0x0c, 0x82, - 0x0f, 0xc2, 0x07, 0x0a, 0x0f, 0xc2, 0x0a, 0x3d, 0x0f, 0xc2, 0x07, 0xf3, - 0x0f, 0xc2, 0x03, 0x9c, 0x0f, 0xc2, 0x0c, 0x95, 0x0f, 0xc2, 0x07, 0xea, - 0x0f, 0xc9, 0x08, 0x00, 0x0f, 0xca, 0x07, 0xfe, 0x0f, 0xc4, 0x07, 0x45, - 0x00, 0x02, 0x0f, 0xc2, 0x0c, 0x00, 0x0c, 0x82, 0x00, 0x02, 0x0c, 0x42, - 0x0c, 0x82, 0x0f, 0xc2, 0x0a, 0xab, 0x0f, 0xc2, 0x0a, 0xaa, 0x0f, 0xc2, - 0x07, 0xfd, 0x0f, 0xc2, 0x07, 0x0a, 0x0f, 0xc2, 0x0a, 0x3d, 0x0f, 0xc2, - 0x07, 0xf8, 0x0f, 0xc4, 0x07, 0x57, 0x00, 0x02, 0x0c, 0x42, 0x0f, 0xc2, - 0x07, 0xfa, 0x00, 0x02, 0x0c, 0x42, 0x0f, 0xc2, 0x07, 0xf0, 0x0f, 0xc4, - 0x07, 0x08, 0x0f, 0xc2, 0x09, 0x51, 0x0f, 0xc2, 0x09, 0xd4, 0x0f, 0xc2, - 0x07, 0xf5, 0x0f, 0xc4, 0x07, 0x0b, 0x00, 0x02, 0x0f, 0xc2, 0x08, 0x00, - 0x0f, 0xc2, 0x07, 0xfd, 0x0f, 0xc4, 0x07, 0x5d, 0x0f, 0xc0, 0x0d, 0xbf, - 0x0f, 0xc4, 0x07, 0xe1, 0x0f, 0xc0, 0x00, 0x50, 0x0f, 0xc4, 0x07, 0xe6, - 0x0f, 0xc2, 0x00, 0x40, 0x00, 0x02, 0x0f, 0xc2, 0x08, 0x00, 0x00, 0x02, - 0x0f, 0xc4, 0x07, 0xf0, 0x00, 0x02, 0x02, 0x02, 0x04, 0x02, 0x0f, 0xc4, - 0x07, 0x5e, 0x0f, 0xc2, 0x00, 0x64, 0x00, 0x02, 0x0f, 0xc4, 0x07, 0x26, - 0x02, 0x40, 0x0f, 0xf1, 0x03, 0x04, 0x0f, 0xc4, 0x07, 0x62, 0x02, 0x82, - 0x00, 0x02, 0x0f, 0xc4, 0x07, 0x6a, 0x0f, 0xc2, 0x0d, 0xac, 0x0f, 0xc2, - 0x00, 0x64, 0x0f, 0xc2, 0x00, 0x55, 0x0f, 0xc4, 0x07, 0x6d, 0x00, 0x00, - 0x0f, 0xc4, 0x07, 0xef, 0x02, 0x00, 0x0a, 0x72, 0x0f, 0xc4, 0x07, 0x70, - 0x0f, 0xc0, 0x0f, 0xff, 0x0f, 0xc4, 0x07, 0x72, 0x03, 0xc2, 0x0f, 0xc2, - 0x02, 0x80, 0x0f, 0xc2, 0x01, 0xe0, 0x02, 0x82, 0x0f, 0xc4, 0x06, 0xff, - 0x0f, 0xc2, 0x08, 0x00, 0x0f, 0xfb, 0x19, 0x4d, 0x0f, 0xf1, 0x0d, 0x00, - 0x0a, 0x61, 0x02, 0xde, 0x0f, 0xc4, 0x07, 0x22, 0x00, 0x40, 0x0f, 0xc4, - 0x07, 0x2b, 0x0f, 0xc2, 0x02, 0x6e, 0x0f, 0xc2, 0x08, 0x31, 0x0f, 0xc2, - 0x07, 0xf9, 0x0f, 0xc2, 0x0b, 0xa5, 0x0f, 0xc2, 0x0c, 0x49, 0x0f, 0xc2, - 0x07, 0xf7, 0x0f, 0xc2, 0x00, 0x38, 0x0f, 0xc2, 0x0e, 0xc3, 0x00, 0xc2, - 0x0f, 0xc2, 0x05, 0x0d, 0x0f, 0xc2, 0x0f, 0x5e, 0x00, 0x42, 0x02, 0x82, - 0x01, 0x82, 0x02, 0x02, 0x00, 0x42, 0x1f, 0xc4, 0x07, 0x5d, 0x1f, 0xe2, - 0x0e, 0xff, 0x1b, 0x24, 0x19, 0x80, 0x0f, 0xc4, 0x07, 0x60, 0x02, 0x00, - 0x12, 0x00, 0x0f, 0xc4, 0x07, 0x61, 0x01, 0x00, 0x0f, 0xf8, 0x1c, 0xa7, - 0x11, 0x00, 0x0f, 0xc4, 0x06, 0xfc, 0x00, 0x40, 0x0f, 0xc4, 0x07, 0xf3, - 0x0f, 0xf8, 0x1c, 0xa7, 0x00, 0x00, 0x0f, 0xc4, 0x07, 0xf3, 0x00, 0x21, - 0x0b, 0x14, 0x1f, 0x00, 0x0f, 0xc4, 0x07, 0xfd, 0x0b, 0x08, 0x00, 0x61, - 0x0c, 0x19, 0x09, 0xc0, 0x09, 0xe1, 0x00, 0x14, 0x10, 0x80, 0x0f, 0xfb, - 0x1e, 0xe0, 0x0f, 0xc4, 0x07, 0xf6, 0x0f, 0xf0, 0x03, 0x0a, 0x0b, 0xb2, - 0x0f, 0xf0, 0x03, 0x09, 0x0b, 0xb2, 0x0f, 0xc4, 0x07, 0xf8, 0x0b, 0x88, - 0x0b, 0x89, 0x0f, 0xf0, 0x03, 0x1a, 0x0c, 0x32, 0x0f, 0xf0, 0x03, 0x19, - 0x0c, 0x72, 0x0f, 0xc4, 0x07, 0xfa, 0x0f, 0xf0, 0x03, 0x38, 0x0b, 0x32, - 0x0f, 0xc4, 0x07, 0xfb, 0x0f, 0xf0, 0x03, 0x11, 0x0b, 0x32, 0x0f, 0xc4, - 0x07, 0xfc, 0x0f, 0xf0, 0x0c, 0x05, 0x0f, 0xf8, 0x1c, 0xdd, 0x0b, 0x32, - 0x0f, 0xc4, 0x07, 0xf3, 0x0f, 0x00, 0x00, 0x04, 0x0f, 0xc8, 0x06, 0xc0, - 0x0f, 0xf7, 0x00, 0x71, 0x0f, 0xc4, 0x07, 0x3d, 0x0f, 0xc5, 0x07, 0x3e, - 0x0b, 0x21, 0x0f, 0xd5, 0x00, 0x3c, 0x1f, 0xf8, 0x1c, 0xff, 0x10, 0x01, - 0x0f, 0xf1, 0x0f, 0x15, 0x01, 0xe2, 0x00, 0x21, 0x0f, 0xc4, 0x07, 0xf5, - 0x0a, 0x48, 0x0c, 0x24, 0x09, 0x95, 0x1c, 0x00, 0x0b, 0x61, 0x00, 0x59, - 0x09, 0xc1, 0x00, 0xd2, 0x10, 0x01, 0x1b, 0x22, 0x1f, 0xe4, 0x0f, 0xf8, - 0x19, 0x80, 0x02, 0x3a, 0x00, 0x48, 0x02, 0xba, 0x00, 0x48, 0x0f, 0xc4, - 0x07, 0xc2, 0x00, 0x61, 0x0b, 0x15, 0x1f, 0xc4, 0x07, 0x62, 0x1b, 0x88, - 0x1f, 0xf6, 0x00, 0x4c, 0x1b, 0x89, 0x0f, 0xfb, 0x01, 0x92, 0x0f, 0xfb, - 0x19, 0xd5, 0x0f, 0xc4, 0x05, 0x80, 0x00, 0x02, 0x0f, 0xc2, 0x0e, 0x00, - 0x0f, 0xc2, 0x07, 0xff, 0x0f, 0xc4, 0x06, 0x31, 0x0f, 0xc5, 0x05, 0x83, - 0x04, 0xb7, 0x0f, 0xfb, 0x12, 0xf9, 0x0f, 0xc4, 0x01, 0x5e, 0x0f, 0xc0, - 0x1c, 0xda, 0x0f, 0xc4, 0x06, 0x92, 0x0f, 0xc5, 0x07, 0x5d, 0x0b, 0x40, - 0x0f, 0xc4, 0x07, 0xf4, 0x0b, 0x21, 0x01, 0x88, 0x00, 0xdf, 0x11, 0xc8, - 0x01, 0x1e, 0x12, 0x08, 0x0f, 0xc4, 0x01, 0x7c, 0x0c, 0x00, 0x0f, 0xfb, - 0x1f, 0x0b, 0x0f, 0xf1, 0x03, 0x11, 0x00, 0xe2, 0x0f, 0xc4, 0x06, 0x8e, - 0x0a, 0x64, 0x09, 0x80, 0x0f, 0xf1, 0x0c, 0x05, 0x0f, 0xc4, 0x05, 0xf2, - 0x0a, 0x48, 0x0c, 0x00, 0x0f, 0xf1, 0x03, 0x38, 0x0a, 0x62, 0x00, 0x64, - 0x09, 0xa1, 0x00, 0x54, 0x03, 0x48, 0x12, 0xc8, 0x04, 0x44, 0x0c, 0x00, - 0x0f, 0xf1, 0x03, 0x1a, 0x0a, 0x48, 0x0f, 0xf1, 0x03, 0x19, 0x0a, 0x49, - 0x0f, 0xc4, 0x01, 0x32, 0x0c, 0x02, 0x00, 0xb6, 0x0c, 0x42, 0x0f, 0xc8, - 0x1f, 0xe8, 0x01, 0x37, 0x0f, 0xc4, 0x06, 0x96, 0x00, 0x37, 0x0f, 0xc4, - 0x06, 0x2b, 0x02, 0xb7, 0x0f, 0xf7, 0x04, 0x66, 0x0f, 0xc4, 0x01, 0x7c, - 0x0b, 0x08, 0x00, 0xb6, 0x00, 0x09, 0x03, 0x37, 0x0f, 0xf7, 0x04, 0x72, - 0x0f, 0xf7, 0x01, 0x39, 0x0f, 0xc8, 0x1f, 0xfd, 0x01, 0x37, 0x0f, 0xc4, - 0x00, 0x8f, 0x00, 0x37, 0x0f, 0xf7, 0x0d, 0x69, 0x0f, 0xf1, 0x03, 0x0a, - 0x0a, 0x48, 0x0f, 0xf1, 0x03, 0x09, 0x0a, 0x49, 0x0f, 0xc4, 0x01, 0x30, - 0x0c, 0x02, 0x0c, 0x42, 0x0c, 0x61, 0x00, 0x17, 0x1f, 0xf9, 0x1d, 0x8b, - 0x0f, 0xc4, 0x01, 0x62, 0x00, 0x00, 0x0c, 0x61, 0x0f, 0xd1, 0x04, 0x00, - 0x0f, 0xf8, 0x1d, 0x97, 0x09, 0xc9, 0x0f, 0xc4, 0x01, 0x62, 0x00, 0x40, - 0x0c, 0x61, 0x0f, 0xd1, 0x0c, 0x00, 0x09, 0xc9, 0x00, 0x21, 0x0c, 0x18, - 0x09, 0xc8, 0x0c, 0x51, 0x09, 0xc9, 0x00, 0xb7, 0x0f, 0xc4, 0x06, 0x99, - 0x06, 0xb7, 0x03, 0x37, 0x03, 0xb7, 0x0f, 0xc4, 0x06, 0x8f, 0x0c, 0x02, - 0x00, 0xb6, 0x0c, 0x42, 0x05, 0x37, 0x04, 0x37, 0x06, 0xbb, 0x1f, 0xf7, - 0x00, 0x8f, 0x00, 0x36, 0x04, 0xc4, 0x0f, 0xfa, 0x07, 0xa2, 0x00, 0x0e, - 0x07, 0x37, 0x0f, 0xf0, 0x03, 0x0b, 0x00, 0x32, 0x0f, 0xf0, 0x03, 0x1b, - 0x00, 0x32, 0x0f, 0xf1, 0x03, 0x1d, 0x0a, 0x7f, 0x0f, 0xf0, 0x03, 0x1c, - 0x0f, 0xf2, 0x00, 0x3f, 0x0f, 0xf0, 0x03, 0x1e, 0x00, 0x32, 0x0f, 0xf0, - 0x03, 0x1f, 0x00, 0x32, 0x0f, 0xf0, 0x03, 0x2a, 0x0f, 0xf2, 0x07, 0xff, - 0x0f, 0xf0, 0x03, 0x29, 0x00, 0xb2, 0x0f, 0xf0, 0x03, 0x2b, 0x0f, 0xf2, - 0x00, 0x28, 0x0f, 0xf0, 0x03, 0x2f, 0x00, 0x72, 0x0f, 0xf0, 0x04, 0x00, - 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x11, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x15, - 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x17, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x0c, - 0x00, 0xb2, 0x0f, 0xf0, 0x05, 0x02, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x08, - 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x01, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x00, - 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x07, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x06, - 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x04, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x05, - 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x0a, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x0b, - 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x03, 0x00, 0x32, 0x0f, 0xf0, 0x05, 0x09, - 0x00, 0x32, 0x0f, 0xf0, 0x0a, 0x00, 0x05, 0xb2, 0x0f, 0xc8, 0x01, 0x13, - 0x0f, 0xc4, 0x06, 0x00, 0x0f, 0xf0, 0x0a, 0x01, 0x0c, 0x32, 0x0c, 0x00, - 0x0f, 0xf0, 0x0a, 0x20, 0x00, 0x32, 0x0f, 0xf0, 0x0a, 0x10, 0x00, 0x72, - 0x0f, 0xf0, 0x0a, 0x11, 0x00, 0x32, 0x0f, 0xf0, 0x0a, 0x0a, 0x00, 0x32, - 0x0f, 0xf0, 0x0a, 0x07, 0x04, 0x32, 0x0f, 0xf0, 0x0a, 0x2e, 0x0f, 0xf2, - 0x01, 0xc8, 0x0f, 0xf0, 0x0a, 0x30, 0x0f, 0xf6, 0x0d, 0xdb, 0x06, 0x32, - 0x0f, 0xf0, 0x0c, 0x11, 0x02, 0xb2, 0x0f, 0xf0, 0x0c, 0x12, 0x00, 0x32, - 0x0f, 0xf0, 0x0c, 0x03, 0x00, 0x72, 0x0f, 0xf0, 0x0c, 0x1a, 0x0f, 0xf2, - 0x08, 0x72, 0x0f, 0xf1, 0x0c, 0x1b, 0x0a, 0x62, 0x01, 0x25, 0x09, 0xb2, - 0x0f, 0xc4, 0x01, 0x80, 0x00, 0x40, 0x0f, 0xc8, 0x0c, 0x1d, 0x0c, 0x30, - 0x0f, 0xf2, 0x00, 0xa0, 0x0c, 0x31, 0x0a, 0x61, 0x0f, 0xd5, 0x02, 0xa0, - 0x10, 0x00, 0x0c, 0x30, 0x0f, 0xf2, 0x00, 0x60, 0x0c, 0x31, 0x0a, 0x61, - 0x0f, 0xd5, 0x01, 0x60, 0x10, 0x00, 0x0f, 0xf0, 0x0c, 0x1a, 0x0f, 0xf2, - 0x08, 0x71, 0x0f, 0xf1, 0x0d, 0x00, 0x0a, 0x49, 0x0c, 0x61, 0x02, 0xde, - 0x0c, 0x62, 0x0f, 0xe4, 0x08, 0x18, 0x1f, 0xe4, 0x08, 0x1e, 0x09, 0xa2, - 0x04, 0x25, 0x09, 0xb2, 0x0f, 0xf1, 0x0d, 0x01, 0x00, 0x22, 0x1f, 0xe2, - 0x0a, 0xaa, 0x0a, 0x64, 0x09, 0xb2, 0x0f, 0xc4, 0x06, 0x93, 0x0f, 0xc0, - 0x00, 0x2b, 0x0f, 0xc8, 0x0f, 0xff, 0x09, 0x37, 0x0f, 0xc4, 0x06, 0x01, - 0x00, 0x40, 0x04, 0x84, 0x00, 0x00, 0x04, 0x04, 0x00, 0x80, 0x0f, 0xc4, - 0x06, 0xba, 0x0f, 0xc0, 0x06, 0xbb, 0x04, 0x04, 0x00, 0x40, 0x0f, 0xc8, - 0x00, 0x28, 0x0f, 0xf7, 0x05, 0x23, 0x0f, 0xf6, 0x05, 0x23, 0x02, 0x88, - 0x00, 0x69, 0x0e, 0xff, 0x00, 0x28, 0x0e, 0xff, 0x02, 0x3a, 0x00, 0x08, - 0x02, 0xba, 0x00, 0x08, 0x0f, 0xc4, 0x01, 0xc1, 0x0f, 0xc0, 0x00, 0x47, - 0x0f, 0xc4, 0x07, 0xf3, 0x0b, 0x08, 0x0c, 0x38, 0x00, 0x00, 0x01, 0x04, - 0x0f, 0xc2, 0x0c, 0x18, 0x0f, 0xc2, 0x03, 0x01, 0x0f, 0xc2, 0x0d, 0x01, - 0x0f, 0xc2, 0x0d, 0x00, 0x0f, 0xc2, 0x03, 0x03, 0x0f, 0xc2, 0x03, 0x06, - 0x0f, 0xc2, 0x03, 0x05, 0x0f, 0xc2, 0x03, 0x28, 0x0f, 0xc2, 0x03, 0x18, - 0x0f, 0xc2, 0x03, 0x3c, 0x0f, 0xc2, 0x03, 0x3b, 0x0f, 0xc2, 0x03, 0x16, - 0x0f, 0xc2, 0x03, 0x17, 0x0f, 0xc2, 0x03, 0x26, 0x0f, 0xc2, 0x03, 0x27, - 0x0f, 0xc2, 0x03, 0x24, 0x0f, 0xc2, 0x03, 0x25, 0x0f, 0xc2, 0x03, 0x12, - 0x0f, 0xc2, 0x0f, 0x00, 0x0f, 0xc8, 0x0f, 0x12, 0x0c, 0x02, 0x0c, 0x02, - 0x0c, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x0c, 0x02, - 0x0f, 0xc2, 0x0f, 0x10, 0x0f, 0xc2, 0x0f, 0x13, 0x0f, 0xc2, 0x02, 0x01, - 0x0f, 0xc2, 0x02, 0x04, 0x0f, 0xc2, 0x02, 0x03, 0x0f, 0xc2, 0x02, 0x06, - 0x00, 0xc5, 0x0a, 0x83, 0x0a, 0xa1, 0x0b, 0xf1, 0x0a, 0xd5, 0x0a, 0x42, - 0x1b, 0xf1, 0x1f, 0xf8, 0x1e, 0xd1, 0x1a, 0xd5, 0x0f, 0x39, 0x00, 0xc5, - 0x0b, 0xc4, 0x0a, 0xa1, 0x0a, 0xd5, 0x1b, 0xf0, 0x1f, 0xf8, 0x1e, 0xda, - 0x1b, 0xb2, 0x0f, 0x39, 0x0f, 0xc4, 0x06, 0xfd, 0x00, 0x61, 0x0b, 0x14, - 0x00, 0x00, 0x1f, 0xc4, 0x06, 0xfc, 0x1f, 0x38, 0x10, 0x00, 0x0f, 0xc4, - 0x06, 0xfb, 0x0b, 0x15, 0x0f, 0xc4, 0x06, 0xfc, 0x1b, 0x15, 0x1f, 0x39, - 0x00, 0x40, 0x0f, 0xe2, 0x0a, 0xaa, 0x00, 0x04, 0x0f, 0xc5, 0x07, 0xfd, - 0x0b, 0x63, 0x09, 0x82, 0x0f, 0xc5, 0x07, 0xfe, 0x0b, 0xe3, 0x09, 0x82, - 0x0b, 0xe3, 0x0f, 0xfa, 0x1e, 0x8f, 0x09, 0x82, 0x0f, 0xf0, 0x0f, 0x19, - 0x00, 0x32, 0x0f, 0xf0, 0x0f, 0x18, 0x00, 0x32, 0x0f, 0xf0, 0x0f, 0x1a, - 0x00, 0x72, 0x0f, 0xf9, 0x1f, 0x09, 0x0f, 0xf1, 0x0f, 0x14, 0x0f, 0xc4, - 0x01, 0x3e, 0x0a, 0x48, 0x0c, 0x02, 0x0f, 0xf1, 0x0f, 0x15, 0x0a, 0x42, - 0x0c, 0x21, 0x00, 0x1f, 0x0f, 0xc4, 0x07, 0xf0, 0x00, 0x00, 0x10, 0x40, - 0x00, 0x09, 0x00, 0x4a, 0x00, 0x5f, 0x10, 0x49, 0x10, 0x0a, 0x00, 0x9e, - 0x10, 0x49, 0x10, 0x4a, 0x0f, 0xc4, 0x07, 0xea, 0x0c, 0x40, 0x0f, 0xc4, - 0x07, 0xeb, 0x0c, 0x80, 0x0f, 0xe2, 0x02, 0xa0, 0x0f, 0xc4, 0x01, 0x7b, - 0x0c, 0x24, 0x09, 0x80, 0x0f, 0xc4, 0x01, 0x7a, 0x0c, 0x26, 0x09, 0xa4, - 0x0f, 0x38, 0x09, 0x80, 0x0f, 0xf9, 0x19, 0xf7, 0x0f, 0xf9, 0x1f, 0x42, - 0x0f, 0xf9, 0x1f, 0x46, 0x0f, 0xf9, 0x1f, 0x4a, 0x0f, 0xf9, 0x1f, 0x4e, - 0x0f, 0xf9, 0x1f, 0x52, 0x0f, 0xf9, 0x1f, 0x5a, 0x0f, 0xc4, 0x00, 0x83, - 0x00, 0x37, 0x0f, 0xb9, 0x0f, 0xc4, 0x00, 0xe0, 0x00, 0x37, 0x0f, 0xb9, - 0x0f, 0xc4, 0x00, 0xe3, 0x00, 0x37, 0x0f, 0xb9, 0x0f, 0xc4, 0x00, 0x8c, - 0x00, 0x37, 0x0f, 0xb9, 0x0f, 0xbb, 0x0f, 0xc4, 0x01, 0x71, 0x0b, 0x14, - 0x1f, 0x39, 0x0c, 0x51, 0x0f, 0x38, 0x09, 0xc9, 0x0f, 0xfb, 0x08, 0xc2, - 0x0f, 0xb9, 0x0f, 0xbf, 0x00, 0xf3, 0x0f, 0xfc, 0x1f, 0x34, 0x0f, 0xfc, - 0x0e, 0xe2, 0x0f, 0xfc, 0x09, 0x7e, 0x0f, 0xfc, 0x09, 0x84, 0x0f, 0xfc, - 0x09, 0x87, 0x0f, 0xfc, 0x0c, 0x9f, 0x0f, 0xfc, 0x0b, 0x5b, 0x0f, 0xfc, - 0x0a, 0x72, 0x0f, 0xff, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0x77, 0x0f, 0xff, - 0x00, 0x26, 0x0f, 0xff, 0x00, 0x27, 0x0f, 0xff, 0x00, 0x28, 0x0f, 0xff, - 0x00, 0x29, 0x0f, 0xff, 0x00, 0x2a, 0x0f, 0xff, 0x02, 0x00, 0x0f, 0xff, - 0x02, 0x05, 0x0f, 0xff, 0x0c, 0xad, 0x0f, 0xff, 0x0a, 0xb6, 0x0f, 0xc4, - 0x06, 0xfd, 0x00, 0x00, 0x00, 0x04, 0x0f, 0xe2, 0x0a, 0xaa, 0x0f, 0xc5, - 0x07, 0xfd, 0x0b, 0xa3, 0x09, 0xa1, 0x0b, 0xd4, 0x1f, 0xc5, 0x07, 0xfe, - 0x1b, 0xa3, 0x19, 0xa1, 0x1b, 0xd4, 0x1b, 0xa3, 0x19, 0xa1, 0x1b, 0xd4, - 0x1f, 0xc4, 0x06, 0xfc, 0x1b, 0x21, 0x10, 0x54, 0x1f, 0xf9, 0x1f, 0xab, - 0x0f, 0xfb, 0x1b, 0x7f, 0x0f, 0xfb, 0x18, 0x51, 0x0f, 0xfb, 0x02, 0xe3, - 0x0f, 0xfb, 0x1b, 0xb6, 0x0f, 0xf0, 0x0f, 0x00, 0x0f, 0xf8, 0x1f, 0xb7, - 0x01, 0x72, 0x0f, 0xc4, 0x06, 0xfd, 0x0f, 0xfa, 0x1e, 0xd7, 0x00, 0x40, - 0x0f, 0xc4, 0x07, 0xf3, 0x0f, 0xfa, 0x1c, 0xa7, 0x00, 0x00, 0x0f, 0xf9, - 0x1f, 0xb7, 0x0f, 0xfb, 0x01, 0xcf, 0x0f, 0xf9, 0x1f, 0xc2, 0x03, 0x3a, - 0x00, 0xc8, 0x10, 0x55, 0x10, 0x95, 0x12, 0x15, 0x1f, 0xfb, 0x02, 0x35, - 0x0f, 0xfb, 0x01, 0xcb, 0x0f, 0xfb, 0x17, 0x17, 0x0f, 0xfb, 0x01, 0xcf, - 0x0f, 0xf8, 0x1f, 0xbb, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x07, 0x06 -}; - -#endif diff -Nru a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/stv0297.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,774 @@ +/* + Driver for STV0297 demodulator + + Copyright (C) 2004 Andrew de Quincey + Copyright (C) 2003-2004 Dennis Noermann + + 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 "dvb_frontend.h" +#include "stv0297.h" + +struct stv0297_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + const struct stv0297_config* config; + + struct dvb_frontend frontend; + + int freq_off; + + unsigned long base_freq; + + u8 pwm; +}; + +#if 1 +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +#define STV0297_CLOCK 28900 + +static u8 init_tab [] = { + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x00,// check + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0xff, + 0x4b, 0x7f, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x00, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x00, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x53, + 0xc1, 0x70, + 0xc2, 0x12, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x49, + 0x62, 0x0b, + 0x53, 0x08, + 0x59, 0x08, +}; + + +static int stv0297_writereg (struct stv0297_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + ret = i2c_transfer (state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " + "ret == %i)\n", __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + +static int stv0297_readreg (struct stv0297_state* state, u8 reg) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + + // this device needs a STOP between the register and data + if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __FUNCTION__, reg, ret); + return -1; + } + if ((ret = i2c_transfer (state->i2c, &msg[1], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __FUNCTION__, reg, ret); + return -1; + } + + return b1[0]; +} + +static int stv0297_writereg_mask (struct stv0297_state* state, u8 reg, u8 mask, u8 data) +{ + int val; + + val = stv0297_readreg(state, reg); + val &= ~mask; + val |= (data & mask); + stv0297_writereg(state, reg, val); + + return 0; +} + +static int stv0297_readregs (struct stv0297_state* state, u8 reg1, u8 *b, u8 len) +{ + int ret; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; + + // this device needs a STOP between the register and data + if ((ret = i2c_transfer (state->i2c, &msg[0], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __FUNCTION__, reg1, ret); + return -1; + } + if ((ret = i2c_transfer (state->i2c, &msg[1], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", + __FUNCTION__, reg1, ret); + return -1; + } + + return 0; +} + +static int stv0297_set_symbolrate (struct stv0297_state* state, u32 srate) +{ + u64 tmp; + + tmp = srate; + tmp <<= 32; + do_div(tmp, STV0297_CLOCK); + + stv0297_writereg (state, 0x55,(unsigned char)(tmp & 0xFF)); + stv0297_writereg (state, 0x56,(unsigned char)(tmp>> 8)); + stv0297_writereg (state, 0x57,(unsigned char)(tmp>>16)); + stv0297_writereg (state, 0x58,(unsigned char)(tmp>>24)); + + return 0; +} + +static u32 stv0297_get_symbolrate (struct stv0297_state* state) +{ + u64 tmp; + + tmp = stv0297_readreg(state, 0x55); + tmp |= (stv0297_readreg(state, 0x56) << 8); + tmp |= (stv0297_readreg(state, 0x57) << 16); + tmp |= (stv0297_readreg(state, 0x57) << 24); + + tmp *= STV0297_CLOCK; + tmp >>= 32; + return tmp; +} + +static void stv0297_set_sweeprate(struct stv0297_state* state, short fshift) +{ + s64 tmp; + u32 symrate; + + symrate = stv0297_get_symbolrate(state); + + // cannot use shifts - it is signed + tmp = fshift * (1<<28); + do_div(tmp, symrate); + + // adjust + if (tmp >= 0) { + tmp += 500000; + } else { + tmp -= 500000; + } + do_div(tmp, 1000000); + + stv0297_writereg(state, 0x60, tmp & 0xFF); + stv0297_writereg_mask(state, 0x69, 0xF0, (tmp >> 4) & 0xf0); + + return; +} + +static void stv0297_set_carrieroffset(struct stv0297_state* state, long offset) +{ + long long_tmp; + + // symrate is hardcoded to 10000 here - don't ask me why + long_tmp = offset * 26844L ; /* (2**28)/10000 */ + if(long_tmp < 0) long_tmp += 0x10000000 ; + long_tmp &= 0x0FFFFFFF ; + + stv0297_writereg (state,0x66,(unsigned char)(long_tmp & 0xFF)); // iphase0 + stv0297_writereg (state,0x67,(unsigned char)(long_tmp>>8)); // iphase1 + stv0297_writereg (state,0x68,(unsigned char)(long_tmp>>16)); // iphase2 + stv0297_writereg_mask(state, 0x69, 0x0F, (long_tmp >> 24) & 0x0f); + + return; +} + +static long stv0297_get_carrieroffset(struct stv0297_state* state) +{ + s32 raw; + s64 tmp; + u32 symbol_rate; + + stv0297_writereg(state,0x6B, 0x00); + + symbol_rate = stv0297_get_symbolrate(state); + + raw = stv0297_readreg(state,0x66); + raw |= (stv0297_readreg(state,0x67) << 8); + raw |= (stv0297_readreg(state,0x68) << 16); + raw |= (stv0297_readreg(state,0x69) & 0x0F) << 24; + + // cannot just use a shift here 'cos it is signed + tmp = raw; + tmp *= symbol_rate; + do_div(tmp, 1<<28); + + return (s32) tmp; +} + +static void stv0297_set_initialdemodfreq(struct stv0297_state* state, long freq) +{ + u64 tmp; + + if (freq > 10000) freq -= STV0297_CLOCK; + if (freq < 0) freq = 0; + + tmp = freq << 16; + do_div(tmp, STV0297_CLOCK); + if (tmp > 0xffff) tmp = 0xffff; + + stv0297_writereg_mask(state, 0x25, 0x80, 0x80); + stv0297_writereg(state, 0x21, tmp >> 8); + stv0297_writereg(state, 0x20, tmp); +} + +static int stv0297_set_qam(struct stv0297_state* state, fe_modulation_t modulation) +{ + int val = 0; + + switch(modulation) { + case QAM_16: + val = 0; + break; + + case QAM_32: + val = 1; + break; + + case QAM_64: + val = 4; + break; + + case QAM_128: + val = 2; + break; + + case QAM_256: + val = 3; + break; + + default: + return -EINVAL; + } + + stv0297_writereg_mask(state, 0x00, 0x70, val << 4); + + return 0; +} + +static int stv0297_set_inversion(struct stv0297_state* state, fe_spectral_inversion_t inversion) +{ + int val = 0; + + switch(inversion) { + case INVERSION_OFF: + val = 0; + break; + + case INVERSION_ON: + val = 1; + break; + + default: + return -EINVAL; + } + + stv0297_writereg_mask(state, 0x83, 0x08, val << 3); + + return 0; +} + + + + + + + + + + + + + +int stv0297_enable_plli2c(struct dvb_frontend* fe) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + + stv0297_writereg(state, 0x87, 0x78); + stv0297_writereg(state, 0x86, 0xc8); + + return 0; +} + +static int stv0297_init (struct dvb_frontend* fe) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + int i; + + stv0297_writereg_mask(state, 0x80, 1, 1); + stv0297_writereg_mask(state, 0x80, 1, 0); + stv0297_writereg_mask(state, 0x81, 1, 1); + stv0297_writereg_mask(state, 0x81, 1, 0); + + for (i=0; ipwm); + msleep(200); + + if (state->config->pll_init) state->config->pll_init(fe); + + return 0; +} + +static int stv0297_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + + u8 sync = stv0297_readreg (state, 0xDF); + + *status = 0; + if (sync & 0x80) + *status |= FE_HAS_SYNC | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK; + return 0; +} + +static int stv0297_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + u8 BER[3]; + + stv0297_writereg (state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes + mdelay(25); // Hopefully got 4096 Bytes + stv0297_readregs (state, 0xA0, BER, 3); + mdelay(25); + *ber = (BER[2] << 8 | BER[1]) / ( 8 * 4096); + + return 0; +} + + +static int stv0297_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + u8 STRENGTH[2]; + + stv0297_readregs (state, 0x41, STRENGTH, 2); + *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0]; + + return 0; +} + +static int stv0297_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + u8 SNR[2]; + + stv0297_readregs (state, 0x07, SNR, 2); + *snr = SNR[1] << 8 | SNR[0]; + + return 0; +} + +static int stv0297_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + + *ucblocks = (stv0297_readreg (state, 0xD5) << 8) + | stv0297_readreg (state, 0xD4); + + return 0; +} + +static int stv0297_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + int u_threshold; + int initial_u; + int blind_u; + int delay; + int locked; + int sweeprate; + int carrieroffset; + unsigned long starttime; + unsigned long timeout; + + switch(p->u.qam.modulation) { + case QAM_16: + case QAM_32: + case QAM_64: + delay = 100; + sweeprate = 1500; + break; + + case QAM_128: + delay = 150; + sweeprate = 1000; + break; + + case QAM_256: + delay = 200; + sweeprate = 500; + break; + + default: + return -EINVAL; + } + + // determine inversion dependant parameters + carrieroffset = -330; + switch(p->inversion) { + case INVERSION_OFF: + break; + + case INVERSION_ON: + sweeprate = -sweeprate; + carrieroffset = -carrieroffset; + break; + + default: + return -EINVAL; + } + + state->config->pll_set(fe, p); + + // reset everything + stv0297_writereg_mask(state, 0x82, 0x4, 0x4); + stv0297_set_initialdemodfreq(state, state->freq_off + 7250); + stv0297_writereg_mask(state, 0x43, 0x10, 0x00); + stv0297_writereg(state, 0x41, 0x00); + stv0297_writereg_mask(state, 0x42, 0x03, 0x01); + stv0297_writereg_mask(state, 0x36, 0x60, 0x00); + stv0297_writereg_mask(state, 0x36, 0x18, 0x00); + stv0297_writereg_mask(state, 0x71, 0x80, 0x80); + stv0297_writereg(state, 0x72, 0x00); + stv0297_writereg(state, 0x73, 0x00); + stv0297_writereg_mask(state, 0x74, 0x0F, 0x00); + stv0297_writereg_mask(state, 0x43, 0x08, 0x00); + stv0297_writereg_mask(state, 0x71, 0x80, 0x00); + stv0297_writereg_mask(state, 0x5a, 0x20, 0x20); + stv0297_writereg_mask(state, 0x5b, 0x02, 0x02); + stv0297_writereg_mask(state, 0x5b, 0x02, 0x00); + stv0297_writereg_mask(state, 0x5b, 0x01, 0x00); + stv0297_writereg_mask(state, 0x5a, 0x40, 0x40); + stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); + stv0297_writereg_mask(state, 0x81, 0x01, 0x01); + stv0297_writereg_mask(state, 0x81, 0x01, 0x00); + stv0297_writereg_mask(state, 0x83, 0x20, 0x20); + stv0297_writereg_mask(state, 0x83, 0x20, 0x00); + u_threshold = stv0297_readreg(state, 0x00) & 0xf; + initial_u = stv0297_readreg(state, 0x01) >> 4; + blind_u = stv0297_readreg(state, 0x01) & 0xf; + stv0297_writereg_mask(state, 0x84, 0x01, 0x01); + stv0297_writereg_mask(state, 0x84, 0x01, 0x00); + stv0297_writereg_mask(state, 0x00, 0x0f, u_threshold); + stv0297_writereg_mask(state, 0x01, 0xf0, initial_u << 4); + stv0297_writereg_mask(state, 0x01, 0x0f, blind_u); + stv0297_writereg_mask(state, 0x87, 0x80, 0x00); + stv0297_writereg(state, 0x63, 0x00); + stv0297_writereg(state, 0x64, 0x00); + stv0297_writereg(state, 0x65, 0x00); + stv0297_writereg(state, 0x66, 0x00); + stv0297_writereg(state, 0x67, 0x00); + stv0297_writereg(state, 0x68, 0x00); + stv0297_writereg_mask(state, 0x69, 0x0f, 0x00); + + // set parameters + stv0297_set_qam(state, p->u.qam.modulation); + stv0297_set_symbolrate(state, p->u.qam.symbol_rate/1000); + stv0297_set_sweeprate(state, sweeprate); + stv0297_set_carrieroffset(state, carrieroffset); + stv0297_set_inversion(state, p->inversion); + + // kick off lock + stv0297_writereg_mask(state, 0x88, 0x08, 0x08); + stv0297_writereg_mask(state, 0x5a, 0x20, 0x00); + stv0297_writereg_mask(state, 0x6a, 0x01, 0x01); + stv0297_writereg_mask(state, 0x43, 0x40, 0x40); + stv0297_writereg_mask(state, 0x5b, 0x30, 0x00); + stv0297_writereg_mask(state, 0x03, 0x0c, 0x0c); + stv0297_writereg_mask(state, 0x03, 0x03, 0x03); + stv0297_writereg_mask(state, 0x43, 0x10, 0x10); + + // wait for WGAGC lock + starttime = jiffies; + timeout = jiffies + (200*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + if (stv0297_readreg(state, 0x43) & 0x08) break; + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + msleep(20); + + // wait for equaliser partial convergence + locked = 0; + timeout = jiffies + (50*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0x82) & 0x04) { + locked = 1; + } + } + if (time_after(jiffies, timeout) && (!locked)) { + goto timeout; + } + + // wait for equaliser full convergence + timeout = jiffies + (delay*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0x82) & 0x08) { + break; + } + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + + // disable sweep + stv0297_writereg_mask(state, 0x6a, 1, 0); + stv0297_writereg_mask(state, 0x88, 8, 0); + + // wait for main lock + timeout = jiffies + (20*HZ)/1000; + while(time_before(jiffies, timeout)) { + msleep(10); + + if (stv0297_readreg(state, 0xDF) & 0x80) { + break; + } + } + if (time_after(jiffies, timeout)) { + goto timeout; + } + msleep(100); + + // is it still locked after that delay? + if (!(stv0297_readreg(state, 0xDF) & 0x80)) { + goto timeout; + } + + // success!! + stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); + state->freq_off = stv0297_get_carrieroffset(state); + state->base_freq = p->frequency; + return 0; + +timeout: + stv0297_writereg_mask(state, 0x6a, 0x01, 0x00); + return 0; +} + +static int stv0297_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + int reg_00, reg_83; + + reg_00 = stv0297_readreg(state, 0x00); + reg_83 = stv0297_readreg(state, 0x83); + + p->frequency = state->base_freq + state->freq_off; + p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; + p->u.qam.symbol_rate = stv0297_get_symbolrate(state); + p->u.qam.fec_inner = 0; + + switch((reg_00 >> 4) & 0x7) { + case 0: p->u.qam.modulation = QAM_16; break; + case 1: p->u.qam.modulation = QAM_32; break; + case 2: p->u.qam.modulation = QAM_128; break; + case 3: p->u.qam.modulation = QAM_256; break; + case 4: p->u.qam.modulation = QAM_64; break; + } + + return 0; +} + +static void stv0297_release(struct dvb_frontend* fe) +{ + struct stv0297_state* state = (struct stv0297_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops stv0297_ops; + +struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, + struct i2c_adapter* i2c, + int pwm) +{ + struct stv0297_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct stv0297_state*) kmalloc(sizeof(struct stv0297_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); + state->freq_off = 0; + state->base_freq = 0; + state->pwm = pwm; + + /* check if the demod is there */ + if ((stv0297_readreg(state, 0x80) & 0x70) != 0x20) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops stv0297_ops = { + + .info = { + .name = "ST STV0297 DVB-C", + .type = FE_QAM, + .frequency_min = 64000000, + .frequency_max = 1300000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO | + FE_CAN_RECOVER + }, + + .release = stv0297_release, + + .init = stv0297_init, + + .set_frontend = stv0297_set_frontend, + .get_frontend = stv0297_get_frontend, + + .read_status = stv0297_read_status, + .read_ber = stv0297_read_ber, + .read_signal_strength = stv0297_read_signal_strength, + .read_snr = stv0297_read_snr, + .read_ucblocks = stv0297_read_ucblocks, +}; + +MODULE_DESCRIPTION("ST STV0297 DVB-C Demodulator driver"); +MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(stv0297_attach); +EXPORT_SYMBOL(stv0297_enable_plli2c); diff -Nru a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/stv0297.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,41 @@ +/* + Driver for STV0297 demodulator + + Copyright (C) 2003-2004 Dennis Noermann + + 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 STV0297_H +#define STV0297_H + +#include +#include "dvb_frontend.h" + +struct stv0297_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, + struct i2c_adapter* i2c, int pwm); +extern int stv0297_enable_plli2c(struct dvb_frontend* fe); + +#endif // STV0297_H diff -Nru a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c --- a/drivers/media/dvb/frontends/stv0299.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/frontends/stv0299.c 2004-12-12 17:40:53 -08:00 @@ -1,8 +1,5 @@ /* - Universal driver for STV0299/TDA5059/SL1935 based - DVB QPSK frontends - - Alps BSRU6, LG TDQB-S00x + Driver for ST STV0299 demodulator Copyright (C) 2001-2002 Convergence Integrated Media GmbH , @@ -54,236 +51,42 @@ #include #include "dvb_frontend.h" +#include "stv0299.h" -#define FRONTEND_NAME "dvbfe_stv0299" - -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) - -static int debug; -static int stv0299_status; - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -module_param(stv0299_status, int, 0444); -MODULE_PARM_DESC(stv0299_status, "Which status value to support " - "(0 == BER (default), 1 == UCBLOCKS)"); +struct stv0299_state { -#define STATUS_BER 0 -#define STATUS_UCBLOCKS 1 + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; -/* frontend types */ -#define UNKNOWN_FRONTEND -1 -#define PHILIPS_SU1278_TSA 0 // SU1278 with TSA5059 synth and datasheet recommended settings -#define ALPS_BSRU6 1 -#define LG_TDQF_S001F 2 -#define PHILIPS_SU1278_TUA 3 // SU1278 with TUA6100 synth -#define SAMSUNG_TBMU24112IMB 4 -#define PHILIPS_SU1278_TSA_TT 5 // SU1278 with TSA5059 synth and TechnoTrend settings -#define PHILIPS_SU1278_TSA_TY 6 // SU1278 with TUA5059 synth and Typhoon wiring -#define PHILIPS_SU1278_TSA_CI 7 // SU1278 with TUA5059 synth and TerraTec Cinergy wiring - -/* Master Clock = 88 MHz */ -#define M_CLK (88000000UL) - -/* Master Clock for TT cards = 64 MHz */ -#define M_CLK_SU1278_TSA_TT (64000000UL) - -static struct dvb_frontend_info uni0299_info = { - .name = "STV0299/TSA5059/SL1935 based", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - .frequency_tolerance = M_CLK/2000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, /* ppm */ - .notifier_delay = 0, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_QPSK | - FE_CAN_FEC_AUTO -}; + const struct stv0299_config* config; + struct dvb_frontend frontend; -struct stv0299_state { - u8 tuner_type; u8 initialised:1; u32 tuner_frequency; u32 symbol_rate; fe_code_rate_t fec_inner; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - - -static u8 init_tab [] = { - 0x04, 0x7d, /* F22FR = 0x7d */ - /* F22 = f_VCO / 128 / 0x7d = 22 kHz */ - - /* I2C bus repeater */ - 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ - - /* general purpose DAC registers */ - 0x06, 0x40, /* DAC not used, set to high impendance mode */ - 0x07, 0x00, /* DAC LSB */ - - /* DiSEqC registers */ - 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ - 0x09, 0x00, /* FIFO */ - - /* Input/Output configuration register */ - 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ - /* OP0 ctl = Normal, OP0 val = 1 (18 V) */ - /* Nyquist filter = 00, QPSK reverse = 0 */ - - /* AGC1 control register */ - 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ - - /* Timing loop register */ - 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ - - 0x10, 0x3f, // AGC2 0x3d - - 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on - - 0x15, 0xc9, // lock detector threshold - - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - - 0x1f, 0x50, - - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - - 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 - - 0x29, 0x1e, // 1/2 threshold - 0x2a, 0x14, // 2/3 threshold - 0x2b, 0x0f, // 3/4 threshold - 0x2c, 0x09, // 5/6 threshold - 0x2d, 0x05, // 7/8 threshold - 0x2e, 0x01, - - 0x31, 0x1f, // test all FECs - - 0x32, 0x19, // viterbi and synchro search - 0x33, 0xfc, // rs control - 0x34, 0x93, // error control -}; - - -static u8 init_tab_samsung [] = { - 0x01, 0x15, - 0x02, 0x00, - 0x03, 0x00, - 0x04, 0x7D, - 0x05, 0x35, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0xC3, - 0x0C, 0x00, - 0x0D, 0x81, - 0x0E, 0x23, - 0x0F, 0x12, - 0x10, 0x7E, - 0x11, 0x84, - 0x12, 0xB9, - 0x13, 0x88, - 0x14, 0x89, - 0x15, 0xC9, - 0x16, 0x00, - 0x17, 0x5C, - 0x18, 0x00, - 0x19, 0x00, - 0x1A, 0x00, - 0x1C, 0x00, - 0x1D, 0x00, - 0x1E, 0x00, - 0x1F, 0x3A, - 0x20, 0x2E, - 0x21, 0x80, - 0x22, 0xFF, - 0x23, 0xC1, - 0x28, 0x00, - 0x29, 0x1E, - 0x2A, 0x14, - 0x2B, 0x0F, - 0x2C, 0x09, - 0x2D, 0x05, - 0x31, 0x1F, - 0x32, 0x19, - 0x33, 0xFE, - 0x34, 0x93 + int errmode; }; +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 -static u8 init_tab_su1278_tsa_tt [] = { - 0x01, 0x0f, - 0x02, 0x30, - 0x03, 0x00, - 0x04, 0x5b, - 0x05, 0x85, - 0x06, 0x02, - 0x07, 0x00, - 0x08, 0x02, - 0x09, 0x00, - 0x0C, 0x01, - 0x0D, 0x81, - 0x0E, 0x44, - 0x0f, 0x14, - 0x10, 0x3c, - 0x11, 0x84, - 0x12, 0xda, - 0x13, 0x97, - 0x14, 0x95, - 0x15, 0xc9, - 0x16, 0x19, - 0x17, 0x8c, - 0x18, 0x59, - 0x19, 0xf8, - 0x1a, 0xfe, - 0x1c, 0x7f, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0x50, - 0x20, 0x00, - 0x21, 0x00, - 0x22, 0x00, - 0x23, 0x00, - 0x28, 0x00, - 0x29, 0x28, - 0x2a, 0x14, - 0x2b, 0x0f, - 0x2c, 0x09, - 0x2d, 0x09, - 0x31, 0x1f, - 0x32, 0x19, - 0x33, 0xfc, - 0x34, 0x13 -}; +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "stv0299: " args); \ + } while (0) -static int stv0299_set_FEC (struct i2c_adapter *i2c, fe_code_rate_t fec); -static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type); -static int stv0299_writereg (struct i2c_adapter *i2c, u8 reg, u8 data) +static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) { int ret; u8 buf [] = { reg, data }; - struct i2c_msg msg = { .addr = 0x68, .flags = 0, .buf = buf, .len = 2 }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; - ret = i2c_transfer (i2c, &msg, 1); + ret = i2c_transfer (state->i2c, &msg, 1); if (ret != 1) dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " @@ -292,16 +95,23 @@ return (ret != 1) ? -EREMOTEIO : 0; } +int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data) +{ + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + + return stv0299_writeregI(state, reg, data); +} + -static u8 stv0299_readreg (struct i2c_adapter *i2c, u8 reg) +static u8 stv0299_readreg (struct stv0299_state* state, u8 reg) { int ret; u8 b0 [] = { reg }; u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = b0, .len = 1 }, - { .addr = 0x68, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - ret = i2c_transfer (i2c, msg, 2); + ret = i2c_transfer (state->i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", @@ -311,13 +121,13 @@ } -static int stv0299_readregs (struct i2c_adapter *i2c, u8 reg1, u8 *b, u8 len) +static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len) { int ret; - struct i2c_msg msg [] = { { .addr = 0x68, .flags = 0, .buf = ®1, .len = 1 }, - { .addr = 0x68, .flags = I2C_M_RD, .buf = b, .len = len } }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; - ret = i2c_transfer (i2c, msg, 2); + ret = i2c_transfer (state->i2c, msg, 2); if (ret != 2) dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); @@ -326,373 +136,44 @@ } -static int pll_write (struct i2c_adapter *i2c, u8 addr, u8 *data, int len) -{ - int ret; - struct i2c_msg msg = { .addr = addr, .buf = data, .len = len }; - - - stv0299_writereg(i2c, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - - ret = i2c_transfer (i2c, &msg, 1); - - stv0299_writereg(i2c, 0x05, 0x35); /* disable i2c repeater on stv0299 */ - - if (ret != 1) - dprintk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); - - return (ret != 1) ? -1 : 0; -} - - -static int sl1935_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype) -{ - u8 buf[4]; - u32 div; - - div = freq / 125; - - dprintk("%s : freq = %i, div = %i\n", __FUNCTION__, freq, div); - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x84; // 0xC4 - buf[3] = 0x08; - - if (freq < 1500000) buf[3] |= 0x10; - - return pll_write (i2c, 0x61, buf, sizeof(buf)); -} - -/** - * set up the downconverter frequency divisor for a - * reference clock comparision frequency of 125 kHz. - */ -static int tsa5059_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate) -{ - u8 addr; - u32 div; - u8 buf[4]; - int divisor, regcode; - - dprintk ("%s: freq %i, ftype %i\n", __FUNCTION__, freq, ftype); - - if ((freq < 950000) || (freq > 2150000)) return -EINVAL; - - if (ftype == PHILIPS_SU1278_TSA_TT) { - divisor = 500; - regcode = 2; - } else { - divisor = 125; - regcode = 4; - } - - // setup frequency divisor - div = (freq + (divisor - 1)) / divisor; // round correctly - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = 0x80 | ((div & 0x18000) >> 10) | regcode; - buf[3] = 0; - - // tuner-specific settings - switch(ftype) { - case PHILIPS_SU1278_TSA: - case PHILIPS_SU1278_TSA_TT: - case PHILIPS_SU1278_TSA_TY: - case PHILIPS_SU1278_TSA_CI: - if (ftype == PHILIPS_SU1278_TSA_TY || ftype == PHILIPS_SU1278_TSA_CI) - addr = 0x61; - else - addr = 0x60; - - buf[3] |= 0x20; - - if (srate < 4000000) buf[3] |= 1; - - if (freq < 1250000) buf[3] |= 0; - else if (freq < 1550000) buf[3] |= 0x40; - else if (freq < 2050000) buf[3] |= 0x80; - else if (freq < 2150000) buf[3] |= 0xC0; - break; - - case ALPS_BSRU6: - addr = 0x61; - buf[3] = 0xC4; - if (freq > 1530000) buf[3] = 0xc0; - break; - - default: - return -EINVAL; - } - - return pll_write (i2c, addr, buf, sizeof(buf)); -} - - -#define MIN2(a,b) ((a) < (b) ? (a) : (b)) -#define MIN3(a,b,c) MIN2(MIN2(a,b),c) - -static int tua6100_set_tv_freq (struct i2c_adapter *i2c, u32 freq, - int ftype, int srate) -{ - u8 reg0 [2] = { 0x00, 0x00 }; - u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 }; - u8 reg2 [3] = { 0x02, 0x00, 0x00 }; - int _fband; - int first_ZF; - int R, A, N, P, M; - int err; - - first_ZF = (freq) / 1000; - - if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) < - abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890)))) - _fband = 2; - else - _fband = 3; - - if (_fband == 2) { - if (((first_ZF >= 950) && (first_ZF < 1350)) || - ((first_ZF >= 1430) && (first_ZF < 1950))) - reg0[1] = 0x07; - else if (((first_ZF >= 1350) && (first_ZF < 1430)) || - ((first_ZF >= 1950) && (first_ZF < 2150))) - reg0[1] = 0x0B; - } - - if(_fband == 3) { - if (((first_ZF >= 950) && (first_ZF < 1350)) || - ((first_ZF >= 1455) && (first_ZF < 1950))) - reg0[1] = 0x07; - else if (((first_ZF >= 1350) && (first_ZF < 1420)) || - ((first_ZF >= 1950) && (first_ZF < 2150))) - reg0[1] = 0x0B; - else if ((first_ZF >= 1420) && (first_ZF < 1455)) - reg0[1] = 0x0F; -} - - if (first_ZF > 1525) - reg1[1] |= 0x80; - else - reg1[1] &= 0x7F; - - if (_fband == 2) { - if (first_ZF > 1430) { /* 1430MHZ */ - reg1[1] &= 0xCF; /* N2 */ - reg2[1] &= 0xCF; /* R2 */ - reg2[1] |= 0x10; - } else { - reg1[1] &= 0xCF; /* N2 */ - reg1[1] |= 0x20; - reg2[1] &= 0xCF; /* R2 */ - reg2[1] |= 0x10; - } -} - - if (_fband == 3) { - if ((first_ZF >= 1455) && - (first_ZF < 1630)) { - reg1[1] &= 0xCF; /* N2 */ - reg1[1] |= 0x20; - reg2[1] &= 0xCF; /* R2 */ - } else { - if (first_ZF < 1455) { - reg1[1] &= 0xCF; /* N2 */ - reg1[1] |= 0x20; - reg2[1] &= 0xCF; /* R2 */ - reg2[1] |= 0x10; - } else { - if (first_ZF >= 1630) { - reg1[1] &= 0xCF; /* N2 */ - reg2[1] &= 0xCF; /* R2 */ - reg2[1] |= 0x10; - } - } - } - } - - /* set ports, enable P0 for symbol rates > 4Ms/s */ - if (srate >= 4000000) - reg1[1] |= 0x0c; - else - reg1[1] |= 0x04; - - reg2[1] |= 0x0c; - - R = 64; - A = 64; - P = 64; //32 - - M = (freq * R) / 4; /* in Mhz */ - N = (M - A * 1000) / (P * 1000); - - reg1[1] |= (N >> 9) & 0x03; - reg1[2] = (N >> 1) & 0xff; - reg1[3] = (N << 7) & 0x80; - - reg2[1] |= (R >> 8) & 0x03; - reg2[2] = R & 0xFF; /* R */ - - reg1[3] |= A & 0x7f; /* A */ - - if (P == 64) - reg1[1] |= 0x40; /* Prescaler 64/65 */ - - reg0[1] |= 0x03; - - if ((err = pll_write(i2c, 0x60, reg0, sizeof(reg0)))) - return err; - - if ((err = pll_write(i2c, 0x60, reg1, sizeof(reg1)))) - return err; - - if ((err = pll_write(i2c, 0x60, reg2, sizeof(reg2)))) - return err; - - return 0; -} - - -static int pll_set_tv_freq (struct i2c_adapter *i2c, u32 freq, int ftype, int srate) -{ - switch(ftype) { - case SAMSUNG_TBMU24112IMB: - return sl1935_set_tv_freq(i2c, freq, ftype); - - case LG_TDQF_S001F: - return sl1935_set_tv_freq(i2c, freq, ftype); - - case PHILIPS_SU1278_TUA: - return tua6100_set_tv_freq(i2c, freq, ftype, srate); - - default: - return tsa5059_set_tv_freq(i2c, freq, ftype, srate); -} -} - -#if 0 -static int tsa5059_read_status (struct i2c_adapter *i2c) -{ - int ret; - u8 rpt1 [] = { 0x05, 0xb5 }; - u8 stat [] = { 0 }; - - struct i2c_msg msg [] = {{ .addr = 0x68, .flags = 0, .buf = rpt1, .len = 2 }, - { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; - - dprintk ("%s\n", __FUNCTION__); - - ret = i2c_transfer (i2c, msg, 2); - - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); - - return stat[0]; -} -#endif - - -static int stv0299_init (struct i2c_adapter *i2c, int ftype) -{ - int i; - - dprintk("stv0299: init chip\n"); - - switch(ftype) { - case SAMSUNG_TBMU24112IMB: - dprintk("%s: init stv0299 chip for Samsung TBMU24112IMB\n", __FUNCTION__); - - for (i=0; i 4) @@ -710,13 +191,13 @@ } -static int stv0299_wait_diseqc_fifo (struct i2c_adapter *i2c, int timeout) +static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) { unsigned long start = jiffies; dprintk ("%s\n", __FUNCTION__); - while (stv0299_readreg(i2c, 0x0a) & 1) { + while (stv0299_readreg(state, 0x0a) & 1) { if (jiffies - start > timeout) { dprintk ("%s: timeout!!\n", __FUNCTION__); return -ETIMEDOUT; @@ -728,13 +209,13 @@ } -static int stv0299_wait_diseqc_idle (struct i2c_adapter *i2c, int timeout) +static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) { unsigned long start = jiffies; dprintk ("%s\n", __FUNCTION__); - while ((stv0299_readreg(i2c, 0x0a) & 3) != 2 ) { + while ((stv0299_readreg(state, 0x0a) & 3) != 2 ) { if (jiffies - start > timeout) { dprintk ("%s: timeout!!\n", __FUNCTION__); return -ETIMEDOUT; @@ -745,101 +226,156 @@ return 0; } +static int stv0299_set_symbolrate (struct dvb_frontend* fe, u32 srate) +{ + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + u64 big = srate; + u32 ratio; + + // check rate is within limits + if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; + + // calculate value to program + big = big << 20; + big += (state->config->mclk-1); // round correctly + do_div(big, state->config->mclk); + ratio = big << 4; + + return state->config->set_symbol_rate(fe, srate, ratio); +} + + +static int stv0299_get_symbolrate (struct stv0299_state* state) +{ + u32 Mclk = state->config->mclk / 4096L; + u32 srate; + s32 offset; + u8 sfr[3]; + s8 rtf; + + dprintk ("%s\n", __FUNCTION__); + + stv0299_readregs (state, 0x1f, sfr, 3); + stv0299_readregs (state, 0x1a, &rtf, 1); + + srate = (sfr[0] << 8) | sfr[1]; + srate *= Mclk; + srate /= 16; + srate += (sfr[2] >> 4) * Mclk / 256; + offset = (s32) rtf * (srate / 4096L); + offset /= 128; + + dprintk ("%s : srate = %i\n", __FUNCTION__, srate); + dprintk ("%s : ofset = %i\n", __FUNCTION__, offset); + + srate += offset; + + srate += 1000; + srate /= 2000; + srate *= 2000; + + return srate; +} + + + + + + + + + + -static int stv0299_send_diseqc_msg (struct i2c_adapter *i2c, + + + +static int stv0299_send_diseqc_msg (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *m) { + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; u8 val; int i; dprintk ("%s\n", __FUNCTION__); - if (stv0299_wait_diseqc_idle (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; - val = stv0299_readreg (i2c, 0x08); + val = stv0299_readreg (state, 0x08); - if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ + if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ return -EREMOTEIO; for (i=0; imsg_len; i++) { - if (stv0299_wait_diseqc_fifo (i2c, 100) < 0) + if (stv0299_wait_diseqc_fifo (state, 100) < 0) return -ETIMEDOUT; - if (stv0299_writereg (i2c, 0x09, m->msg[i])) + if (stv0299_writeregI (state, 0x09, m->msg[i])) return -EREMOTEIO; } - if (stv0299_wait_diseqc_idle (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; return 0; } -static int stv0299_send_diseqc_burst (struct i2c_adapter *i2c, fe_sec_mini_cmd_t burst) +static int stv0299_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; u8 val; dprintk ("%s\n", __FUNCTION__); - if (stv0299_wait_diseqc_idle (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; - val = stv0299_readreg (i2c, 0x08); + val = stv0299_readreg (state, 0x08); - if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ + if (stv0299_writeregI (state, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ return -EREMOTEIO; - if (stv0299_writereg (i2c, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) + if (stv0299_writeregI (state, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) return -EREMOTEIO; - if (stv0299_wait_diseqc_idle (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; - if (stv0299_writereg (i2c, 0x08, val)) + if (stv0299_writeregI (state, 0x08, val)) return -EREMOTEIO; return 0; } -static int stv0299_set_tone (struct i2c_adapter *i2c, fe_sec_tone_mode_t tone) +static int stv0299_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; u8 val; - dprintk("%s: %s\n", __FUNCTION__, - tone == SEC_TONE_ON ? "SEC_TONE_ON" : - tone == SEC_TONE_OFF ? "SEC_TONE_OFF" : "??"); - - if (stv0299_wait_diseqc_idle (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (state, 100) < 0) return -ETIMEDOUT; - val = stv0299_readreg (i2c, 0x08); + val = stv0299_readreg (state, 0x08); switch (tone) { case SEC_TONE_ON: - { - dprintk("%s: TONE_ON\n", __FUNCTION__); - return stv0299_writereg (i2c, 0x08, val | 0x3); - } + return stv0299_writeregI (state, 0x08, val | 0x3); + case SEC_TONE_OFF: - { - dprintk("%s: TONE_OFF\n", __FUNCTION__); - return stv0299_writereg (i2c, 0x08, (val & ~0x3) | 0x02); - } + return stv0299_writeregI (state, 0x08, (val & ~0x3) | 0x02); + default: - { - dprintk("%s: TONE INVALID\n", __FUNCTION__); return -EINVAL; } - }; } -static int stv0299_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage, - int tuner_type) +static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) { + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; u8 reg0x08; u8 reg0x0c; @@ -847,8 +383,8 @@ voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" : voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??"); - reg0x08 = stv0299_readreg (i2c, 0x08); - reg0x0c = stv0299_readreg (i2c, 0x0c); + reg0x08 = stv0299_readreg (state, 0x08); + reg0x0c = stv0299_readreg (state, 0x0c); /** * H/V switching over OP0, OP1 and OP2 are LNB power enable bits @@ -856,37 +392,28 @@ reg0x0c &= 0x0f; if (voltage == SEC_VOLTAGE_OFF) { - stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */ - return stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */ + stv0299_writeregI (state, 0x0c, 0x00); /* LNB power off! */ + return stv0299_writeregI (state, 0x08, 0x00); /* LNB power off! */ } - if (tuner_type == PHILIPS_SU1278_TSA_CI) - { - stv0299_writereg (i2c, 0x08, reg0x08 & 0xBF); // switch LNB power on OP2/LOCK pin off - } - else - { - stv0299_writereg (i2c, 0x08, reg0x08 | 0x40); - } + stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); switch (voltage) { case SEC_VOLTAGE_13: - if (tuner_type == PHILIPS_SU1278_TSA_TY || tuner_type == PHILIPS_SU1278_TSA_CI) - return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x10); - else - return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x40); + if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) reg0x0c |= 0x10; + else reg0x0c |= 0x40; - case SEC_VOLTAGE_18: - return stv0299_writereg (i2c, 0x0c, reg0x0c | 0x50); + return stv0299_writeregI(state, 0x0c, reg0x0c); + case SEC_VOLTAGE_18: + return stv0299_writeregI(state, 0x0c, reg0x0c | 0x50); default: return -EINVAL; }; } -static int stv0299_send_legacy_dish_cmd(struct i2c_adapter *i2c, u32 cmd, - int tuner_type) +static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd) { u8 last = 1; int i; @@ -901,15 +428,14 @@ cmd = cmd << 1; dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd); - stv0299_set_voltage(i2c,SEC_VOLTAGE_18,tuner_type); + stv0299_set_voltage(fe,SEC_VOLTAGE_18); msleep(32); for (i=0; i<9; i++) { if((cmd & 0x01) != last) { - stv0299_set_voltage(i2c, + stv0299_set_voltage(fe, last ? SEC_VOLTAGE_13 : - SEC_VOLTAGE_18, - tuner_type); + SEC_VOLTAGE_18); last = (last) ? 0 : 1; } @@ -922,160 +448,35 @@ return 0; } -static int stv0299_set_symbolrate (struct i2c_adapter *i2c, u32 srate, int tuner_type) + +static int stv0299_init (struct dvb_frontend* fe) { - u64 big = srate; - u32 ratio; - u8 aclk = 0; - u8 bclk = 0; - u8 m1; - int Mclk = M_CLK; + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + int i; - // check rate is within limits - if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; + dprintk("stv0299: init chip\n"); - // calculate value to program - if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT; - big = big << 20; - big += (Mclk-1); // round correctly - do_div(big, Mclk); - ratio = big << 4; - - // program registers - switch(tuner_type) { - case PHILIPS_SU1278_TSA_TT: - stv0299_writereg (i2c, 0x0e, 0x44); - if (srate >= 10000000) { - stv0299_writereg (i2c, 0x13, 0x97); - stv0299_writereg (i2c, 0x14, 0x95); - stv0299_writereg (i2c, 0x15, 0xc9); - stv0299_writereg (i2c, 0x17, 0x8c); - stv0299_writereg (i2c, 0x1a, 0xfe); - stv0299_writereg (i2c, 0x1c, 0x7f); - stv0299_writereg (i2c, 0x2d, 0x09); - } else { - stv0299_writereg (i2c, 0x13, 0x99); - stv0299_writereg (i2c, 0x14, 0x8d); - stv0299_writereg (i2c, 0x15, 0xce); - stv0299_writereg (i2c, 0x17, 0x43); - stv0299_writereg (i2c, 0x1a, 0x1d); - stv0299_writereg (i2c, 0x1c, 0x12); - stv0299_writereg (i2c, 0x2d, 0x05); - } - stv0299_writereg (i2c, 0x0e, 0x23); - stv0299_writereg (i2c, 0x0f, 0x94); - stv0299_writereg (i2c, 0x10, 0x39); - stv0299_writereg (i2c, 0x15, 0xc9); - - stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0); - break; - - case PHILIPS_SU1278_TSA_TY: - case PHILIPS_SU1278_TSA_CI: - case PHILIPS_SU1278_TSA: - aclk = 0xb5; - if (srate < 2000000) bclk = 0x86; - else if (srate < 5000000) bclk = 0x89; - else if (srate < 15000000) bclk = 0x8f; - else if (srate < 45000000) bclk = 0x95; - - m1 = 0x14; - if (srate < 4000000) m1 = 0x10; - - stv0299_writereg (i2c, 0x13, aclk); - stv0299_writereg (i2c, 0x14, bclk); - stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0); - stv0299_writereg (i2c, 0x0f, (stv0299_readreg(i2c, 0x0f) & 0xc0) | m1); - break; + for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) + stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]); - case ALPS_BSRU6: - default: - if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } - else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } - else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } - else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } - else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } - else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } - - stv0299_writereg (i2c, 0x13, aclk); - stv0299_writereg (i2c, 0x14, bclk); - stv0299_writereg (i2c, 0x1f, (ratio >> 16) & 0xff); - stv0299_writereg (i2c, 0x20, (ratio >> 8) & 0xff); - stv0299_writereg (i2c, 0x21, (ratio ) & 0xf0); - break; + if (state->config->pll_init) { + stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ + state->config->pll_init(fe); + stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ } - return 0; } -static int stv0299_get_symbolrate (struct i2c_adapter *i2c, int tuner_type) -{ - u32 Mclk = M_CLK / 4096L; - u32 srate; - s32 offset; - u8 sfr[3]; - s8 rtf; - - dprintk ("%s\n", __FUNCTION__); - - if (tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT / 4096L; - - stv0299_readregs (i2c, 0x1f, sfr, 3); - stv0299_readregs (i2c, 0x1a, &rtf, 1); - - srate = (sfr[0] << 8) | sfr[1]; - srate *= Mclk; - srate /= 16; - srate += (sfr[2] >> 4) * Mclk / 256; - - offset = (s32) rtf * (srate / 4096L); - offset /= 128; - - dprintk ("%s : srate = %i\n", __FUNCTION__, srate); - dprintk ("%s : ofset = %i\n", __FUNCTION__, offset); - - srate += offset; - - srate += 1000; - srate /= 2000; - srate *= 2000; - - return srate; -} - -static int uni0299_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct stv0299_state *state = (struct stv0299_state *) fe->data; - struct i2c_adapter *i2c = state->i2c; - - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_GET_INFO: +static int stv0299_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) arg; - memcpy (arg, &uni0299_info, sizeof(struct dvb_frontend_info)); - - if (state->tuner_type == PHILIPS_SU1278_TSA_TT) { - tmp->frequency_tolerance = M_CLK_SU1278_TSA_TT / 2000; - } - break; - } + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - case FE_READ_STATUS: - { - fe_status_t *status = (fe_status_t *) arg; - u8 signal = 0xff - stv0299_readreg (i2c, 0x18); - u8 sync = stv0299_readreg (i2c, 0x1b); + u8 signal = 0xff - stv0299_readreg (state, 0x18); + u8 sync = stv0299_readreg (state, 0x1b); dprintk ("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __FUNCTION__, sync); - *status = 0; if (signal > 10) @@ -1093,53 +494,61 @@ if ((sync & 0x98) == 0x98) *status |= FE_HAS_LOCK; - break; + return 0; } - case FE_READ_BER: - if (stv0299_status == STATUS_BER) { - *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8) - | stv0299_readreg (i2c, 0x1e); - } else { - *((u32*) arg) = 0; +static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + + if (state->errmode != STATUS_BER) return 0; + *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); + + return 0; } - break; - case FE_READ_SIGNAL_STRENGTH: +static int stv0299_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - s32 signal = 0xffff - ((stv0299_readreg (i2c, 0x18) << 8) - | stv0299_readreg (i2c, 0x19)); + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + + s32 signal = 0xffff - ((stv0299_readreg (state, 0x18) << 8) + | stv0299_readreg (state, 0x19)); dprintk ("%s : FE_READ_SIGNAL_STRENGTH : AGC2I: 0x%02x%02x, signal=0x%04x\n", __FUNCTION__, - stv0299_readreg (i2c, 0x18), - stv0299_readreg (i2c, 0x19), (int) signal); + stv0299_readreg (state, 0x18), + stv0299_readreg (state, 0x19), (int) signal); signal = signal * 5 / 4; - *((u16*) arg) = (signal > 0xffff) ? 0xffff : - (signal < 0) ? 0 : signal; - break; - } - case FE_READ_SNR: - { - s32 snr = 0xffff - ((stv0299_readreg (i2c, 0x24) << 8) - | stv0299_readreg (i2c, 0x25)); - snr = 3 * (snr - 0xa100); - *((u16*) arg) = (snr > 0xffff) ? 0xffff : - (snr < 0) ? 0 : snr; - break; - } - case FE_READ_UNCORRECTED_BLOCKS: - if (stv0299_status == STATUS_UCBLOCKS) { - *((u32*) arg) = (stv0299_readreg (i2c, 0x1d) << 8) - | stv0299_readreg (i2c, 0x1e); - } else { - *((u32*) arg) = 0; + *strength = (signal > 0xffff) ? 0xffff : (signal < 0) ? 0 : signal; + + return 0; } - break; - case FE_SET_FRONTEND: +static int stv0299_read_snr(struct dvb_frontend* fe, u16* snr) { - struct dvb_frontend_parameters *p = arg; + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + + s32 xsnr = 0xffff - ((stv0299_readreg (state, 0x24) << 8) + | stv0299_readreg (state, 0x25)); + xsnr = 3 * (xsnr - 0xa100); + *snr = (xsnr > 0xffff) ? 0xffff : (xsnr < 0) ? 0 : xsnr; + + return 0; +} + +static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + + if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; + else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); + + return 0; +} + +static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) +{ + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; int invval = 0; dprintk ("%s : FE_SET_FRONTEND\n", __FUNCTION__); @@ -1151,12 +560,10 @@ printk("stv0299 does not support auto-inversion\n"); return -EINVAL; } - if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1; - stv0299_writereg(i2c, 0x0c, (stv0299_readreg(i2c, 0x0c) & 0xfe) | invval); + if (state->config->invert) invval = (~invval) & 1; + stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); - switch(state->tuner_type) { - case PHILIPS_SU1278_TSA_TT: - { + if (state->config->enhanced_tuning) { /* check if we should do a finetune */ int frequency_delta = p->frequency - state->tuner_frequency; int minmax = p->u.qpsk.symbol_rate / 2000; @@ -1165,130 +572,88 @@ if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) && (state->fec_inner == p->u.qpsk.fec_inner) && (state->symbol_rate == p->u.qpsk.symbol_rate)) { - int Drot_freq = (frequency_delta << 16) / (M_CLK_SU1278_TSA_TT / 1000); + int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000); // zap the derotator registers first - stv0299_writereg (i2c, 0x22, 0x00); - stv0299_writereg (i2c, 0x23, 0x00); + stv0299_writeregI(state, 0x22, 0x00); + stv0299_writeregI(state, 0x23, 0x00); // now set them as we want - stv0299_writereg (i2c, 0x22, Drot_freq >> 8); - stv0299_writereg (i2c, 0x23, Drot_freq); + stv0299_writeregI(state, 0x22, Drot_freq >> 8); + stv0299_writeregI(state, 0x23, Drot_freq); } else { /* A "normal" tune is requested */ - pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate); - stv0299_writereg (i2c, 0x32, 0x80); - stv0299_writereg (i2c, 0x22, 0x00); - stv0299_writereg (i2c, 0x23, 0x00); - stv0299_writereg (i2c, 0x32, 0x19); - stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type); - stv0299_set_FEC (i2c, p->u.qpsk.fec_inner); - } - break; + stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ + state->config->pll_set(fe, p); + stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ + + stv0299_writeregI(state, 0x32, 0x80); + stv0299_writeregI(state, 0x22, 0x00); + stv0299_writeregI(state, 0x23, 0x00); + stv0299_writeregI(state, 0x32, 0x19); + stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); + stv0299_set_FEC (state, p->u.qpsk.fec_inner); } - - default: - pll_set_tv_freq (i2c, p->frequency, state->tuner_type, p->u.qpsk.symbol_rate); - stv0299_set_FEC (i2c, p->u.qpsk.fec_inner); - stv0299_set_symbolrate (i2c, p->u.qpsk.symbol_rate, state->tuner_type); - stv0299_writereg (i2c, 0x22, 0x00); - stv0299_writereg (i2c, 0x23, 0x00); - stv0299_readreg (i2c, 0x23); - stv0299_writereg (i2c, 0x12, 0xb9); - break; + } else { + stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ + state->config->pll_set(fe, p); + stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ + + stv0299_set_FEC (state, p->u.qpsk.fec_inner); + stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); + stv0299_writeregI(state, 0x22, 0x00); + stv0299_writeregI(state, 0x23, 0x00); + stv0299_readreg (state, 0x23); + stv0299_writeregI(state, 0x12, 0xb9); } state->tuner_frequency = p->frequency; state->fec_inner = p->u.qpsk.fec_inner; state->symbol_rate = p->u.qpsk.symbol_rate; - break; + + return 0; } - case FE_GET_FRONTEND: +static int stv0299_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters * p) { - struct dvb_frontend_parameters *p = arg; + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; s32 derot_freq; - int Mclk = M_CLK; int invval; - if (state->tuner_type == PHILIPS_SU1278_TSA_TT) Mclk = M_CLK_SU1278_TSA_TT; + derot_freq = (s32)(s16) ((stv0299_readreg (state, 0x22) << 8) + | stv0299_readreg (state, 0x23)); - derot_freq = (s32)(s16) ((stv0299_readreg (i2c, 0x22) << 8) - | stv0299_readreg (i2c, 0x23)); - - derot_freq *= (Mclk >> 16); + derot_freq *= (state->config->mclk >> 16); derot_freq += 500; derot_freq /= 1000; p->frequency += derot_freq; - invval = stv0299_readreg (i2c, 0x0c) & 1; - if (state->tuner_type == ALPS_BSRU6) invval = (~invval) & 1; + invval = stv0299_readreg (state, 0x0c) & 1; + if (state->config->invert) invval = (~invval) & 1; p->inversion = invval ? INVERSION_ON : INVERSION_OFF; - p->u.qpsk.fec_inner = stv0299_get_fec (i2c); - p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c, state->tuner_type); - break; - } - - case FE_SLEEP: - stv0299_writereg (i2c, 0x0c, 0x00); /* LNB power off! */ - stv0299_writereg (i2c, 0x08, 0x00); /* LNB power off! */ - stv0299_writereg (i2c, 0x02, 0x80); - state->initialised = 0; - break; - - case FE_INIT: - switch(state->tuner_type) { - case PHILIPS_SU1278_TSA_TT: - state->tuner_frequency = 0; - if (!state->initialised) { - state->initialised = 1; - return stv0299_init (i2c, state->tuner_type); - } - break; + p->u.qpsk.fec_inner = stv0299_get_fec (state); + p->u.qpsk.symbol_rate = stv0299_get_symbolrate (state); - default: - return stv0299_init (i2c, state->tuner_type); + return 0; } - break; - - case FE_DISEQC_SEND_MASTER_CMD: - return stv0299_send_diseqc_msg (i2c, arg); - case FE_DISEQC_SEND_BURST: - return stv0299_send_diseqc_burst (i2c, (fe_sec_mini_cmd_t) arg); - - case FE_SET_TONE: - return stv0299_set_tone (i2c, (fe_sec_tone_mode_t) arg); +static int stv0299_sleep(struct dvb_frontend* fe) +{ + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - case FE_SET_VOLTAGE: - return stv0299_set_voltage (i2c, (fe_sec_voltage_t) arg, - state->tuner_type); + stv0299_writeregI(state, 0x02, 0x80); + state->initialised = 0; - case FE_DISHNETWORK_SEND_LEGACY_CMD: - return stv0299_send_legacy_dish_cmd (i2c, - (u32)(unsigned long)arg, - state->tuner_type); + return 0; +} - case FE_GET_TUNE_SETTINGS: +static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; - - switch(state->tuner_type) { - case PHILIPS_SU1278_TSA_TT: - fesettings->min_delay_ms = 50; - if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; - fesettings->max_drift = 5000; - } else { - fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; - fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; - } - break; + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; - default: - fesettings->min_delay_ms = 100; + fesettings->min_delay_ms = state->config->min_delay_ms; if (fesettings->parameters.u.qpsk.symbol_rate < 10000000) { fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 32000; fesettings->max_drift = 5000; @@ -1296,225 +661,103 @@ fesettings->step_size = fesettings->parameters.u.qpsk.symbol_rate / 16000; fesettings->max_drift = fesettings->parameters.u.qpsk.symbol_rate / 2000; } - break; - } - - return 0; - } - - default: - return -EOPNOTSUPP; - }; - return 0; } -static long probe_tuner (struct i2c_adapter *adapter) -{ - struct i2c_adapter *i2c = adapter; /* superfluous */ - - /* read the status register of TSA5059 */ - u8 rpt[] = { 0x05, 0xb5 }; - u8 stat [] = { 0 }; - u8 tda6100_buf [] = { 0, 0 }; - int ret; - struct i2c_msg msg1 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, .len = 2 }, - { .addr = 0x60, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; - struct i2c_msg msg2 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, .len = 2 }, - { .addr = 0x61, .flags = I2C_M_RD, .buf = stat, .len = 1 }}; - struct i2c_msg msg3 [] = {{ .addr = 0x68, .flags = 0, .buf = rpt, .len = 2 }, - { .addr = 0x60, .flags = 0, .buf = tda6100_buf, .len = 2 }}; - - stv0299_writereg (i2c, 0x01, 0x15); - stv0299_writereg (i2c, 0x02, 0x30); - stv0299_writereg (i2c, 0x03, 0x00); - - - printk("stv0299: try to attach to %s\n", adapter->name); - - if (!strcmp(adapter->name, "SkyStar2")) { - printk ("stv0299: setup for tuner Samsung TBMU24112IMB\n"); - return SAMSUNG_TBMU24112IMB; - } - - if ((ret = i2c_transfer(i2c, msg1, 2)) == 2) { - if ( strcmp(adapter->name, "TT-Budget/WinTV-NOVA-CI PCI") == 0 ) { - // technotrend cards require non-datasheet settings - printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on TechnoTrend hardware\n"); - return PHILIPS_SU1278_TSA_TT; - } else { - // fall back to datasheet-recommended settings - printk ("stv0299: setup for tuner SU1278 (TSA5059 synth)\n"); - return PHILIPS_SU1278_TSA; - } - } - - if ((ret = i2c_transfer(i2c, msg2, 2)) == 2) { - if ( strcmp(adapter->name, "KNC1 DVB-S") == 0 ) +static void stv0299_release(struct dvb_frontend* fe) { - // Typhoon cards have unusual wiring. - printk ("stv0299: setup for tuner SU1278 (TSA5059 synth) on Typhoon hardware\n"); - return PHILIPS_SU1278_TSA_TY; - } - else if ( strcmp(adapter->name, "TerraTec Cinergy 1200 DVB-S") == 0 ) - { - // Cinergy cards have unusual wiring. - printk ("%s: setup for tuner SU1278 (TSA5059 synth) on" - " TerraTec hardware\n", __FILE__); - return PHILIPS_SU1278_TSA_CI; - } - //else if ((stat[0] & 0x3f) == 0) { - else if (0) { - printk ("stv0299: setup for tuner TDQF-S001F\n"); - return LG_TDQF_S001F; - } else { - printk ("stv0299: setup for tuner BSRU6, TDQB-S00x\n"); - return ALPS_BSRU6; - } - } - - /** - * setup i2c timing for SU1278... - */ - stv0299_writereg (i2c, 0x02, 0x00); - - if ((ret = i2c_transfer(i2c, msg3, 2)) == 2) { - printk ("stv0299: setup for tuner Philips SU1278 (TUA6100 synth)\n"); - return PHILIPS_SU1278_TUA; - } - - printk ("stv0299: unknown PLL synthesizer (ret == %i), please report to !!\n", ret); - - return UNKNOWN_FRONTEND; + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + kfree(state); } -static struct i2c_client client_template; +static struct dvb_frontend_ops stv0299_ops; -static int attach_adapter(struct i2c_adapter *adapter) +struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, + struct i2c_adapter* i2c) { - struct i2c_client *client; - struct stv0299_state* state; - int tuner_type; - int ret; - u8 id; + struct stv0299_state* state = NULL; + int id; - stv0299_writereg(adapter, 0x02, 0x34); /* standby off */ - msleep(200); - id = stv0299_readreg(adapter, 0x00); + /* allocate memory for the internal state */ + state = (struct stv0299_state*) kmalloc(sizeof(struct stv0299_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + state->tuner_frequency = 0; + state->symbol_rate = 0; + state->fec_inner = 0; + state->errmode = STATUS_BER; - dprintk ("%s: id == 0x%02x\n", __FUNCTION__, id); + /* check if the demod is there */ + stv0299_writeregI(state, 0x02, 0x34); /* standby off */ + msleep(200); + id = stv0299_readreg(state, 0x00); /* register 0x00 contains 0xa1 for STV0299 and STV0299B */ /* register 0x00 might contain 0x80 when returning from standby */ - if (id != 0xa1 && id != 0x80) - return -ENODEV; - - if ((tuner_type = probe_tuner(adapter)) < 0) - return -ENODEV; - - if ((state = kmalloc(sizeof(struct stv0299_state), GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(state); - return -ENOMEM; - } - - state->tuner_type = tuner_type; - state->tuner_frequency = 0; - state->initialised = 0; - state->i2c = adapter; - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = (0x68>>1); - i2c_set_clientdata(client, (void*)state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(state); - return -EFAULT; - } - - BUG_ON(!state->dvb); - - ret = dvb_register_frontend(uni0299_ioctl, state->dvb, state, - &uni0299_info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - kfree(client); - kfree(state); - return -EFAULT; -} + if (id != 0xa1 && id != 0x80) goto error; - return 0; -} - -static int detach_client(struct i2c_client *client) -{ - struct stv0299_state *state = (struct stv0299_state*)i2c_get_clientdata(client); - - dvb_unregister_frontend (uni0299_ioctl, state->dvb); - i2c_detach_client(client); - kfree(client); - kfree(state); - return 0; -} - -static int command (struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct stv0299_state *data = (struct stv0299_state*)i2c_get_clientdata(client); - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_REGISTER: { - data->dvb = (struct dvb_adapter*)arg; - break; - } - case FE_UNREGISTER: { - data->dvb = NULL; - break; - } - default: - return -EOPNOTSUPP; - } - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_STV0299, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; - -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops stv0299_ops = { + + .info = { + .name = "ST STV0299 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + + .release = stv0299_release, + + .init = stv0299_init, + .sleep = stv0299_sleep, + + .set_frontend = stv0299_set_frontend, + .get_frontend = stv0299_get_frontend, + .get_tune_settings = stv0299_get_tune_settings, + + .read_status = stv0299_read_status, + .read_ber = stv0299_read_ber, + .read_signal_strength = stv0299_read_signal_strength, + .read_snr = stv0299_read_snr, + .read_ucblocks = stv0299_read_ucblocks, + + .diseqc_send_master_cmd = stv0299_send_diseqc_msg, + .diseqc_send_burst = stv0299_send_diseqc_burst, + .set_tone = stv0299_set_tone, + .set_voltage = stv0299_set_voltage, + .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, }; -static int __init init_uni0299 (void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_uni0299 (void) -{ - if (i2c_del_driver(&driver)) - printk("stv0299: driver deregistration failed\n"); -} - -module_init (init_uni0299); -module_exit (exit_uni0299); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("Universal STV0299/TSA5059/SL1935 DVB Frontend driver"); +MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(stv0299_writereg); +EXPORT_SYMBOL(stv0299_attach); diff -Nru a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/stv0299.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,104 @@ +/* + Driver for ST STV0299 demodulator + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + , + , + + + + Philips SU1278/SH + + Copyright (C) 2002 by Peter Schildmann + + + LG TDQF-S001F + + Copyright (C) 2002 Felix Domke + & Andreas Oberritter + + + Support for Samsung TBMU24112IMB used on Technisat SkyStar2 rev. 2.6B + + Copyright (C) 2003 Vadim Catana : + + Support for Philips SU1278 on Technotrend hardware + + Copyright (C) 2004 Andrew de Quincey + + 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 STV0299_H +#define STV0299_H + +#include +#include "dvb_frontend.h" + +#define STV0229_LOCKOUTPUT_0 0 +#define STV0229_LOCKOUTPUT_1 1 +#define STV0229_LOCKOUTPUT_CF 2 +#define STV0229_LOCKOUTPUT_LK 3 + +#define STV0299_VOLT13_OP0 0 +#define STV0299_VOLT13_OP1 1 + +struct stv0299_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* inittab - array of pairs of values. + * First of each pair is the register, second is the value. + * List should be terminated with an 0xff, 0xff pair. + */ + u8* inittab; + + /* master clock to use */ + u32 mclk; + + /* does the inversion require inversion? */ + u8 invert:1; + + /* Should the enhanced tuning code be used? */ + u8 enhanced_tuning:1; + + /* Skip reinitialisation? */ + u8 skip_reinit:1; + + /* LOCK OUTPUT setting */ + u8 lock_output:2; + + /* Is 13v controlled by OP0 or OP1? */ + u8 volt13_op0_op1:1; + + /* minimum delay before retuning */ + int min_delay_ms; + + /* Set the symbol rate */ + int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); + +extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, + struct i2c_adapter* i2c); + +#endif // STV0299_H diff -Nru a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/tda10021.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,483 @@ +/* + TDA10021 - Single Chip Cable Channel Receiver driver module + used on the the Siemens DVB-C cards + + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2004 Markus Schulz + Suppport for TDA10021 + + 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 "dvb_frontend.h" +#include "tda10021.h" + + +struct tda10021_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct tda10021_config* config; + + struct dvb_frontend frontend; + + u8 pwm; + u8 reg0; +}; + + +#if 0 +#define dprintk(x...) printk(x) +#else +#define dprintk(x...) +#endif + +static int verbose; + +#define XIN 57840000UL +#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0) +#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0) +#define HAS_INVERSION(reg0) (!(reg0 & 0x20)) + +#define FIN (XIN >> 4) + +int tda10021_inittab_size = 0x40; +static u8 tda10021_inittab[0x40]= +{ + 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a, + 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40, + 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff, + 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58, + 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00, + 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00, +}; + +static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data) +{ + u8 buf[] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer (state->i2c, &msg, 1); + if (ret != 1) + printk("DVB: TDA10021(%d): %s, writereg error " + "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", + state->frontend.dvb->num, __FUNCTION__, reg, data, ret); + + msleep(10); + return (ret != 1) ? -EREMOTEIO : 0; +} + + +static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) +{ + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + int ret; + + ret = i2c_transfer (state->i2c, msg, 2); + if (ret != 2) + printk("DVB: TDA10021(%d): %s: readreg error (ret == %i)\n", + state->frontend.dvb->num, __FUNCTION__, ret); + return b1[0]; +} + +//get access to tuner +static int lock_tuner(struct tda10021_state* state) +{ + u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 }; + struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg, 1) != 1) + { + printk("tda10021: lock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +//release access from tuner +static int unlock_tuner(struct tda10021_state* state) +{ + u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f }; + struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2}; + + if(i2c_transfer(state->i2c, &msg_post, 1) != 1) + { + printk("tda10021: unlock tuner fails\n"); + return -EREMOTEIO; + } + return 0; +} + +static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0, + fe_spectral_inversion_t inversion) +{ + reg0 |= state->reg0 & 0x63; + + if (INVERSION_ON == inversion) + ENABLE_INVERSION(reg0); + else if (INVERSION_OFF == inversion) + DISABLE_INVERSION(reg0); + + tda10021_writereg (state, 0x00, reg0 & 0xfe); + tda10021_writereg (state, 0x00, reg0 | 0x01); + + state->reg0 = reg0; + return 0; +} + +static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate) +{ + s32 BDR; + s32 BDRI; + s16 SFIL=0; + u16 NDEC = 0; + u32 tmp, ratio; + + if (symbolrate > XIN/2) + symbolrate = XIN/2; + if (symbolrate < 500000) + symbolrate = 500000; + + if (symbolrate < XIN/16) NDEC = 1; + if (symbolrate < XIN/32) NDEC = 2; + if (symbolrate < XIN/64) NDEC = 3; + + if (symbolrate < (u32)(XIN/12.3)) SFIL = 1; + if (symbolrate < (u32)(XIN/16)) SFIL = 0; + if (symbolrate < (u32)(XIN/24.6)) SFIL = 1; + if (symbolrate < (u32)(XIN/32)) SFIL = 0; + if (symbolrate < (u32)(XIN/49.2)) SFIL = 1; + if (symbolrate < (u32)(XIN/64)) SFIL = 0; + if (symbolrate < (u32)(XIN/98.4)) SFIL = 1; + + symbolrate <<= NDEC; + ratio = (symbolrate << 4) / FIN; + tmp = ((symbolrate << 4) % FIN) << 8; + ratio = (ratio << 8) + tmp / FIN; + tmp = (tmp % FIN) << 8; + ratio = (ratio << 8) + (tmp + FIN/2) / FIN; + + BDR = ratio; + BDRI = (((XIN << 5) / symbolrate) + 1) / 2; + + if (BDRI > 0xFF) + BDRI = 0xFF; + + SFIL = (SFIL << 4) | tda10021_inittab[0x0E]; + + NDEC = (NDEC << 6) | tda10021_inittab[0x03]; + + tda10021_writereg (state, 0x03, NDEC); + tda10021_writereg (state, 0x0a, BDR&0xff); + tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff); + tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f); + + tda10021_writereg (state, 0x0d, BDRI); + tda10021_writereg (state, 0x0e, SFIL); + + return 0; +} + + + + + + + + + + +static int tda10021_init (struct dvb_frontend *fe) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + int i; + + dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num); + + //tda10021_writereg (fe, 0, 0); + + for (i=0; ipwm); + + //Comment by markus + //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0) + //0x2A[4] == BYPPLL -> Power down mode (default 1) + //0x2A[5] == LCK -> PLL Lock Flag + //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0) + + //Activate PLL + tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef); + + if (state->config->pll_init) { + lock_tuner(state); + state->config->pll_init(fe); + unlock_tuner(state); + } + + return 0; +} + +static int tda10021_set_parameters (struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + + //table for QAM4-QAM256 ready QAM4 QAM16 QAM32 QAM64 QAM128 QAM256 + //CONF + static const u8 reg0x00 [] = { 0x14, 0x00, 0x04, 0x08, 0x0c, 0x10 }; + //AGCREF value + static const u8 reg0x01 [] = { 0x78, 0x8c, 0x8c, 0x6a, 0x78, 0x5c }; + //LTHR value + static const u8 reg0x05 [] = { 0x78, 0x87, 0x64, 0x46, 0x36, 0x26 }; + //MSETH + static const u8 reg0x08 [] = { 0x8c, 0xa2, 0x74, 0x43, 0x34, 0x23 }; + //AREF + static const u8 reg0x09 [] = { 0x96, 0x91, 0x96, 0x6a, 0x7e, 0x6b }; + + int qam = p->u.qam.modulation; + + if (qam < 0 || qam > 5) + return -EINVAL; + + //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); + + lock_tuner(state); + state->config->pll_set(fe, p); + unlock_tuner(state); + + tda10021_set_symbolrate (state, p->u.qam.symbol_rate); + tda10021_writereg (state, 0x34, state->pwm); + + tda10021_writereg (state, 0x01, reg0x01[qam]); + tda10021_writereg (state, 0x05, reg0x05[qam]); + tda10021_writereg (state, 0x08, reg0x08[qam]); + tda10021_writereg (state, 0x09, reg0x09[qam]); + + tda10021_setup_reg0 (state, reg0x00[qam], p->inversion); + + return 0; +} + +static int tda10021_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + int sync; + + *status = 0; + //0x11[0] == EQALGO -> Equalizer algorithms state + //0x11[1] == CARLOCK -> Carrier locked + //0x11[2] == FSYNC -> Frame synchronisation + //0x11[3] == FEL -> Front End locked + //0x11[6] == NODVB -> DVB Mode Information + sync = tda10021_readreg (state, 0x11); + + if (sync & 2) + *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER; + + if (sync & 4) + *status |= FE_HAS_SYNC|FE_HAS_VITERBI; + + if (sync & 8) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + + u32 _ber = tda10021_readreg(state, 0x14) | + (tda10021_readreg(state, 0x15) << 8) | + ((tda10021_readreg(state, 0x16) & 0x0f) << 16); + *ber = 10 * _ber; + + return 0; +} + +static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + + u8 gain = tda10021_readreg(state, 0x17); + *strength = (gain << 8) | gain; + + return 0; +} + +static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + + u8 quality = ~tda10021_readreg(state, 0x18); + *snr = (quality << 8) | quality; + + return 0; +} + +static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + + *ucblocks = tda10021_readreg (state, 0x13) & 0x7f; + if (*ucblocks == 0x7f) + *ucblocks = 0xffffffff; + + /* reset uncorrected block counter */ + tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf); + tda10021_writereg (state, 0x10, tda10021_inittab[0x10]); + + return 0; +} + +static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + int sync; + s8 afc = 0; + + sync = tda10021_readreg(state, 0x11); + afc = tda10021_readreg(state, 0x19); + if (verbose) { + /* AFC only valid when carrier has been recovered */ + printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" : + "DVB: TDA10021(%d): [AFC (%d) %dHz]\n", + state->frontend.dvb->num, afc, + -((s32)p->u.qam.symbol_rate * afc) >> 10); + } + + p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF; + p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; + + p->u.qam.fec_inner = FEC_NONE; + p->frequency = ((p->frequency + 31250) / 62500) * 62500; + + if (sync & 2) + p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; + + return 0; +} + +static int tda10021_sleep(struct dvb_frontend* fe) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + + tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */ + tda10021_writereg (state, 0x00, 0x80); /* standby */ + + return 0; +} + +static void tda10021_release(struct dvb_frontend* fe) +{ + struct tda10021_state* state = (struct tda10021_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops tda10021_ops; + +struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, + struct i2c_adapter* i2c, + u8 pwm) +{ + struct tda10021_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct tda10021_state*) kmalloc(sizeof(struct tda10021_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); + state->pwm = pwm; + state->reg0 = tda10021_inittab[0]; + + /* check if the demod is there */ + if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops tda10021_ops = { + + .info = { + .name = "Philips TDA10021 DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ + .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ + #if 0 + .frequency_tolerance = ???, + .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ + #endif + .caps = 0x400 | //FE_CAN_QAM_4 + FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO + }, + + .release = tda10021_release, + + .init = tda10021_init, + .sleep = tda10021_sleep, + + .set_frontend = tda10021_set_parameters, + .get_frontend = tda10021_get_frontend, + + .read_status = tda10021_read_status, + .read_ber = tda10021_read_ber, + .read_signal_strength = tda10021_read_signal_strength, + .read_snr = tda10021_read_snr, + .read_ucblocks = tda10021_read_ucblocks, +}; + +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); + +MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda10021_attach); diff -Nru a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/tda10021.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,43 @@ +/* + TDA10021 - Single Chip Cable Channel Receiver driver module + used on the the Siemens DVB-C cards + + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2004 Markus Schulz + Suppport for TDA10021 + + 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 TDA10021_H +#define TDA10021_H + +#include + +struct tda10021_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, + struct i2c_adapter* i2c, + u8 pwm); + +#endif // TDA10021_H diff -Nru a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c --- a/drivers/media/dvb/frontends/tda1004x.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/frontends/tda1004x.c 2004-12-12 17:40:53 -08:00 @@ -1,5 +1,5 @@ /* - Driver for Philips tda1004xh OFDM Frontend + Driver for Philips tda1004xh OFDM Demodulator (c) 2003, 2004 Andrew de Quincey & Robert Schlabbach @@ -32,23 +32,35 @@ #include #include #include -#include - #include "dvb_frontend.h" +#include "tda1004x.h" -#define FRONTEND_NAME "dvbfe_tda1004x" +#define TDA1004X_DEMOD_TDA10045 0 +#define TDA1004X_DEMOD_TDA10046 1 -#define dprintk(args...) \ - do { \ - if (debug) printk(KERN_DEBUG FRONTEND_NAME ": " args); \ - } while (0) -static int debug; +struct tda1004x_state +{ + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + const struct tda1004x_config* config; + + struct dvb_frontend frontend; + + /* private demod data */ + u8 initialised:1; + + u8 demod_type; +}; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -#define MC44BC374_ADDRESS 0x65 +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda1004x: " args); \ + } while (0) #define TDA1004X_CHIPID 0x00 #define TDA1004X_AUTO 0x01 @@ -128,53 +140,7 @@ #define TDA10046H_CODE_IN 0x58 -#define FE_TYPE_TDA10045H 0 -#define FE_TYPE_TDA10046H 1 - -#define TUNER_TYPE_TD1344 0 -#define TUNER_TYPE_TD1316 1 - -static struct dvb_frontend_info tda10045h_info = { - .name = "Philips TDA10045H", - .type = FE_OFDM, - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO -}; - -static struct dvb_frontend_info tda10046h_info = { - .name = "Philips TDA10046H", - .type = FE_OFDM, - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO -}; - -struct tda1004x_state { - u8 tda1004x_address; - u8 tuner_address; - u8 initialised; - u8 tuner_type; - u8 fe_type; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; - - int dspCodeCounterReg; - int dspCodeInReg; - int dspVersion; -}; - -static int tda1004x_write_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int data) +static int tda1004x_write_byteI(struct tda1004x_state *state, int reg, int data) { int ret; u8 buf[] = { reg, data }; @@ -182,8 +148,8 @@ dprintk("%s: reg=0x%x, data=0x%x\n", __FUNCTION__, reg, data); - msg.addr = tda_state->tda1004x_address; - ret = i2c_transfer(i2c, &msg, 1); + msg.addr = state->config->demod_address; + ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", @@ -194,7 +160,7 @@ return (ret != 1) ? -1 : 0; } -static int tda1004x_read_byte(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg) +static int tda1004x_read_byte(struct tda1004x_state *state, int reg) { int ret; u8 b0[] = { reg }; @@ -204,9 +170,9 @@ dprintk("%s: reg=0x%x\n", __FUNCTION__, reg); - msg[0].addr = tda_state->tda1004x_address; - msg[1].addr = tda_state->tda1004x_address; - ret = i2c_transfer(i2c, msg, 2); + msg[0].addr = state->config->demod_address; + msg[1].addr = state->config->demod_address; + ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) { dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg, @@ -219,14 +185,14 @@ return b1[0]; } -static int tda1004x_write_mask(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, int mask, int data) +static int tda1004x_write_mask(struct tda1004x_state *state, int reg, int mask, int data) { int val; dprintk("%s: reg=0x%x, mask=0x%x, data=0x%x\n", __FUNCTION__, reg, mask, data); // read a byte and check - val = tda1004x_read_byte(i2c, tda_state, reg); + val = tda1004x_read_byte(state, reg); if (val < 0) return val; @@ -235,10 +201,10 @@ val |= data & 0xff; // write it out again - return tda1004x_write_byte(i2c, tda_state, reg, val); + return tda1004x_write_byteI(state, reg, val); } -static int tda1004x_write_buf(struct i2c_adapter *i2c, struct tda1004x_state *tda_state, int reg, unsigned char *buf, int len) +static int tda1004x_write_buf(struct tda1004x_state *state, int reg, unsigned char *buf, int len) { int i; int result; @@ -247,7 +213,7 @@ result = 0; for (i = 0; i < len; i++) { - result = tda1004x_write_byte(i2c, tda_state, reg + i, buf[i]); + result = tda1004x_write_byteI(state, reg + i, buf[i]); if (result != 0) break; } @@ -255,25 +221,24 @@ return result; } -static int tda1004x_enable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state) +static int tda1004x_enable_tuner_i2c(struct tda1004x_state *state) { int result; dprintk("%s\n", __FUNCTION__); - result = tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 2); + result = tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 2); msleep(1); return result; } -static int tda1004x_disable_tuner_i2c(struct i2c_adapter *i2c, struct tda1004x_state *tda_state) +static int tda1004x_disable_tuner_i2c(struct tda1004x_state *state) { dprintk("%s\n", __FUNCTION__); - return tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 2, 0); + return tda1004x_write_mask(state, TDA1004X_CONFC4, 2, 0); } -static int tda10045h_set_bandwidth(struct i2c_adapter *i2c, - struct tda1004x_state *tda_state, +static int tda10045h_set_bandwidth(struct tda1004x_state *state, fe_bandwidth_t bandwidth) { static u8 bandwidth_6mhz[] = { 0x02, 0x00, 0x3d, 0x00, 0x60, 0x1e, 0xa7, 0x45, 0x4f }; @@ -282,31 +247,27 @@ switch (bandwidth) { case BANDWIDTH_6_MHZ: - tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14); - tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_6mhz, sizeof(bandwidth_6mhz)); break; case BANDWIDTH_7_MHZ: - tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x80); - tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_7mhz, sizeof(bandwidth_7mhz)); break; case BANDWIDTH_8_MHZ: - tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0x14); - tda1004x_write_buf(i2c, tda_state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); + tda1004x_write_buf(state, TDA10045H_CONFPLL_P, bandwidth_8mhz, sizeof(bandwidth_8mhz)); break; default: return -EINVAL; } - tda1004x_write_byte(i2c, tda_state, TDA10045H_IOFFSET, 0); + tda1004x_write_byteI(state, TDA10045H_IOFFSET, 0); return 0; } -static int tda10046h_set_bandwidth(struct i2c_adapter *i2c, - struct tda1004x_state *tda_state, +static int tda10046h_set_bandwidth(struct tda1004x_state *state, fe_bandwidth_t bandwidth) { static u8 bandwidth_6mhz[] = { 0x80, 0x15, 0xfe, 0xab, 0x8e }; @@ -315,18 +276,15 @@ switch (bandwidth) { case BANDWIDTH_6_MHZ: - tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); - tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0); + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz)); break; case BANDWIDTH_7_MHZ: - tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); - tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0); + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz)); break; case BANDWIDTH_8_MHZ: - tda1004x_write_buf(i2c, tda_state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); - tda1004x_write_byte(i2c, tda_state, TDA1004X_DSSPARE2, 0xFF); + tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz)); break; default: @@ -336,7 +294,9 @@ return 0; } -static int tda1004x_do_upload(struct i2c_adapter *i2c, struct tda1004x_state *state, unsigned char *mem, unsigned int len) +static int tda1004x_do_upload(struct tda1004x_state *state, + unsigned char *mem, unsigned int len, + u8 dspCodeCounterReg, u8 dspCodeInReg) { u8 buf[65]; struct i2c_msg fw_msg = {.addr = 0,.flags = 0,.buf = buf,.len = 0 }; @@ -344,10 +304,10 @@ int pos = 0; /* clear code counter */ - tda1004x_write_byte(i2c, state, state->dspCodeCounterReg, 0); - fw_msg.addr = state->tda1004x_address; + tda1004x_write_byteI(state, dspCodeCounterReg, 0); + fw_msg.addr = state->config->demod_address; - buf[0] = state->dspCodeInReg; + buf[0] = dspCodeInReg; while (pos != len) { // work out how much to send this time @@ -359,7 +319,7 @@ // send the chunk memcpy(buf + 1, mem + pos, tx_size); fw_msg.len = tx_size + 1; - if (i2c_transfer(i2c, &fw_msg, 1) != 1) { + if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) { printk("tda1004x: Error during firmware upload\n"); return -EIO; } @@ -370,18 +330,17 @@ return 0; } -static int tda1004x_check_upload_ok(struct i2c_adapter *i2c, struct tda1004x_state *state) +static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion) { u8 data1, data2; // check upload was OK - tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP - tda1004x_write_byte(i2c, state, TDA1004X_DSP_CMD, 0x67); + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP + tda1004x_write_byteI(state, TDA1004X_DSP_CMD, 0x67); - data1 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA1); - data2 = tda1004x_read_byte(i2c, state, TDA1004X_DSP_DATA2); - if (data1 != 0x67 || data2 != state->dspVersion) { - printk("tda1004x: firmware upload failed!\n"); + data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1); + data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2); + if (data1 != 0x67 || data2 != dspVersion) { return -EIO; } @@ -389,31 +348,34 @@ } -static int tda10045_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client) +static int tda10045_fwupload(struct dvb_frontend* fe) { + struct tda1004x_state* state = fe->demodulator_priv; int ret; const struct firmware *fw; + + /* don't re-upload unless necessary */ + if (tda1004x_check_upload_ok(state, 0x2c) == 0) return 0; + /* request the firmware, this will block until someone uploads it */ printk("tda1004x: waiting for firmware upload...\n"); - ret = request_firmware(&fw, TDA10045_DEFAULT_FIRMWARE, &client->dev); + ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE); if (ret) { printk("tda1004x: no firmware upload (timeout or file not found?)\n"); return ret; } - /* set some valid bandwith parameters before uploading */ - /* reset chip */ - tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 0x10, 0); - tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8); - tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 0); + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); msleep(10); /* set parameters */ - tda10045h_set_bandwidth(i2c, state, BANDWIDTH_8_MHZ); + tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ); - ret = tda1004x_do_upload(i2c, state, fw->data, fw->size); + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN); if (ret) return ret; @@ -421,49 +383,47 @@ /* DSPREADY doesn't seem to work on the TDA10045H */ msleep(100); - ret = tda1004x_check_upload_ok(i2c, state); - if (ret) - return ret; - - return 0; + return tda1004x_check_upload_ok(state, 0x2c); } -static int tda10046_fwupload(struct i2c_adapter *i2c, struct tda1004x_state *state, struct i2c_client *client) +static int tda10046_fwupload(struct dvb_frontend* fe) { + struct tda1004x_state* state = fe->demodulator_priv; unsigned long timeout; int ret; const struct firmware *fw; + /* don't re-upload unless necessary */ + if (tda1004x_check_upload_ok(state, 0x20) == 0) return 0; + /* request the firmware, this will block until someone uploads it */ printk("tda1004x: waiting for firmware upload...\n"); - ret = request_firmware(&fw, TDA10046_DEFAULT_FIRMWARE, &client->dev); + ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE); if (ret) { printk("tda1004x: no firmware upload (timeout or file not found?)\n"); return ret; } - /* set some valid bandwith parameters before uploading */ - /* reset chip */ - tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 1, 0); - tda1004x_write_mask(i2c, state, TDA10046H_CONF_TRISTATE1, 1, 0); + tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); + tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0); msleep(10); /* set parameters */ - tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL2, 10); - tda1004x_write_byte(i2c, state, TDA10046H_CONFPLL3, 0); - tda1004x_write_byte(i2c, state, TDA10046H_FREQ_OFFSET, 99); - tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_MSB, 0xd4); - tda1004x_write_byte(i2c, state, TDA10046H_FREQ_PHY2_LSB, 0x2c); - tda1004x_write_mask(i2c, state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST - ret = tda1004x_do_upload(i2c, state, fw->data, fw->size); + ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN); if (ret) return ret; /* wait for DSP to initialise */ timeout = jiffies + HZ; - while(!(tda1004x_read_byte(i2c, state, TDA1004X_STATUS_CD) & 0x20)) { + while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) { if (time_after(jiffies, timeout)) { printk("tda1004x: DSP failed to initialised.\n"); return -EIO; @@ -471,95 +431,7 @@ msleep(1); } - ret = tda1004x_check_upload_ok(i2c, state); - if (ret) - return ret; - - return 0; -} - -static int tda10045h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state) -{ - struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 }; - static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - - dprintk("%s\n", __FUNCTION__); - - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC - - // Disable the MC44BC374C - tda1004x_enable_tuner_i2c(i2c, tda_state); - tuner_msg.addr = MC44BC374_ADDRESS; - tuner_msg.buf = disable_mc44BC374c; - tuner_msg.len = sizeof(disable_mc44BC374c); - if (i2c_transfer(i2c, &tuner_msg, 1) != 1) { - i2c_transfer(i2c, &tuner_msg, 1); - } - tda1004x_disable_tuner_i2c(i2c, tda_state); - - // tda setup - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0); // no frequency inversion - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset - tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface - tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface - tda1004x_write_mask(i2c, tda_state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity - tda1004x_write_byte(i2c, tda_state, TDA1004X_CONFADC1, 0x2e); - - return 0; -} - -static int tda10046h_init(struct i2c_adapter *i2c, struct tda1004x_state *tda_state) -{ - struct i2c_msg tuner_msg = {.addr = 0,.flags = 0,.buf = NULL,.len = 0 }; - static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; - - dprintk("%s\n", __FUNCTION__); - - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 0); // wake up the chip - - // Disable the MC44BC374C - tda1004x_enable_tuner_i2c(i2c, tda_state); - tuner_msg.addr = MC44BC374_ADDRESS; - tuner_msg.buf = disable_mc44BC374c; - tuner_msg.len = sizeof(disable_mc44BC374c); - if (i2c_transfer(i2c, &tuner_msg, 1) != 1) { - i2c_transfer(i2c, &tuner_msg, 1); - } - tda1004x_disable_tuner_i2c(i2c, tda_state); - - // tda setup - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x40, 0x40); // TT TDA10046H needs inversion ON - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 8, 0); // select HP stream - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer - tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL2, 10); // PLL M = 10 - tda1004x_write_byte(i2c, tda_state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 - tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99 - tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221 - tda1004x_write_byte(i2c, tda_state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // } - tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_CONF, 0); // AGC setup - tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities - tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MIN, 0); // } - tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values - tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MIN, 0); // } - tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_IF_MAX, 0xff); // } - tda1004x_write_mask(i2c, tda_state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits - tda1004x_write_byte(i2c, tda_state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm - tda1004x_write_byte(i2c, tda_state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config - tda1004x_write_mask(i2c, tda_state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN - tda1004x_write_byte(i2c, tda_state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup - tda1004x_write_byte(i2c, tda_state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config - tda1004x_write_mask(i2c, tda_state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select - tda10046h_set_bandwidth(i2c, tda_state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz - - return 0; + return tda1004x_check_upload_ok(state, 0x20); } static int tda1004x_encode_fec(int fec) @@ -602,174 +474,147 @@ return -1; } -static int tda1004x_set_frequency(struct i2c_adapter *i2c, - struct tda1004x_state *tda_state, - struct dvb_frontend_parameters *fe_params) -{ - u8 tuner_buf[4]; - struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; - int tuner_frequency = 0; - u8 band, cp, filter; - int counter, counter2; - dprintk("%s\n", __FUNCTION__); - // setup the frequency buffer - switch (tda_state->tuner_type) { - case TUNER_TYPE_TD1344: - - // setup tuner buffer - // ((Fif+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = - (((fe_params->frequency / 1000) * 6) + 217502) / 1000; - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0x88; - if (fe_params->frequency < 550000000) { - tuner_buf[3] = 0xab; - } else { - tuner_buf[3] = 0xeb; - } - // tune it - tda1004x_enable_tuner_i2c(i2c, tda_state); - tuner_msg.addr = tda_state->tuner_address; - tuner_msg.len = 4; - i2c_transfer(i2c, &tuner_msg, 1); - - // wait for it to finish - tuner_msg.len = 1; - tuner_msg.flags = I2C_M_RD; - counter = 0; - counter2 = 0; - while (counter++ < 100) { - if (i2c_transfer(i2c, &tuner_msg, 1) == 1) { - if (tuner_buf[0] & 0x40) { - counter2++; - } else { - counter2 = 0; - } - } - - if (counter2 > 10) { - break; - } - } - tda1004x_disable_tuner_i2c(i2c, tda_state); - break; - case TUNER_TYPE_TD1316: - // determine charge pump - tuner_frequency = fe_params->frequency + 36130000; - if (tuner_frequency < 87000000) { - return -EINVAL; - } else if (tuner_frequency < 130000000) { - cp = 3; - } else if (tuner_frequency < 160000000) { - cp = 5; - } else if (tuner_frequency < 200000000) { - cp = 6; - } else if (tuner_frequency < 290000000) { - cp = 3; - } else if (tuner_frequency < 420000000) { - cp = 5; - } else if (tuner_frequency < 480000000) { - cp = 6; - } else if (tuner_frequency < 620000000) { - cp = 3; - } else if (tuner_frequency < 830000000) { - cp = 5; - } else if (tuner_frequency < 895000000) { - cp = 7; - } else { - return -EINVAL; - } - // determine band - if (fe_params->frequency < 49000000) { - return -EINVAL; - } else if (fe_params->frequency < 159000000) { - band = 1; - } else if (fe_params->frequency < 444000000) { - band = 2; - } else if (fe_params->frequency < 861000000) { - band = 4; - } else { - return -EINVAL; + + + + + + + + + + + + +int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data) +{ + struct tda1004x_state* state = fe->demodulator_priv; + + return tda1004x_write_byteI(state, reg, data); } - // work out filter - switch (fe_params->u.ofdm.bandwidth) { - case BANDWIDTH_6_MHZ: - filter = 0; - break; +static int tda10045_init(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; - case BANDWIDTH_7_MHZ: - filter = 0; - break; + dprintk("%s\n", __FUNCTION__); - case BANDWIDTH_8_MHZ: - filter = 1; - break; + if (state->initialised) return 0; - default: - return -EINVAL; + if (tda10045_fwupload(fe)) { + printk("tda1004x: firmware upload failed\n"); + return -EIO; } - // calculate divisor - // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) - tuner_frequency = - (((fe_params->frequency / 1000) * 6) + 217280) / 1000; - - // setup tuner buffer - tuner_buf[0] = tuner_frequency >> 8; - tuner_buf[1] = tuner_frequency & 0xff; - tuner_buf[2] = 0xca; - tuner_buf[3] = (cp << 5) | (filter << 3) | band; - - // tune it - if (tda_state->fe_type == FE_TYPE_TDA10046H) { - // setup auto offset - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x10, 0x10); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x80, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0xC0, 0); + tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC - // disable agc_conf[2] - tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 0); + // Init the PLL + if (state->config->pll_init) { + tda1004x_enable_tuner_i2c(state); + state->config->pll_init(fe); + tda1004x_disable_tuner_i2c(state); + } + + // tda setup + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer + tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0); // set polarity of VAGC signal + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0x80); // enable pulse killer + tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); // enable auto offset + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0x0); // no frequency offset + tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 0); // setup MPEG2 TS interface + tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0); // setup MPEG2 TS interface + tda1004x_write_mask(state, TDA1004X_VBER_MSB, 0xe0, 0xa0); // 10^6 VBER measurement bits + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x10, 0); // VAGC polarity + tda1004x_write_byteI(state, TDA1004X_CONFADC1, 0x2e); + + state->initialised = 1; + return 0; } - tda1004x_enable_tuner_i2c(i2c, tda_state); - tuner_msg.addr = tda_state->tuner_address; - tuner_msg.len = 4; - if (i2c_transfer(i2c, &tuner_msg, 1) != 1) { + +static int tda10046_init(struct dvb_frontend* fe) +{ + struct tda1004x_state* state = fe->demodulator_priv; + dprintk("%s\n", __FUNCTION__); + + if (state->initialised) return 0; + + if (tda10046_fwupload(fe)) { + printk("tda1004x: firmware upload failed\n"); return -EIO; } - msleep(1); - tda1004x_disable_tuner_i2c(i2c, tda_state); - if (tda_state->fe_type == FE_TYPE_TDA10046H) - tda1004x_write_mask(i2c, tda_state, TDA10046H_AGC_CONF, 4, 4); - break; - default: - return -EINVAL; + tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip + + // Init the PLL + if (state->config->pll_init) { + tda1004x_enable_tuner_i2c(state); + state->config->pll_init(fe); + tda1004x_disable_tuner_i2c(state); } - dprintk("%s: success\n", __FUNCTION__); + // tda setup + tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40); + tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 + tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 + tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99 + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221 + tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // } + tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup + tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities + tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // } + tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values + tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // } + tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // } + tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits + tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1 + tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm + tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config + tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config + tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN + tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup + tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config + tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select + tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz + state->initialised = 1; return 0; } -static int tda1004x_set_fe(struct i2c_adapter *i2c, - struct tda1004x_state *tda_state, +static int tda1004x_set_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) { + struct tda1004x_state* state = fe->demodulator_priv; int tmp; int inversion; dprintk("%s\n", __FUNCTION__); + if (state->demod_type == TDA1004X_DEMOD_TDA10046) { + // setup auto offset + tda1004x_write_mask(state, TDA1004X_AUTO, 0x10, 0x10); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0xC0, 0); + + // disable agc_conf[2] + tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 0); + } + // set frequency - if ((tmp = tda1004x_set_frequency(i2c, tda_state, fe_params)) < 0) - return tmp; + tda1004x_enable_tuner_i2c(state); + state->config->pll_set(fe, fe_params); + tda1004x_disable_tuner_i2c(state); + + if (state->demod_type == TDA1004X_DEMOD_TDA10046) + tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4); // Hardcoded to use auto as much as possible // The TDA10045 is very unreliable if AUTO mode is _not_ used. I have not @@ -783,35 +628,35 @@ (fe_params->u.ofdm.code_rate_LP == FEC_AUTO) || (fe_params->u.ofdm.constellation == QAM_AUTO) || (fe_params->u.ofdm.hierarchy_information == HIERARCHY_AUTO)) { - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 1); // enable auto - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits + tda1004x_write_mask(state, TDA1004X_AUTO, 1, 1); // enable auto + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x03, 0); // turn off constellation bits + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0); // turn off hierarchy bits + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x3f, 0); // turn off FEC bits } else { - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 1, 0); // disable auto + tda1004x_write_mask(state, TDA1004X_AUTO, 1, 0); // disable auto // set HP FEC tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_HP); if (tmp < 0) return tmp; - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 7, tmp); + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 7, tmp); // set LP FEC tmp = tda1004x_encode_fec(fe_params->u.ofdm.code_rate_LP); if (tmp < 0) return tmp; - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF2, 0x38, tmp << 3); + tda1004x_write_mask(state, TDA1004X_IN_CONF2, 0x38, tmp << 3); // set constellation switch (fe_params->u.ofdm.constellation) { case QPSK: - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 0); break; case QAM_16: - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 1); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 1); break; case QAM_64: - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 3, 2); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 3, 2); break; default: @@ -821,19 +666,19 @@ // set hierarchy switch (fe_params->u.ofdm.hierarchy_information) { case HIERARCHY_NONE: - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 0 << 5); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 0 << 5); break; case HIERARCHY_1: - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 1 << 5); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 1 << 5); break; case HIERARCHY_2: - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 2 << 5); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 2 << 5); break; case HIERARCHY_4: - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x60, 3 << 5); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x60, 3 << 5); break; default: @@ -842,30 +687,26 @@ } // set bandwidth - switch(tda_state->fe_type) { - case FE_TYPE_TDA10045H: - tda10045h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth); + switch(state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda10045h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); break; - case FE_TYPE_TDA10046H: - tda10046h_set_bandwidth(i2c, tda_state, fe_params->u.ofdm.bandwidth); + case TDA1004X_DEMOD_TDA10046: + tda10046h_set_bandwidth(state, fe_params->u.ofdm.bandwidth); break; } - // need to invert the inversion for TT TDA10046H - inversion = fe_params->inversion; - if (tda_state->fe_type == FE_TYPE_TDA10046H) { - inversion = inversion ? INVERSION_OFF : INVERSION_ON; - } - // set inversion + inversion = fe_params->inversion; + if (state->config->invert) inversion = inversion ? INVERSION_OFF : INVERSION_ON; switch (inversion) { case INVERSION_OFF: - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0); + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0); break; case INVERSION_ON: - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC1, 0x20, 0x20); + tda1004x_write_mask(state, TDA1004X_CONFC1, 0x20, 0x20); break; default: @@ -875,28 +716,28 @@ // set guard interval switch (fe_params->u.ofdm.guard_interval) { case GUARD_INTERVAL_1_32: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); break; case GUARD_INTERVAL_1_16: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 1 << 2); break; case GUARD_INTERVAL_1_8: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 2 << 2); break; case GUARD_INTERVAL_1_4: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 3 << 2); break; case GUARD_INTERVAL_AUTO: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 2, 2); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); + tda1004x_write_mask(state, TDA1004X_AUTO, 2, 2); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x0c, 0 << 2); break; default: @@ -906,18 +747,18 @@ // set transmission mode switch (fe_params->u.ofdm.transmission_mode) { case TRANSMISSION_MODE_2K: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0 << 4); + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0 << 4); break; case TRANSMISSION_MODE_8K: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 1 << 4); + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 0); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 1 << 4); break; case TRANSMISSION_MODE_AUTO: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 4, 4); - tda1004x_write_mask(i2c, tda_state, TDA1004X_IN_CONF1, 0x10, 0); + tda1004x_write_mask(state, TDA1004X_AUTO, 4, 4); + tda1004x_write_mask(state, TDA1004X_IN_CONF1, 0x10, 0); break; default: @@ -925,15 +766,15 @@ } // start the lock - switch(tda_state->fe_type) { - case FE_TYPE_TDA10045H: - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 8); - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 8, 0); + switch(state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); + tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 0); msleep(10); break; - case FE_TYPE_TDA10046H: - tda1004x_write_mask(i2c, tda_state, TDA1004X_AUTO, 0x40, 0x40); + case TDA1004X_DEMOD_TDA10046: + tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); msleep(10); break; } @@ -941,25 +782,22 @@ return 0; } -static int tda1004x_get_fe(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, struct dvb_frontend_parameters *fe_params) +static int tda1004x_get_fe(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params) { + struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __FUNCTION__); // inversion status fe_params->inversion = INVERSION_OFF; - if (tda1004x_read_byte(i2c, tda_state, TDA1004X_CONFC1) & 0x20) { + if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) { fe_params->inversion = INVERSION_ON; } - - // need to invert the inversion for TT TDA10046H - if (tda_state->fe_type == FE_TYPE_TDA10046H) { - fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; - } + if (state->config->invert) fe_params->inversion = fe_params->inversion ? INVERSION_OFF : INVERSION_ON; // bandwidth - switch(tda_state->fe_type) { - case FE_TYPE_TDA10045H: - switch (tda1004x_read_byte(i2c, tda_state, TDA10045H_WREF_LSB)) { + switch(state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + switch (tda1004x_read_byte(state, TDA10045H_WREF_LSB)) { case 0x14: fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break; @@ -972,8 +810,8 @@ } break; - case FE_TYPE_TDA10046H: - switch (tda1004x_read_byte(i2c, tda_state, TDA10046H_TIME_WREF1)) { + case TDA1004X_DEMOD_TDA10046: + switch (tda1004x_read_byte(state, TDA10046H_TIME_WREF1)) { case 0x60: fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; break; @@ -989,12 +827,12 @@ // FEC fe_params->u.ofdm.code_rate_HP = - tda1004x_decode_fec(tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) & 7); + tda1004x_decode_fec(tda1004x_read_byte(state, TDA1004X_OUT_CONF2) & 7); fe_params->u.ofdm.code_rate_LP = - tda1004x_decode_fec((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF2) >> 3) & 7); + tda1004x_decode_fec((tda1004x_read_byte(state, TDA1004X_OUT_CONF2) >> 3) & 7); // constellation - switch (tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 3) { + switch (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 3) { case 0: fe_params->u.ofdm.constellation = QPSK; break; @@ -1008,12 +846,12 @@ // transmission mode fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; - if (tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x10) { + if (tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x10) { fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; } // guard interval - switch ((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { + switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x0c) >> 2) { case 0: fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; @@ -1029,7 +867,7 @@ } // hierarchy - switch ((tda1004x_read_byte(i2c, tda_state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { + switch ((tda1004x_read_byte(state, TDA1004X_OUT_CONF1) & 0x60) >> 5) { case 0: fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE; break; @@ -1047,8 +885,9 @@ return 0; } -static int tda1004x_read_status(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, fe_status_t * fe_status) +static int tda1004x_read_status(struct dvb_frontend* fe, fe_status_t * fe_status) { + struct tda1004x_state* state = fe->demodulator_priv; int status; int cber; int vber; @@ -1056,7 +895,7 @@ dprintk("%s\n", __FUNCTION__); // read status - status = tda1004x_read_byte(i2c, tda_state, TDA1004X_STATUS_CD); + status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); if (status == -1) { return -EIO; } @@ -1071,12 +910,12 @@ // is getting anything valid if (!(*fe_status & FE_HAS_VITERBI)) { // read the CBER - cber = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB); + cber = tda1004x_read_byte(state, TDA1004X_CBER_LSB); if (cber == -1) return -EIO; - status = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB); + status = tda1004x_read_byte(state, TDA1004X_CBER_MSB); if (status == -1) return -EIO; cber |= (status << 8); - tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET); + tda1004x_read_byte(state, TDA1004X_CBER_RESET); if (cber != 65535) { *fe_status |= FE_HAS_VITERBI; @@ -1087,15 +926,15 @@ // bytes (i.e. not LOCKED), see if the RS decoder is getting anything valid. if ((*fe_status & FE_HAS_VITERBI) && (!(*fe_status & FE_HAS_SYNC))) { // read the VBER - vber = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_LSB); + vber = tda1004x_read_byte(state, TDA1004X_VBER_LSB); if (vber == -1) return -EIO; - status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MID); + status = tda1004x_read_byte(state, TDA1004X_VBER_MID); if (status == -1) return -EIO; vber |= (status << 8); - status = tda1004x_read_byte(i2c, tda_state, TDA1004X_VBER_MSB); + status = tda1004x_read_byte(state, TDA1004X_VBER_MSB); if (status == -1) return -EIO; vber |= ((status << 16) & 0x0f); - tda1004x_read_byte(i2c, tda_state, TDA1004X_CVBER_LUT); + tda1004x_read_byte(state, TDA1004X_CVBER_LUT); // if RS has passed some valid TS packets, then we must be // getting some SYNC bytes @@ -1109,26 +948,27 @@ return 0; } -static int tda1004x_read_signal_strength(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * signal) +static int tda1004x_read_signal_strength(struct dvb_frontend* fe, u16 * signal) { + struct tda1004x_state* state = fe->demodulator_priv; int tmp; int reg = 0; dprintk("%s\n", __FUNCTION__); // determine the register to use - switch(tda_state->fe_type) { - case FE_TYPE_TDA10045H: + switch(state->demod_type) { + case TDA1004X_DEMOD_TDA10045: reg = TDA10045H_S_AGC; break; - case FE_TYPE_TDA10046H: + case TDA1004X_DEMOD_TDA10046: reg = TDA10046H_AGC_IF_LEVEL; break; } // read it - tmp = tda1004x_read_byte(i2c, tda_state, reg); + tmp = tda1004x_read_byte(state, reg); if (tmp < 0) return -EIO; @@ -1137,14 +977,15 @@ return 0; } -static int tda1004x_read_snr(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u16 * snr) +static int tda1004x_read_snr(struct dvb_frontend* fe, u16 * snr) { + struct tda1004x_state* state = fe->demodulator_priv; int tmp; dprintk("%s\n", __FUNCTION__); // read it - tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_SNR); + tmp = tda1004x_read_byte(state, TDA1004X_SNR); if (tmp < 0) return -EIO; if (tmp) { @@ -1156,8 +997,9 @@ return 0; } -static int tda1004x_read_ucblocks(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ucblocks) +static int tda1004x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { + struct tda1004x_state* state = fe->demodulator_priv; int tmp; int tmp2; int counter; @@ -1166,16 +1008,16 @@ // read the UCBLOCKS and reset counter = 0; - tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR); + tmp = tda1004x_read_byte(state, TDA1004X_UNCOR); if (tmp < 0) return -EIO; tmp &= 0x7f; while (counter++ < 5) { - tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); - tda1004x_write_mask(i2c, tda_state, TDA1004X_UNCOR, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); + tda1004x_write_mask(state, TDA1004X_UNCOR, 0x80, 0); - tmp2 = tda1004x_read_byte(i2c, tda_state, TDA1004X_UNCOR); + tmp2 = tda1004x_read_byte(state, TDA1004X_UNCOR); if (tmp2 < 0) return -EIO; tmp2 &= 0x7f; @@ -1192,373 +1034,188 @@ return 0; } -static int tda1004x_read_ber(struct i2c_adapter *i2c, struct tda1004x_state* tda_state, u32* ber) +static int tda1004x_read_ber(struct dvb_frontend* fe, u32* ber) { + struct tda1004x_state* state = fe->demodulator_priv; int tmp; dprintk("%s\n", __FUNCTION__); // read it in - tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_LSB); + tmp = tda1004x_read_byte(state, TDA1004X_CBER_LSB); if (tmp < 0) return -EIO; *ber = tmp << 1; - tmp = tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_MSB); + tmp = tda1004x_read_byte(state, TDA1004X_CBER_MSB); if (tmp < 0) return -EIO; *ber |= (tmp << 9); - tda1004x_read_byte(i2c, tda_state, TDA1004X_CBER_RESET); + tda1004x_read_byte(state, TDA1004X_CBER_RESET); dprintk("%s: ber=0x%x\n", __FUNCTION__, *ber); return 0; } -static int tda1004x_sleep(struct i2c_adapter *i2c, struct tda1004x_state* tda_state) +static int tda1004x_sleep(struct dvb_frontend* fe) { - switch(tda_state->fe_type) { - case FE_TYPE_TDA10045H: - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFADC1, 0x10, 0x10); - break; - - case FE_TYPE_TDA10046H: - tda1004x_write_mask(i2c, tda_state, TDA1004X_CONFC4, 1, 1); - break; - } + struct tda1004x_state* state = fe->demodulator_priv; - return 0; -} - -static int tda1004x_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct tda1004x_state *tda_state = (struct tda1004x_state *) fe->data; - struct i2c_adapter *i2c = tda_state->i2c; - int status = 0; - - dprintk("%s: cmd=0x%x\n", __FUNCTION__, cmd); - - switch (cmd) { - case FE_GET_INFO: - switch(tda_state->fe_type) { - case FE_TYPE_TDA10045H: - memcpy(arg, &tda10045h_info, sizeof(struct dvb_frontend_info)); + switch(state->demod_type) { + case TDA1004X_DEMOD_TDA10045: + tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0x10); break; - case FE_TYPE_TDA10046H: - memcpy(arg, &tda10046h_info, sizeof(struct dvb_frontend_info)); + case TDA1004X_DEMOD_TDA10046: + tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } - break; - - case FE_READ_STATUS: - return tda1004x_read_status(i2c, tda_state, (fe_status_t *) arg); - - case FE_READ_BER: - return tda1004x_read_ber(i2c, tda_state, (u32 *) arg); - - case FE_READ_SIGNAL_STRENGTH: - return tda1004x_read_signal_strength(i2c, tda_state, (u16 *) arg); - - case FE_READ_SNR: - return tda1004x_read_snr(i2c, tda_state, (u16 *) arg); - - case FE_READ_UNCORRECTED_BLOCKS: - return tda1004x_read_ucblocks(i2c, tda_state, (u32 *) arg); - - case FE_SET_FRONTEND: - return tda1004x_set_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg); - - case FE_GET_FRONTEND: - return tda1004x_get_fe(i2c, tda_state, (struct dvb_frontend_parameters*) arg); - - case FE_SLEEP: - tda_state->initialised = 0; - return tda1004x_sleep(i2c, tda_state); - - case FE_INIT: + state->initialised = 0; - // don't bother reinitialising - if (tda_state->initialised) return 0; - - // OK, perform initialisation - switch(tda_state->fe_type) { - case FE_TYPE_TDA10045H: - status = tda10045h_init(i2c, tda_state); - break; - - case FE_TYPE_TDA10046H: - status = tda10046h_init(i2c, tda_state); - break; } - if (status == 0) - tda_state->initialised = 1; - return status; - case FE_GET_TUNE_SETTINGS: +static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - struct dvb_frontend_tune_settings* fesettings = (struct dvb_frontend_tune_settings*) arg; fesettings->min_delay_ms = 800; fesettings->step_size = 166667; fesettings->max_drift = 166667*2; return 0; } - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static int tda1004x_attach(struct i2c_adapter *i2c, struct tda1004x_state* state) +static void tda1004x_release(struct dvb_frontend* fe) { - int tda1004x_address = -1; - int tuner_address = -1; - int fe_type = -1; - int tuner_type = -1; - struct i2c_msg tuner_msg = {.addr=0, .flags=0, .buf=NULL, .len=0 }; - static u8 td1344_init[] = { 0x0b, 0xf5, 0x88, 0xab }; - static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; - static u8 td1316_init_tda10046h[] = { 0x0b, 0xf5, 0x80, 0xab }; - - dprintk("%s\n", __FUNCTION__); - - // probe for tda10045h - if (tda1004x_address == -1) { - state->tda1004x_address = 0x08; - if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x25) { - tda1004x_address = 0x08; - fe_type = FE_TYPE_TDA10045H; - printk("tda1004x: Detected Philips TDA10045H.\n"); - } - } - - // probe for tda10046h - if (tda1004x_address == -1) { - state->tda1004x_address = 0x08; - if (tda1004x_read_byte(i2c, state, TDA1004X_CHIPID) == 0x46) { - tda1004x_address = 0x08; - fe_type = FE_TYPE_TDA10046H; - printk("tda1004x: Detected Philips TDA10046H.\n"); - } - } - - // did we find a frontend? - if (tda1004x_address == -1) { - return -ENODEV; - } - - // enable access to the tuner - tda1004x_enable_tuner_i2c(i2c, state); - - // check for a TD1344 first - if (tuner_address == -1) { - tuner_msg.addr = 0x61; - tuner_msg.buf = td1344_init; - tuner_msg.len = sizeof(td1344_init); - if (i2c_transfer(i2c, &tuner_msg, 1) == 1) { - msleep(1); - tuner_address = 0x61; - tuner_type = TUNER_TYPE_TD1344; - printk("tda1004x: Detected Philips TD1344 tuner.\n"); - } - } - - // OK, try a TD1316 on address 0x63 - if (tuner_address == -1) { - tuner_msg.addr = 0x63; - tuner_msg.buf = td1316_init; - tuner_msg.len = sizeof(td1316_init); - if (i2c_transfer(i2c, &tuner_msg, 1) == 1) { - msleep(1); - tuner_address = 0x63; - tuner_type = TUNER_TYPE_TD1316; - printk("tda1004x: Detected Philips TD1316 tuner.\n"); - } - } - - // OK, TD1316 again, on address 0x60 (TDA10046H) - if (tuner_address == -1) { - tuner_msg.addr = 0x60; - tuner_msg.buf = td1316_init_tda10046h; - tuner_msg.len = sizeof(td1316_init_tda10046h); - if (i2c_transfer(i2c, &tuner_msg, 1) == 1) { - msleep(1); - tuner_address = 0x60; - tuner_type = TUNER_TYPE_TD1316; - printk("tda1004x: Detected Philips TD1316 tuner.\n"); - } - } - tda1004x_disable_tuner_i2c(i2c, state); - - // did we find a tuner? - if (tuner_address == -1) { - printk("tda1004x: Detected, but with unknown tuner.\n"); - return -ENODEV; + struct tda1004x_state* state = (struct tda1004x_state*) fe->demodulator_priv; + kfree(state); } - // create state - state->tda1004x_address = tda1004x_address; - state->fe_type = fe_type; - state->tuner_address = tuner_address; - state->tuner_type = tuner_type; - state->initialised = 0; - - return 0; -} - -static struct i2c_client client_template; +static struct dvb_frontend_ops tda10045_ops; -static int attach_adapter(struct i2c_adapter *adapter) +struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) { - struct i2c_client *client; - struct tda1004x_state *state; - int ret; + struct tda1004x_state* state = NULL; - dprintk ("%s\n", __FUNCTION__); - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - return -ENOMEM; - } + /* allocate memory for the internal state */ + state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (state == NULL) goto error; - if (NULL == (state = kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL))) { - kfree(client); - return -ENOMEM; - } - state->i2c = adapter; - - ret = tda1004x_attach(adapter, state); - if (ret) { - kfree(state); - kfree(client); - return -ENODEV; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = state->tda1004x_address; - i2c_set_clientdata(client, (void*)state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(state); - return ret; - } - - // upload firmware - BUG_ON(!state->dvb); - - switch(state->fe_type) { - case FE_TYPE_TDA10045H: - state->dspCodeCounterReg = TDA10045H_FWPAGE; - state->dspCodeInReg = TDA10045H_CODE_IN; - state->dspVersion = 0x2c; - - ret = tda10045_fwupload(adapter, state, client); - if (ret) { - printk("tda1004x: firmware upload failed\n"); - goto out; - } + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + state->demod_type = TDA1004X_DEMOD_TDA10045; - ret = dvb_register_frontend(tda1004x_ioctl, state->dvb, - state, &tda10045h_info, - THIS_MODULE); - break; - case FE_TYPE_TDA10046H: - state->dspCodeCounterReg = TDA10046H_CODE_CPT; - state->dspCodeInReg = TDA10046H_CODE_IN; - state->dspVersion = 0x20; - - ret = tda10046_fwupload(adapter, state, client); - if (ret) { - printk("tda1004x: firmware upload failed\n"); - goto out; - } + /* check if the demod is there */ + if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x25) goto error; - ret = dvb_register_frontend(tda1004x_ioctl, state->dvb, - state, &tda10046h_info, - THIS_MODULE); - break; - default: - BUG_ON(1); - } + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; - if (ret) { - printk("tda1004x: registering frontend failed\n"); - goto out; +error: + if (state) kfree(state); + return NULL; } - return 0; -out: - i2c_detach_client(client); - kfree(client); - kfree(state); - return ret; -} - -static int detach_client(struct i2c_client *client) -{ - struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); +static struct dvb_frontend_ops tda10046_ops; - dvb_unregister_frontend (tda1004x_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} - -static int command (struct i2c_client *client, unsigned int cmd, void *arg) +struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c) { - struct tda1004x_state *state = (struct tda1004x_state*)i2c_get_clientdata(client); + struct tda1004x_state* state = NULL; - dprintk ("%s\n", __FUNCTION__); + /* allocate memory for the internal state */ + state = (struct tda1004x_state*) kmalloc(sizeof(struct tda1004x_state), GFP_KERNEL); + if (state == NULL) goto error; - switch (cmd) { - case FE_REGISTER: - state->dvb = (struct dvb_adapter*)arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + state->demod_type = TDA1004X_DEMOD_TDA10046; -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = FRONTEND_NAME, - .id = I2C_DRIVERID_DVBFE_TDA1004X, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; + /* check if the demod is there */ + if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) goto error; -static struct i2c_client client_template = { - .name = FRONTEND_NAME, - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; + } + +static struct dvb_frontend_ops tda10045_ops = { + + .info = { + .name = "Philips TDA10045H DVB-T", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = tda1004x_release, + + .init = tda10045_init, + .sleep = tda1004x_sleep, + + .set_frontend = tda1004x_set_fe, + .get_frontend = tda1004x_get_fe, + + .read_status = tda1004x_read_status, + .read_ber = tda1004x_read_ber, + .read_signal_strength = tda1004x_read_signal_strength, + .read_snr = tda1004x_read_snr, + .read_ucblocks = tda1004x_read_ucblocks, }; -static int __init init_tda1004x(void) -{ - return i2c_add_driver(&driver); -} +static struct dvb_frontend_ops tda10046_ops = { -static void __exit exit_tda1004x(void) -{ - if (i2c_del_driver(&driver)) - printk("tda1004x: driver deregistration failed\n"); -} + .info = { + .name = "Philips TDA10046H DVB-T", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = tda1004x_release, + + .init = tda10046_init, + .sleep = tda1004x_sleep, + + .set_frontend = tda1004x_set_fe, + .get_frontend = tda1004x_get_fe, + .get_tune_settings = tda1004x_get_tune_settings, + + .read_status = tda1004x_read_status, + .read_ber = tda1004x_read_ber, + .read_signal_strength = tda1004x_read_signal_strength, + .read_snr = tda1004x_read_snr, + .read_ucblocks = tda1004x_read_ucblocks, +}; -module_init(init_tda1004x); -module_exit(exit_tda1004x); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); -MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Frontend"); +MODULE_DESCRIPTION("Philips TDA10045H & TDA10046H DVB-T Demodulator"); MODULE_AUTHOR("Andrew de Quincey & Robert Schlabbach"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(tda10045_attach); +EXPORT_SYMBOL(tda10046_attach); +EXPORT_SYMBOL(tda1004x_write_byte); diff -Nru a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/tda1004x.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,53 @@ + /* + Driver for Philips tda1004xh OFDM Frontend + + (c) 2004 Andrew de Quincey + + 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 TDA1004X_H +#define TDA1004X_H + +#include +#include + +struct tda1004x_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* does the "inversion" need inverted? */ + u8 invert:1; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c); + +extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, + struct i2c_adapter* i2c); + +extern int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data); + +#endif // TDA1004X_H diff -Nru a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/tda8083.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,490 @@ +/* + Driver for Philips TDA8083 based QPSK Demodulator + + Copyright (C) 2001 Convergence Integrated Media GmbH + + written by Ralph Metzler + + adoption to the new DVB frontend API and diagnostic ioctl's + by Holger Waechtler + + 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 "tda8083.h" + + +struct tda8083_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct tda8083_config* config; + + struct dvb_frontend frontend; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "tda8083: " args); \ + } while (0) + + +static u8 tda8083_init_tab [] = { + 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea, + 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10, + 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8, + 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00, + 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + + +static int tda8083_writereg (struct tda8083_state* state, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk ("%s: writereg error (reg %02x, ret == %i)\n", + __FUNCTION__, reg, ret); + + return (ret != 1) ? -1 : 0; +} + + +static int tda8083_readregs (struct tda8083_state* state, u8 reg1, u8 *b, u8 len) +{ + int ret; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®1, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = len } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + dprintk ("%s: readreg error (reg %02x, ret == %i)\n", + __FUNCTION__, reg1, ret); + + return ret == 2 ? 0 : -1; +} + + +static inline u8 tda8083_readreg (struct tda8083_state* state, u8 reg) +{ + u8 val; + + tda8083_readregs (state, reg, &val, 1); + + return val; +} + + + +static int tda8083_set_inversion (struct tda8083_state* state, fe_spectral_inversion_t inversion) +{ + /* XXX FIXME: implement other modes than FEC_AUTO */ + if (inversion == INVERSION_AUTO) + return 0; + + return -EINVAL; +} + + +static int tda8083_set_fec (struct tda8083_state* state, fe_code_rate_t fec) +{ + if (fec == FEC_AUTO) + return tda8083_writereg (state, 0x07, 0xff); + + if (fec >= FEC_1_2 && fec <= FEC_8_9) + return tda8083_writereg (state, 0x07, 1 << (FEC_8_9 - fec)); + + return -EINVAL; +} + + +static fe_code_rate_t tda8083_get_fec (struct tda8083_state* state) +{ + u8 index; + static fe_code_rate_t fec_tab [] = { FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, + FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8 }; + + index = tda8083_readreg(state, 0x0e) & 0x07; + + return fec_tab [index]; +} + + +static int tda8083_set_symbolrate (struct tda8083_state* state, u32 srate) +{ + u32 ratio; + u32 tmp; + u8 filter; + + if (srate > 32000000) + srate = 32000000; + if (srate < 500000) + srate = 500000; + + filter = 0; + if (srate < 24000000) + filter = 2; + if (srate < 16000000) + filter = 3; + + tmp = 31250 << 16; + ratio = tmp / srate; + + tmp = (tmp % srate) << 8; + ratio = (ratio << 8) + tmp / srate; + + tmp = (tmp % srate) << 8; + ratio = (ratio << 8) + tmp / srate; + + dprintk("tda8083: ratio == %08x\n", (unsigned int) ratio); + + tda8083_writereg (state, 0x05, filter); + tda8083_writereg (state, 0x02, (ratio >> 16) & 0xff); + tda8083_writereg (state, 0x03, (ratio >> 8) & 0xff); + tda8083_writereg (state, 0x04, (ratio ) & 0xff); + + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 1; +} + + +static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) +{ + unsigned long start = jiffies; + + while (jiffies - start < timeout && + !(tda8083_readreg(state, 0x02) & 0x80)) + { + msleep(50); + }; +} + +static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) +{ + tda8083_writereg (state, 0x26, 0xf1); + + switch (tone) { + case SEC_TONE_OFF: + return tda8083_writereg (state, 0x29, 0x00); + case SEC_TONE_ON: + return tda8083_writereg (state, 0x29, 0x80); + default: + return -EINVAL; + }; +} + + +static int tda8083_set_voltage (struct tda8083_state* state, fe_sec_voltage_t voltage) +{ + switch (voltage) { + case SEC_VOLTAGE_13: + return tda8083_writereg (state, 0x20, 0x00); + case SEC_VOLTAGE_18: + return tda8083_writereg (state, 0x20, 0x11); + default: + return -EINVAL; + }; +} + +static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_cmd_t burst) +{ + switch (burst) { + case SEC_MINI_A: + tda8083_writereg (state, 0x29, (5 << 2)); /* send burst A */ + break; + case SEC_MINI_B: + tda8083_writereg (state, 0x29, (7 << 2)); /* send B */ + break; + default: + return -EINVAL; + }; + + tda8083_wait_diseqc_fifo (state, 100); + + return 0; +} + + + + + + + + + + + + + + + + + + + + + + +static int tda8083_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + int i; + + tda8083_writereg (state, 0x29, (m->msg_len - 3) | (1 << 2)); /* enable */ + + for (i=0; imsg_len; i++) + tda8083_writereg (state, 0x23 + i, m->msg[i]); + + tda8083_writereg (state, 0x29, (m->msg_len - 3) | (3 << 2)); /* send!! */ + + tda8083_wait_diseqc_fifo (state, 100); + + return 0; +} + +static int tda8083_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + u8 signal = ~tda8083_readreg (state, 0x01); + u8 sync = tda8083_readreg (state, 0x02); + + *status = 0; + + if (signal > 10) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x01) + *status |= FE_HAS_CARRIER; + + if (sync & 0x02) + *status |= FE_HAS_VITERBI; + + if (sync & 0x10) + *status |= FE_HAS_SYNC; + + if ((sync & 0x1f) == 0x1f) + *status |= FE_HAS_LOCK; + + return 0; +} + +static int tda8083_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + u8 signal = ~tda8083_readreg (state, 0x01); + *strength = (signal << 8) | signal; + + return 0; +} + +static int tda8083_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + u8 _snr = tda8083_readreg (state, 0x08); + *snr = (_snr << 8) | _snr; + + return 0; +} + +static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + state->config->pll_set(fe, p); + tda8083_set_inversion (state, p->inversion); + tda8083_set_fec (state, p->u.qpsk.fec_inner); + tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate); + + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + /* FIXME: get symbolrate & frequency offset...*/ + /*p->frequency = ???;*/ + p->inversion = (tda8083_readreg (state, 0x0e) & 0x80) ? + INVERSION_ON : INVERSION_OFF; + p->u.qpsk.fec_inner = tda8083_get_fec (state); + /*p->u.qpsk.symbol_rate = tda8083_get_symbolrate (state);*/ + + return 0; +} + +static int tda8083_sleep(struct dvb_frontend* fe) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + tda8083_writereg (state, 0x00, 0x02); + return 0; +} + +static int tda8083_init(struct dvb_frontend* fe) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + int i; + + for (i=0; i<44; i++) + tda8083_writereg (state, i, tda8083_init_tab[i]); + + if (state->config->pll_init) state->config->pll_init(fe); + + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + tda8083_send_diseqc_burst (state, burst); + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_diseqc_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + tda8083_set_tone (state, tone); + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static int tda8083_diseqc_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + + tda8083_set_voltage (state, voltage); + tda8083_writereg (state, 0x00, 0x3c); + tda8083_writereg (state, 0x00, 0x04); + + return 0; +} + +static void tda8083_release(struct dvb_frontend* fe) +{ + struct tda8083_state* state = (struct tda8083_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops tda8083_ops; + +struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, + struct i2c_adapter* i2c) +{ + struct tda8083_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct tda8083_state*) kmalloc(sizeof(struct tda8083_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops)); + + /* check if the demod is there */ + if ((tda8083_readreg(state, 0x00)) != 0x05) goto error; + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops tda8083_ops = { + + .info = { + .name = "Philips TDA8083 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, /* FIXME: guessed! */ + .frequency_max = 1400000, /* FIXME: guessed! */ + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + /* .frequency_tolerance = ???,*/ + .symbol_rate_min = 1000000, /* FIXME: guessed! */ + .symbol_rate_max = 45000000, /* FIXME: guessed! */ + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_MUTE_TS + }, + + .release = tda8083_release, + + .init = tda8083_init, + .sleep = tda8083_sleep, + + .set_frontend = tda8083_set_frontend, + .get_frontend = tda8083_get_frontend, + + .read_status = tda8083_read_status, + .read_signal_strength = tda8083_read_signal_strength, + .read_snr = tda8083_read_snr, + + .diseqc_send_master_cmd = tda8083_send_diseqc_msg, + .diseqc_send_burst = tda8083_diseqc_send_burst, + .set_tone = tda8083_diseqc_set_tone, + .set_voltage = tda8083_diseqc_set_voltage, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Philips TDA8083 DVB-S Demodulator"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda8083_attach); diff -Nru a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/tda8083.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,45 @@ +/* + Driver for Grundig 29504-491, a Philips TDA8083 based QPSK Frontend + + Copyright (C) 2001 Convergence Integrated Media GmbH + + written by Ralph Metzler + + adoption to the new DVB frontend API and diagnostic ioctl's + by Holger Waechtler + + 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 TDA8083_H +#define TDA8083_H + +#include + +struct tda8083_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, + struct i2c_adapter* i2c); + +#endif // TDA8083_H diff -Nru a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/tda80xx.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,749 @@ +/* + * tda80xx.c + * + * Philips TDA8044 / TDA8083 QPSK demodulator driver + * + * Copyright (C) 2001 Felix Domke + * Copyright (C) 2002-2004 Andreas Oberritter + * + * 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 "dvb_frontend.h" +#include "tda80xx.h" + +enum { + ID_TDA8044 = 0x04, + ID_TDA8083 = 0x05, +}; + + +struct tda80xx_state { + + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct tda80xx_config* config; + + struct dvb_frontend frontend; + + u32 clk; + int afc_loop; + struct work_struct worklet; + fe_code_rate_t code_rate; + fe_spectral_inversion_t spectral_inversion; + fe_status_t status; + u8 id; +}; + +static int debug = 1; +#define dprintk if (debug) printk + +static u8 tda8044_inittab_pre[] = { + 0x02, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea, + 0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x58, + 0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68, + 0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x00, + 0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +static u8 tda8044_inittab_post[] = { + 0x04, 0x00, 0x6f, 0xb5, 0x86, 0x22, 0x00, 0xea, + 0x30, 0x42, 0x98, 0x68, 0x70, 0x42, 0x99, 0x50, + 0x95, 0x10, 0xf5, 0xe7, 0x93, 0x0b, 0x15, 0x68, + 0x9a, 0x90, 0x61, 0x80, 0x00, 0xe0, 0x40, 0x6c, + 0x0f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +static u8 tda8083_inittab[] = { + 0x04, 0x00, 0x4a, 0x79, 0x04, 0x00, 0xff, 0xea, + 0x48, 0x42, 0x79, 0x60, 0x70, 0x52, 0x9a, 0x10, + 0x0e, 0x10, 0xf2, 0xa7, 0x93, 0x0b, 0x05, 0xc8, + 0x9d, 0x00, 0x42, 0x80, 0x00, 0x60, 0x40, 0x00, + 0x00, 0x75, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static __inline__ u32 tda80xx_div(u32 a, u32 b) +{ + return (a + (b / 2)) / b; +} + +static __inline__ u32 tda80xx_gcd(u32 a, u32 b) +{ + u32 r; + + while ((r = a % b)) { + a = b; + b = r; + } + + return b; +} + +static int tda80xx_read(struct tda80xx_state* state, u8 reg, u8 *buf, u8 len) +{ + int ret; + struct i2c_msg msg[] = { { .addr = state->config->demod_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; + + ret = i2c_transfer(state->i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (reg %02x, ret == %i)\n", + __FUNCTION__, reg, ret); + + mdelay(10); + + return (ret == 2) ? 0 : -EREMOTEIO; +} + +static int tda80xx_write(struct tda80xx_state* state, u8 reg, const u8 *buf, u8 len) +{ + int ret; + u8 wbuf[len + 1]; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = wbuf, .len = len + 1 }; + + wbuf[0] = reg; + memcpy(&wbuf[1], buf, len); + + ret = i2c_transfer(state->i2c, &msg, 1); + + if (ret != 1) + dprintk("%s: i2c xfer error (ret == %i)\n", __FUNCTION__, ret); + + mdelay(10); + + return (ret == 1) ? 0 : -EREMOTEIO; +} + +static __inline__ u8 tda80xx_readreg(struct tda80xx_state* state, u8 reg) +{ + u8 val; + + tda80xx_read(state, reg, &val, 1); + + return val; +} + +static __inline__ int tda80xx_writereg(struct tda80xx_state* state, u8 reg, u8 data) +{ + return tda80xx_write(state, reg, &data, 1); +} + +static int tda80xx_set_parameters(struct tda80xx_state* state, + fe_spectral_inversion_t inversion, + u32 symbol_rate, + fe_code_rate_t fec_inner) +{ + u8 buf[15]; + u64 ratio; + u32 clk; + u32 k; + u32 sr = symbol_rate; + u32 gcd; + u8 scd; + + if (symbol_rate > (state->clk * 3) / 16) + scd = 0; + else if (symbol_rate > (state->clk * 3) / 32) + scd = 1; + else if (symbol_rate > (state->clk * 3) / 64) + scd = 2; + else + scd = 3; + + clk = scd ? (state->clk / (scd * 2)) : state->clk; + + /* + * Viterbi decoder: + * Differential decoding off + * Spectral inversion unknown + * QPSK modulation + */ + if (inversion == INVERSION_ON) + buf[0] = 0x60; + else if (inversion == INVERSION_OFF) + buf[0] = 0x20; + else + buf[0] = 0x00; + + /* + * CLK ratio: + * system clock frequency is up to 64 or 96 MHz + * + * formula: + * r = k * clk / symbol_rate + * + * k: 2^21 for caa 0..3, + * 2^20 for caa 4..5, + * 2^19 for caa 6..7 + */ + if (symbol_rate <= (clk * 3) / 32) + k = (1 << 19); + else if (symbol_rate <= (clk * 3) / 16) + k = (1 << 20); + else + k = (1 << 21); + + gcd = tda80xx_gcd(clk, sr); + clk /= gcd; + sr /= gcd; + + gcd = tda80xx_gcd(k, sr); + k /= gcd; + sr /= gcd; + + ratio = (u64)k * (u64)clk; + do_div(ratio, sr); + + buf[1] = ratio >> 16; + buf[2] = ratio >> 8; + buf[3] = ratio; + + /* nyquist filter roll-off factor 35% */ + buf[4] = 0x20; + + clk = scd ? (state->clk / (scd * 2)) : state->clk; + + /* Anti Alias Filter */ + if (symbol_rate < (clk * 3) / 64) + printk("tda80xx: unsupported symbol rate: %u\n", symbol_rate); + else if (symbol_rate <= clk / 16) + buf[4] |= 0x07; + else if (symbol_rate <= (clk * 3) / 32) + buf[4] |= 0x06; + else if (symbol_rate <= clk / 8) + buf[4] |= 0x05; + else if (symbol_rate <= (clk * 3) / 16) + buf[4] |= 0x04; + else if (symbol_rate <= clk / 4) + buf[4] |= 0x03; + else if (symbol_rate <= (clk * 3) / 8) + buf[4] |= 0x02; + else if (symbol_rate <= clk / 2) + buf[4] |= 0x01; + else + buf[4] |= 0x00; + + /* Sigma Delta converter */ + buf[5] = 0x00; + + /* FEC: Possible puncturing rates */ + if (fec_inner == FEC_NONE) + buf[6] = 0x00; + else if ((fec_inner >= FEC_1_2) && (fec_inner <= FEC_8_9)) + buf[6] = (1 << (8 - fec_inner)); + else if (fec_inner == FEC_AUTO) + buf[6] = 0xff; + else + return -EINVAL; + + /* carrier lock detector threshold value */ + buf[7] = 0x30; + /* AFC1: proportional part settings */ + buf[8] = 0x42; + /* AFC1: integral part settings */ + buf[9] = 0x98; + /* PD: Leaky integrator SCPC mode */ + buf[10] = 0x28; + /* AFC2, AFC1 controls */ + buf[11] = 0x30; + /* PD: proportional part settings */ + buf[12] = 0x42; + /* PD: integral part settings */ + buf[13] = 0x99; + /* AGC */ + buf[14] = 0x50 | scd; + + printk("symbol_rate=%u clk=%u\n", symbol_rate, clk); + + return tda80xx_write(state, 0x01, buf, sizeof(buf)); +} + +static int tda80xx_set_clk(struct tda80xx_state* state) +{ + u8 buf[2]; + + /* CLK proportional part */ + buf[0] = (0x06 << 5) | 0x08; /* CMP[2:0], CSP[4:0] */ + /* CLK integral part */ + buf[1] = (0x04 << 5) | 0x1a; /* CMI[2:0], CSI[4:0] */ + + return tda80xx_write(state, 0x17, buf, sizeof(buf)); +} + +#if 0 +static int tda80xx_set_scpc_freq_offset(struct tda80xx_state* state) +{ + /* a constant value is nonsense here imho */ + return tda80xx_writereg(state, 0x22, 0xf9); +} +#endif + +static int tda80xx_close_loop(struct tda80xx_state* state) +{ + u8 buf[2]; + + /* PD: Loop closed, LD: lock detect enable, SCPC: Sweep mode - AFC1 loop closed */ + buf[0] = 0x68; + /* AFC1: Loop closed, CAR Feedback: 8192 */ + buf[1] = 0x70; + + return tda80xx_write(state, 0x0b, buf, sizeof(buf)); +} + +static irqreturn_t tda80xx_irq(int irq, void *priv, struct pt_regs *pt) +{ + schedule_work(priv); + + return IRQ_HANDLED; +} + +static void tda80xx_read_status_int(struct tda80xx_state* state) +{ + u8 val; + + static const fe_spectral_inversion_t inv_tab[] = { + INVERSION_OFF, INVERSION_ON + }; + + static const fe_code_rate_t fec_tab[] = { + FEC_8_9, FEC_1_2, FEC_2_3, FEC_3_4, + FEC_4_5, FEC_5_6, FEC_6_7, FEC_7_8, + }; + + val = tda80xx_readreg(state, 0x02); + + state->status = 0; + + if (val & 0x01) /* demodulator lock */ + state->status |= FE_HAS_SIGNAL; + if (val & 0x02) /* clock recovery lock */ + state->status |= FE_HAS_CARRIER; + if (val & 0x04) /* viterbi lock */ + state->status |= FE_HAS_VITERBI; + if (val & 0x08) /* deinterleaver lock (packet sync) */ + state->status |= FE_HAS_SYNC; + if (val & 0x10) /* derandomizer lock (frame sync) */ + state->status |= FE_HAS_LOCK; + if (val & 0x20) /* frontend can not lock */ + state->status |= FE_TIMEDOUT; + + if ((state->status & (FE_HAS_CARRIER)) && (state->afc_loop)) { + printk("tda80xx: closing loop\n"); + tda80xx_close_loop(state); + state->afc_loop = 0; + } + + if (state->status & (FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK)) { + val = tda80xx_readreg(state, 0x0e); + state->code_rate = fec_tab[val & 0x07]; + if (state->status & (FE_HAS_SYNC | FE_HAS_LOCK)) + state->spectral_inversion = inv_tab[(val >> 7) & 0x01]; + else + state->spectral_inversion = INVERSION_AUTO; + } + else { + state->code_rate = FEC_AUTO; + } +} + +static void tda80xx_worklet(void *priv) +{ + struct tda80xx_state *state = priv; + + tda80xx_writereg(state, 0x00, 0x04); + enable_irq(state->config->irq); + + tda80xx_read_status_int(state); +} + +static void tda80xx_wait_diseqc_fifo(struct tda80xx_state* state) +{ + size_t i; + + for (i = 0; i < 100; i++) { + if (tda80xx_readreg(state, 0x02) & 0x80) + break; + msleep(10); + } +} + +static int tda8044_init(struct dvb_frontend* fe) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + int ret; + + /* + * this function is a mess... + */ + + if ((ret = tda80xx_write(state, 0x00, tda8044_inittab_pre, sizeof(tda8044_inittab_pre)))) + return ret; + + tda80xx_writereg(state, 0x0f, 0x50); +#if 1 + tda80xx_writereg(state, 0x20, 0x8F); /* FIXME */ + tda80xx_writereg(state, 0x20, state->config->volt18setting); /* FIXME */ + //tda80xx_writereg(state, 0x00, 0x04); + tda80xx_writereg(state, 0x00, 0x0C); +#endif + //tda80xx_writereg(state, 0x00, 0x08); /* Reset AFC1 loop filter */ + + tda80xx_write(state, 0x00, tda8044_inittab_post, sizeof(tda8044_inittab_post)); + + if (state->config->pll_init) { + tda80xx_writereg(state, 0x1c, 0x80); + state->config->pll_init(fe); + tda80xx_writereg(state, 0x1c, 0x00); + } + + return 0; +} + +static int tda8083_init(struct dvb_frontend* fe) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + tda80xx_write(state, 0x00, tda8083_inittab, sizeof(tda8083_inittab)); + + if (state->config->pll_init) { + tda80xx_writereg(state, 0x1c, 0x80); + state->config->pll_init(fe); + tda80xx_writereg(state, 0x1c, 0x00); + } + + return 0; +} + + + + + + + + + + + + + + + + +static int tda80xx_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + return tda80xx_writereg(state, 0x20, state->config->volt13setting); + case SEC_VOLTAGE_18: + return tda80xx_writereg(state, 0x20, state->config->volt18setting); + case SEC_VOLTAGE_OFF: + return tda80xx_writereg(state, 0x20, 0); + default: + return -EINVAL; + } +} + +static int tda80xx_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + switch (tone) { + case SEC_TONE_OFF: + return tda80xx_writereg(state, 0x29, 0x00); + case SEC_TONE_ON: + return tda80xx_writereg(state, 0x29, 0x80); + default: + return -EINVAL; + } +} + +static int tda80xx_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + if (cmd->msg_len > 6) + return -EINVAL; + + tda80xx_writereg(state, 0x29, 0x08 | (cmd->msg_len - 3)); + tda80xx_write(state, 0x23, cmd->msg, cmd->msg_len); + tda80xx_writereg(state, 0x29, 0x0c | (cmd->msg_len - 3)); + tda80xx_wait_diseqc_fifo(state); + + return 0; +} + +static int tda80xx_send_diseqc_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t cmd) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + switch (cmd) { + case SEC_MINI_A: + tda80xx_writereg(state, 0x29, 0x14); + break; + case SEC_MINI_B: + tda80xx_writereg(state, 0x29, 0x1c); + break; + default: + return -EINVAL; + } + + tda80xx_wait_diseqc_fifo(state); + + return 0; +} + +static int tda80xx_sleep(struct dvb_frontend* fe) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + tda80xx_writereg(state, 0x00, 0x02); /* enter standby */ + + return 0; +} + +static int tda80xx_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + tda80xx_writereg(state, 0x1c, 0x80); + state->config->pll_set(fe, p); + tda80xx_writereg(state, 0x1c, 0x00); + + tda80xx_set_parameters(state, p->inversion, p->u.qpsk.symbol_rate, p->u.qpsk.fec_inner); + tda80xx_set_clk(state); + //tda80xx_set_scpc_freq_offset(state); + state->afc_loop = 1; + + return 0; +} + +static int tda80xx_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + if (!state->config->irq) + tda80xx_read_status_int(state); + + p->inversion = state->spectral_inversion; + p->u.qpsk.fec_inner = state->code_rate; + + return 0; +} + +static int tda80xx_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + if (!state->config->irq) + tda80xx_read_status_int(state); + *status = state->status; + + return 0; +} + +static int tda80xx_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + int ret; + u8 buf[3]; + + if ((ret = tda80xx_read(state, 0x0b, buf, sizeof(buf)))) + return ret; + + *ber = ((buf[0] & 0x1f) << 16) | (buf[1] << 8) | buf[2]; + + return 0; +} + +static int tda80xx_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + u8 gain = ~tda80xx_readreg(state, 0x01); + *strength = (gain << 8) | gain; + + return 0; +} + +static int tda80xx_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + u8 quality = tda80xx_readreg(state, 0x08); + *snr = (quality << 8) | quality; + + return 0; +} + +static int tda80xx_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + *ucblocks = tda80xx_readreg(state, 0x0f); + if (*ucblocks == 0xff) + *ucblocks = 0xffffffff; + + return 0; +} + +static int tda80xx_init(struct dvb_frontend* fe) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + switch(state->id) { + case ID_TDA8044: + return tda8044_init(fe); + + case ID_TDA8083: + return tda8083_init(fe); + } + return 0; +} + +static void tda80xx_release(struct dvb_frontend* fe) +{ + struct tda80xx_state* state = (struct tda80xx_state*) fe->demodulator_priv; + + if (state->config->irq) + free_irq(state->config->irq, &state->worklet); + + kfree(state); +} + +static struct dvb_frontend_ops tda80xx_ops; + +struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config, + struct i2c_adapter* i2c) +{ + struct tda80xx_state* state = NULL; + int ret; + + /* allocate memory for the internal state */ + state = (struct tda80xx_state*) kmalloc(sizeof(struct tda80xx_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &tda80xx_ops, sizeof(struct dvb_frontend_ops)); + state->spectral_inversion = INVERSION_AUTO; + state->code_rate = FEC_AUTO; + state->status = 0; + state->afc_loop = 0; + + /* check if the demod is there */ + if (tda80xx_writereg(state, 0x89, 0x00) < 0) goto error; + state->id = tda80xx_readreg(state, 0x00); + + switch (state->id) { + case ID_TDA8044: + state->clk = 96000000; + printk("tda80xx: Detected tda8044\n"); + break; + + case ID_TDA8083: + state->clk = 64000000; + printk("tda80xx: Detected tda8083\n"); + break; + + default: + goto error; + } + + /* setup IRQ */ + if (state->config->irq) { + INIT_WORK(&state->worklet, tda80xx_worklet, state); + if ((ret = request_irq(state->config->irq, tda80xx_irq, SA_ONESHOT, "tda80xx", &state->worklet)) < 0) { + printk(KERN_ERR "tda80xx: request_irq failed (%d)\n", ret); + goto error; + } + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops tda80xx_ops = { + + .info = { + .name = "Philips TDA80xx DVB-S", + .type = FE_QPSK, + .frequency_min = 500000, + .frequency_max = 2700000, + .frequency_stepsize = 125, + .symbol_rate_min = 4500000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_MUTE_TS + }, + + .release = tda80xx_release, + + .init = tda80xx_init, + .sleep = tda80xx_sleep, + + .set_frontend = tda80xx_set_frontend, + .get_frontend = tda80xx_get_frontend, + + .read_status = tda80xx_read_status, + .read_ber = tda80xx_read_ber, + .read_signal_strength = tda80xx_read_signal_strength, + .read_snr = tda80xx_read_snr, + .read_ucblocks = tda80xx_read_ucblocks, + + .diseqc_send_master_cmd = tda80xx_send_diseqc_msg, + .diseqc_send_burst = tda80xx_send_diseqc_burst, + .set_tone = tda80xx_set_tone, + .set_voltage = tda80xx_set_voltage, +}; + +module_param(debug, int, 0644); + +MODULE_DESCRIPTION("Philips TDA8044 / TDA8083 DVB-S Demodulator driver"); +MODULE_AUTHOR("Felix Domke, Andreas Oberritter"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(tda80xx_attach); diff -Nru a/drivers/media/dvb/frontends/tda80xx.h b/drivers/media/dvb/frontends/tda80xx.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/tda80xx.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,51 @@ +/* + * tda80xx.c + * + * Philips TDA8044 / TDA8083 QPSK demodulator driver + * + * Copyright (C) 2001 Felix Domke + * Copyright (C) 2002-2004 Andreas Oberritter + * + * 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 TDA80XX_H +#define TDA80XX_H + +#include + +struct tda80xx_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* IRQ to use (0=>no IRQ used) */ + u32 irq; + + /* Register setting to use for 13v */ + u8 volt13setting; + + /* Register setting to use for 18v */ + u8 volt18setting; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* tda80xx_attach(const struct tda80xx_config* config, + struct i2c_adapter* i2c); + +#endif // TDA80XX_H diff -Nru a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c --- a/drivers/media/dvb/frontends/ves1820.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/ves1820.c 2004-12-12 17:40:52 -08:00 @@ -1,6 +1,5 @@ /* VES1820 - Single Chip Cable Channel Receiver driver module - used on the the Siemens DVB-C cards Copyright (C) 1999 Convergence Integrated Media GmbH @@ -27,70 +26,34 @@ #include #include #include +#include #include "dvb_frontend.h" +#include "ves1820.h" -/* I2C_DRIVERID_VES1820 is already defined in i2c-id.h */ -#if 0 -static int debug = 0; -#define dprintk if (debug) printk -#endif - -static int verbose; struct ves1820_state { - int pwm; - u8 reg0; - int tuner; - u8 demod_addr; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; -/* possible ves1820 adresses */ -static u8 addr[] = { 0x61, 0x62 }; + struct i2c_adapter *i2c; -#if defined(CONFIG_DBOX2) -#define XIN 69600000UL -#define DISABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0) -#define ENABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0) -#define HAS_INVERSION(reg0) (reg0 & 0x20) -#else /* PCI cards */ -#define XIN 57840000UL -#define DISABLE_INVERSION(reg0) do { reg0 |= 0x20; } while (0) -#define ENABLE_INVERSION(reg0) do { reg0 &= ~0x20; } while (0) -#define HAS_INVERSION(reg0) (!(reg0 & 0x20)) -#endif - -#define FIN (XIN >> 4) + struct dvb_frontend_ops ops; + /* configuration settings */ + const struct ves1820_config* config; + struct dvb_frontend frontend; -static struct dvb_frontend_info ves1820_info = { - .name = "VES1820 based DVB-C frontend", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */ - .symbol_rate_max = (XIN/2)/4, /* SACLK/4 */ -#if 0 - .frequency_tolerance = ???, - .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */ - .notifier_delay = ?, -#endif - .caps = FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_FEC_AUTO | - FE_CAN_INVERSION_AUTO, + /* private demodulator data */ + u8 reg0; + u8 pwm; }; + +static int verbose; + static u8 ves1820_inittab[] = { - 0x69, 0x6A, 0x9B, 0x12, 0x12, 0x46, 0x26, 0x1A, + 0x69, 0x6A, 0x93, 0x12, 0x12, 0x46, 0x26, 0x1A, 0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20, 0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, @@ -102,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) { u8 buf[] = { 0x00, reg, data }; - struct i2c_msg msg = {.addr = state->demod_addr,.flags = 0,.buf = buf,.len = 3 }; + struct i2c_msg msg = {.addr = state->config->demod_address,.flags = 0,.buf = buf,.len = 3 }; int ret; ret = i2c_transfer(state->i2c, &msg, 1); @@ -120,8 +83,8 @@ u8 b0 [] = { 0x00, reg }; u8 b1 [] = { 0 }; struct i2c_msg msg[] = { - {.addr = state->demod_addr,.flags = 0,.buf = b0,.len = 2}, - {.addr = state->demod_addr,.flags = I2C_M_RD,.buf = b1,.len = 1} + {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 2}, + {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} }; int ret; @@ -134,148 +97,88 @@ return b1[0]; } -static int tuner_write(struct ves1820_state *state, u8 addr, u8 data[4]) -{ - int ret; - struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 }; - - ret = i2c_transfer(state->i2c, &msg, 1); - - if (ret != 1) - printk("ves1820: %s(): i/o error (ret == %i)\n", __FUNCTION__, ret); - - return (ret != 1) ? -EREMOTEIO : 0; -} - - -/** - * set up the downconverter frequency divisor for a - * reference clock comparision frequency of 62.5 kHz. - */ -static int tuner_set_tv_freq(struct ves1820_state *state, u32 freq) -{ - u32 div, ifreq; - static u8 byte3 [] = { 0x8e, 0x85 }; - int tuner_type = state->tuner; - u8 buf [4]; - - if (tuner_type == 0xff) /* PLL not reachable over i2c ... */ - return 0; - - if (strstr(state->i2c->name, "Technotrend") - || strstr(state->i2c->name, "TT-Budget")) - ifreq = 35937500; - else - ifreq = 36125000; - - div = (freq + ifreq + 31250) / 62500; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = byte3[tuner_type]; - - if (tuner_type == 1) { - buf[2] |= (div >> 10) & 0x60; - buf[3] = (freq < 174000000 ? 0x88 : freq < 470000000 ? 0x84 : 0x81); - } else { - buf[3] = (freq < 174000000 ? 0xa1 : freq < 454000000 ? 0x92 : 0x34); - } - - return tuner_write(state, addr[tuner_type], buf); -} static int ves1820_setup_reg0(struct ves1820_state *state, u8 reg0, fe_spectral_inversion_t inversion) { reg0 |= state->reg0 & 0x62; - if (INVERSION_ON == inversion) - ENABLE_INVERSION(reg0); - else if (INVERSION_OFF == inversion) - DISABLE_INVERSION(reg0); + if (INVERSION_ON == inversion) { + if (!state->config->invert) reg0 |= 0x20; + else reg0 &= ~0x20; - ves1820_writereg(state, 0x00, reg0 & 0xfe); - ves1820_writereg(state, 0x00, reg0 | 0x01); + } else if (INVERSION_OFF == inversion) { + + if (!state->config->invert) reg0 &= ~0x20; + else reg0 |= 0x20; + } - /** - * check lock and toggle inversion bit if required... - */ - if (INVERSION_AUTO == inversion && !(ves1820_readreg(state, 0x11) & 0x08)) { - mdelay(50); - if (!(ves1820_readreg(state, 0x11) & 0x08)) { - reg0 ^= 0x20; ves1820_writereg(state, 0x00, reg0 & 0xfe); ves1820_writereg(state, 0x00, reg0 | 0x01); - } - } state->reg0 = reg0; return 0; } -static int ves1820_init(struct ves1820_state *state) -{ - int i; - - ves1820_writereg(state, 0, 0); - -#if defined(CONFIG_DBOX2) - ves1820_inittab[2] &= ~0x08; -#endif - - for (i=0; i<53; i++) - ves1820_writereg(state, i, ves1820_inittab[i]); - - ves1820_writereg(state, 0x34, state->pwm); - - return 0; -} - static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) { s32 BDR; s32 BDRI; s16 SFIL=0; u16 NDEC = 0; - u32 tmp, ratio; + u32 ratio; + u32 fin; + u32 tmp; + u64 fptmp; + u64 fpxin; - if (symbolrate > XIN/2) - symbolrate = XIN/2; + if (symbolrate > state->config->xin / 2) + symbolrate = state->config->xin / 2; if (symbolrate < 500000) symbolrate = 500000; - if (symbolrate < XIN / 16) + if (symbolrate < state->config->xin / 16) NDEC = 1; - if (symbolrate < XIN / 32) + if (symbolrate < state->config->xin / 32) NDEC = 2; - if (symbolrate < XIN / 64) + if (symbolrate < state->config->xin / 64) NDEC = 3; - if (symbolrate < (u32) (XIN / 12.3)) + /* yeuch! */ + fpxin = state->config->xin * 10; + fptmp = fpxin; do_div(fptmp, 123); + if (symbolrate < fptmp); SFIL = 1; - if (symbolrate < (u32) (XIN / 16)) + fptmp = fpxin; do_div(fptmp, 160); + if (symbolrate < fptmp); SFIL = 0; - if (symbolrate < (u32) (XIN / 24.6)) + fptmp = fpxin; do_div(fptmp, 246); + if (symbolrate < fptmp); SFIL = 1; - if (symbolrate < (u32) (XIN / 32)) + fptmp = fpxin; do_div(fptmp, 320); + if (symbolrate < fptmp); SFIL = 0; - if (symbolrate < (u32) (XIN / 49.2)) + fptmp = fpxin; do_div(fptmp, 492); + if (symbolrate < fptmp); SFIL = 1; - if (symbolrate < (u32) (XIN / 64)) + fptmp = fpxin; do_div(fptmp, 640); + if (symbolrate < fptmp); SFIL = 0; - if (symbolrate < (u32) (XIN / 98.4)) + fptmp = fpxin; do_div(fptmp, 984); + if (symbolrate < fptmp); SFIL = 1; + fin = state->config->xin >> 4; symbolrate <<= NDEC; - ratio = (symbolrate << 4) / FIN; - tmp = ((symbolrate << 4) % FIN) << 8; - ratio = (ratio << 8) + tmp / FIN; - tmp = (tmp % FIN) << 8; - ratio = (ratio << 8) + (tmp + FIN/2) / FIN; + ratio = (symbolrate << 4) / fin; + tmp = ((symbolrate << 4) % fin) << 8; + ratio = (ratio << 8) + tmp / fin; + tmp = (tmp % fin) << 8; + ratio = (ratio << 8) + (tmp + fin / 2) / fin; BDR = ratio; - BDRI = (((XIN << 5) / symbolrate) + 1) / 2; + BDRI = (((state->config->xin << 5) / symbolrate) + 1) / 2; if (BDRI > 0xFF) BDRI = 0xFF; @@ -295,8 +198,42 @@ return 0; } -static int ves1820_set_parameters(struct ves1820_state *state, struct dvb_frontend_parameters *p) + + + + + + + + + + + + +static int ves1820_init(struct dvb_frontend* fe) { + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + int i; + int val; + + ves1820_writereg(state, 0, 0); + + for (i = 0; i < 53; i++) { + val = ves1820_inittab[i]; + if ((i == 2) && (state->config->selagc)) val |= 0x08; + ves1820_writereg(state, i, val); + } + + ves1820_writereg(state, 0x34, state->pwm); + + if (state->config->pll_init) state->config->pll_init(fe); + + return 0; +} + +static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; static const u8 reg0x00 [] = { 0x00, 0x04, 0x08, 0x0c, 0x10 }; static const u8 reg0x01 [] = { 140, 140, 106, 100, 92 }; static const u8 reg0x05 [] = { 135, 100, 70, 54, 38 }; @@ -307,7 +244,7 @@ if (real_qam < 0 || real_qam > 4) return -EINVAL; - tuner_set_tv_freq(state, p->frequency); + state->config->pll_set(fe, p); ves1820_set_symbolrate(state, p->u.qam.symbol_rate); ves1820_writereg(state, 0x34, state->pwm); @@ -318,25 +255,12 @@ ves1820_setup_reg0(state, reg0x00[real_qam], p->inversion); - /* yes, this speeds things up: userspace reports lock in about 8 ms - instead of 500 to 1200 ms after calling FE_SET_FRONTEND. */ - mdelay(50); - return 0; } -static int ves1820_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int ves1820_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct ves1820_state *state = (struct ves1820_state *) fe->data; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &ves1820_info, sizeof(struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: - { - fe_status_t *status = (fe_status_t *) arg; + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; int sync; *status = 0; @@ -358,46 +282,59 @@ if (sync & 8) *status |= FE_HAS_LOCK; - break; + return 0; } - case FE_READ_BER: +static int ves1820_read_ber(struct dvb_frontend* fe, u32* ber) { - u32 ber = ves1820_readreg(state, 0x14) | + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + + u32 _ber = ves1820_readreg(state, 0x14) | (ves1820_readreg(state, 0x15) << 8) | ((ves1820_readreg(state, 0x16) & 0x0f) << 16); - *((u32*) arg) = 10 * ber; - break; + *ber = 10 * _ber; + + return 0; } - case FE_READ_SIGNAL_STRENGTH: + +static int ves1820_read_signal_strength(struct dvb_frontend* fe, u16* strength) { + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + u8 gain = ves1820_readreg(state, 0x17); - *((u16*) arg) = (gain << 8) | gain; - break; + *strength = (gain << 8) | gain; + + return 0; } - case FE_READ_SNR: +static int ves1820_read_snr(struct dvb_frontend* fe, u16* snr) { + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + u8 quality = ~ves1820_readreg(state, 0x18); - *((u16*) arg) = (quality << 8) | quality; - break; + *snr = (quality << 8) | quality; + + return 0; } - case FE_READ_UNCORRECTED_BLOCKS: - *((u32 *) arg) = ves1820_readreg(state, 0x13) & 0x7f; - if (*((u32*) arg) == 0x7f) - *((u32*) arg) = 0xffffffff; +static int ves1820_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; + + *ucblocks = ves1820_readreg(state, 0x13) & 0x7f; + if (*ucblocks == 0x7f) + *ucblocks = 0xffffffff; + /* reset uncorrected block counter */ ves1820_writereg(state, 0x10, ves1820_inittab[0x10] & 0xdf); ves1820_writereg(state, 0x10, ves1820_inittab[0x10]); - break; - case FE_SET_FRONTEND: - return ves1820_set_parameters(state, arg); + return 0; +} - case FE_GET_FRONTEND: +static int ves1820_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dvb_frontend_parameters *p = (struct dvb_frontend_parameters *)arg; + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; int sync; s8 afc = 0; @@ -409,7 +346,12 @@ "ves1820: [AFC (%d) %dHz]\n", afc, -((s32) p->u.qam.symbol_rate * afc) >> 10); } - p->inversion = HAS_INVERSION(state->reg0) ? INVERSION_ON : INVERSION_OFF; + if (!state->config->invert) { + p->inversion = (state->reg0 & 0x20) ? INVERSION_ON : INVERSION_OFF; + } else { + p->inversion = (!(state->reg0 & 0x20)) ? INVERSION_ON : INVERSION_OFF; + } + p->u.qam.modulation = ((state->reg0 >> 2) & 7) + QAM_16; p->u.qam.fec_inner = FEC_NONE; @@ -417,229 +359,112 @@ p->frequency = ((p->frequency + 31250) / 62500) * 62500; if (sync & 2) p->frequency -= ((s32)p->u.qam.symbol_rate * afc) >> 10; - break; - } - case FE_SLEEP: - ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */ - ves1820_writereg(state, 0x00, 0x80); /* standby */ - break; - - case FE_INIT: - return ves1820_init(state); - - default: - return -EINVAL; - } return 0; } -static long probe_tuner(struct i2c_adapter *i2c) +static int ves1820_sleep(struct dvb_frontend* fe) { - struct i2c_msg msg1 = {.addr = 0x61,.flags = 0,.buf = NULL,.len = 0 }; - struct i2c_msg msg2 = {.addr = 0x62,.flags = 0,.buf = NULL,.len = 0 }; - int type; - - if (i2c_transfer(i2c, &msg1, 1) == 1) { - type = 0; - printk("ves1820: setup for tuner spXXXX\n"); - } else if (i2c_transfer(i2c, &msg2, 1) == 1) { - type = 1; - printk("ves1820: setup for tuner sp5659c\n"); - } else { - type = -1; - } - - return type; -} + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; -static u8 read_pwm(struct i2c_adapter *i2c) -{ - u8 b = 0xff; - u8 pwm; - struct i2c_msg msg [] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 }, - {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} - }; - - if ((i2c_transfer(i2c, msg, 2) != 2) || (pwm == 0xff)) - pwm = 0x48; - - printk("ves1820: pwm=0x%02x\n", pwm); - - return pwm; -} - -static long probe_demod_addr(struct i2c_adapter *i2c) -{ - u8 b [] = { 0x00, 0x1a }; - u8 id; - struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b, .len = 2 }, - {.addr = 0x08,.flags = I2C_M_RD,.buf = &id,.len = 1} - }; - - if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70) - return msg[0].addr; - - msg[0].addr = msg[1].addr = 0x09; - - if (i2c_transfer(i2c, msg, 2) == 2 && (id & 0xf0) == 0x70) - return msg[0].addr; - - return -1; -} - -static ssize_t attr_read_pwm(struct device *dev, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client); - return sprintf(buf, "0x%02x\n", state->pwm); -} + ves1820_writereg(state, 0x1b, 0x02); /* pdown ADC */ + ves1820_writereg(state, 0x00, 0x80); /* standby */ -static ssize_t attr_write_pwm(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client); - unsigned long pwm; - pwm = simple_strtoul(buf, NULL, 0); - state->pwm = pwm & 0xff; - return strlen(buf)+1; + return 0; } -static struct device_attribute dev_attr_client_name = { - .attr = { .name = "pwm", .mode = S_IRUGO|S_IWUGO, .owner = THIS_MODULE }, - .show = &attr_read_pwm, - .store = &attr_write_pwm, -}; - -static struct i2c_client client_template; - -static int attach_adapter(struct i2c_adapter *adapter) +static int ves1820_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { - struct i2c_client *client; - struct ves1820_state *state; - long demod_addr; - int tuner_type; - int ret; - - demod_addr = probe_demod_addr(adapter); - if (demod_addr < 0) - return -ENODEV; - - tuner_type = probe_tuner(adapter); - if (tuner_type < 0) { - printk("ves1820: demod found, but unknown tuner type.\n"); - return -ENODEV; - } - - if ((state = kmalloc(sizeof(struct ves1820_state), GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(state); - return -ENOMEM; - } - - memset(state, 0, sizeof(*state)); - state->i2c = adapter; - state->tuner = tuner_type; - state->pwm = read_pwm(adapter); - state->reg0 = ves1820_inittab[0]; - state->demod_addr = demod_addr; - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = addr[tuner_type]; - - i2c_set_clientdata(client, (void *) state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(state); - return ret; -} - - BUG_ON(!state->dvb); - - device_create_file(&client->dev, &dev_attr_client_name); - - ret = dvb_register_frontend(ves1820_ioctl, state->dvb, state, &ves1820_info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - kfree(client); - kfree(state); - return ret; - } + fesettings->min_delay_ms = 200; + fesettings->step_size = 0; + fesettings->max_drift = 0; return 0; } -static int detach_client(struct i2c_client *client) +static void ves1820_release(struct dvb_frontend* fe) { - struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client); - dvb_unregister_frontend(ves1820_ioctl, state->dvb); - device_remove_file(&client->dev, &dev_attr_client_name); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); + struct ves1820_state* state = (struct ves1820_state*) fe->demodulator_priv; kfree(state); - return 0; -} - -static int command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct ves1820_state *state = (struct ves1820_state *) i2c_get_clientdata(client); - - switch (cmd) { - case FE_REGISTER:{ - state->dvb = (struct dvb_adapter *) arg; - break; - } - case FE_UNREGISTER:{ - state->dvb = NULL; - break; - } - default: - return -EOPNOTSUPP; - } - return 0; } -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "ves1820", - .id = I2C_DRIVERID_VES1820, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; +static struct dvb_frontend_ops ves1820_ops; -static struct i2c_client client_template = { - I2C_DEVNAME("ves1820"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_ves1820 (void) +struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, + struct i2c_adapter* i2c, + u8 pwm) { - return i2c_add_driver(&driver); -} + struct ves1820_state* state = NULL; -static void __exit exit_ves1820 (void) -{ - if (i2c_del_driver(&driver)) - printk("ves1820: driver deregistration failed\n"); -} + /* allocate memory for the internal state */ + state = (struct ves1820_state*) kmalloc(sizeof(struct ves1820_state), GFP_KERNEL); + if (state == NULL) + goto error; -module_init(init_ves1820); -module_exit(exit_ves1820); + /* setup the state */ + memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops)); + state->reg0 = ves1820_inittab[0]; + state->config = config; + state->i2c = i2c; + state->pwm = pwm; + + /* check if the demod is there */ + if ((ves1820_readreg(state, 0x1a) & 0xf0) != 0x70) + goto error; + + if (verbose) + printk("ves1820: pwm=0x%02x\n", state->pwm); + + state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */ + state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */ + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; + } + +static struct dvb_frontend_ops ves1820_ops = { + + .info = { + .name = "VLSI VES1820 DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .caps = FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO + }, + + .release = ves1820_release, + + .init = ves1820_init, + .sleep = ves1820_sleep, + + .set_frontend = ves1820_set_parameters, + .get_frontend = ves1820_get_frontend, + .get_tune_settings = ves1820_get_tune_settings, + + .read_status = ves1820_read_status, + .read_ber = ves1820_read_ber, + .read_signal_strength = ves1820_read_signal_strength, + .read_snr = ves1820_read_snr, + .read_ucblocks = ves1820_read_ucblocks, +}; -MODULE_PARM(verbose, "i"); +module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting"); -MODULE_DESCRIPTION("VES1820 DVB-C frontend driver"); +MODULE_DESCRIPTION("VLSI VES1820 DVB-C Demodulator driver"); MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); MODULE_LICENSE("GPL"); +EXPORT_SYMBOL(ves1820_attach); diff -Nru a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/ves1820.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,52 @@ +/* + VES1820 - Single Chip Cable Channel Receiver driver module + + Copyright (C) 1999 Convergence Integrated Media GmbH + + 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 VES1820_H +#define VES1820_H + +#include + +#define VES1820_SELAGC_PWM 0 +#define VES1820_SELAGC_SIGNAMPERR 1 + +struct ves1820_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* value of XIN to use */ + u32 xin; + + /* does inversion need inverted? */ + u8 invert:1; + + /* SELAGC control */ + u8 selagc:1; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, + struct i2c_adapter* i2c, + u8 pwm); + +#endif // VES1820_H diff -Nru a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c --- a/drivers/media/dvb/frontends/ves1x93.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/frontends/ves1x93.c 2004-12-12 17:40:52 -08:00 @@ -1,5 +1,5 @@ /* - Driver for VES1893 and VES1993 QPSK Frontends + Driver for VES1893 and VES1993 QPSK Demodulators Copyright (C) 1999 Convergence Integrated Media GmbH Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> @@ -31,41 +31,33 @@ #include #include "dvb_frontend.h" +#include "ves1x93.h" -static int debug = 0; -#define dprintk if (debug) printk -static int board_type = 0; -#define BOARD_SIEMENS_PCI 0 -#define BOARD_NOKIA_DBOX2 1 -#define BOARD_SAGEM_DBOX2 2 +struct ves1x93_state { -static int demod_type = 0; -#define DEMOD_VES1893 0 -#define DEMOD_VES1993 1 + struct i2c_adapter* i2c; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct ves1x93_config* config; -static struct dvb_frontend_info ves1x93_info = { - .name = "VES1x93", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, -/* .symbol_rate_tolerance = ???,*/ - .notifier_delay = 50, /* 1/20 s */ - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK + struct dvb_frontend frontend; + + /* previous uncorrected block counter */ + fe_spectral_inversion_t inversion; + u8 *init_1x93_tab; + u8 *init_1x93_wtab; + u8 tab_size; + u8 demod_type; }; +static int debug = 0; +#define dprintk if (debug) printk -/** - * nokia dbox2 (ves1893) and sagem dbox2 (ves1993) - * need bit AGCR[PWMS] set to 1 - */ +#define DEMOD_VES1893 0 +#define DEMOD_VES1993 1 static u8 init_1893_tab [] = { 0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4, @@ -89,10 +81,6 @@ 0x00, 0x00, 0x0e, 0x80, 0x00 }; - -static u8 * init_1x93_tab; - - static u8 init_1893_wtab[] = { 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0, @@ -110,21 +98,13 @@ 1,1,1,0,1,1,1,1, 1,1,1,1,1 }; -struct ves1x93_state { - fe_spectral_inversion_t inversion; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - - - -static int ves1x93_writereg (struct i2c_adapter *i2c, u8 reg, u8 data) +static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data) { u8 buf [] = { 0x00, reg, data }; - struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 3 }; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 }; int err; - if ((err = i2c_transfer (i2c, &msg, 1)) != 1) { + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); return -EREMOTEIO; } @@ -133,151 +113,31 @@ } -static u8 ves1x93_readreg (struct i2c_adapter *i2c, u8 reg) +static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg) { int ret; u8 b0 [] = { 0x00, reg }; u8 b1 [] = { 0 }; - struct i2c_msg msg [] = { { .addr = 0x08, .flags = 0, .buf = b0, .len = 2 }, - { .addr = 0x08, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } }; - ret = i2c_transfer (i2c, msg, 2); + ret = i2c_transfer (state->i2c, msg, 2); - if (ret != 2) - dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + if (ret != 2) return ret; return b1[0]; } - -static int tuner_write (struct i2c_adapter *i2c, u8 *data, u8 len) -{ - int ret; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = len }; - - ves1x93_writereg(i2c, 0x00, 0x11); - ret = i2c_transfer (i2c, &msg, 1); - ves1x93_writereg(i2c, 0x00, 0x01); - - if (ret != 1) - printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); - - return (ret != 1) ? -1 : 0; -} - - - -/** - * set up the downconverter frequency divisor for a - * reference clock comparision frequency of 125 kHz. - */ -static int sp5659_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ - u8 pwr = 0; - u8 buf[4]; - u32 div = (freq + 479500) / 125; - - if (freq > 2000000) pwr = 3; - else if (freq > 1800000) pwr = 2; - else if (freq > 1600000) pwr = 1; - else if (freq > 1200000) pwr = 0; - else if (freq >= 1100000) pwr = 1; - else pwr = 2; - - buf[0] = (div >> 8) & 0x7f; - buf[1] = div & 0xff; - buf[2] = ((div & 0x18000) >> 10) | 0x95; - buf[3] = (pwr << 6) | 0x30; - - // NOTE: since we're using a prescaler of 2, we set the - // divisor frequency to 62.5kHz and divide by 125 above - - return tuner_write (i2c, buf, sizeof(buf)); -} - - -static int tsa5059_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ - int ret; - u8 buf [2]; - - freq /= 1000; - - buf[0] = (freq >> 8) & 0x7F; - buf[1] = freq & 0xFF; - - ret = tuner_write(i2c, buf, sizeof(buf)); - - return ret; -} - - -static int tuner_set_tv_freq (struct i2c_adapter *i2c, u32 freq) -{ - if ((demod_type == DEMOD_VES1893) && (board_type == BOARD_SIEMENS_PCI)) - return sp5659_set_tv_freq (i2c, freq); - else if (demod_type == DEMOD_VES1993) - return tsa5059_set_tv_freq (i2c, freq); - - return -EINVAL; -} - - -static int ves1x93_init (struct i2c_adapter *i2c) -{ - int i; - int size; - u8 *init_1x93_wtab; - - dprintk("%s: init chip\n", __FUNCTION__); - - switch (demod_type) { - case DEMOD_VES1893: - init_1x93_tab = init_1893_tab; - init_1x93_wtab = init_1893_wtab; - size = sizeof(init_1893_tab); - if (board_type == BOARD_NOKIA_DBOX2) - init_1x93_tab[0x05] |= 0x20; /* invert PWM */ - break; - - case DEMOD_VES1993: - init_1x93_tab = init_1993_tab; - init_1x93_wtab = init_1993_wtab; - size = sizeof(init_1993_tab); - if (board_type == BOARD_SAGEM_DBOX2) - init_1x93_tab[0x05] |= 0x20; /* invert PWM */ - break; - - default: - return -EINVAL; - } - - for (i = 0; i < size; i++) - if (init_1x93_wtab[i]) - ves1x93_writereg (i2c, i, init_1x93_tab[i]); - - if (demod_type == DEMOD_VES1993) { - if (board_type == BOARD_NOKIA_DBOX2) - tuner_write(i2c, "\x06\x5c\x83\x60", 4); - else if (board_type == BOARD_SAGEM_DBOX2) - tuner_write(i2c, "\x25\x70\x92\x40", 4); - } - - return 0; -} - - -static int ves1x93_clr_bit (struct i2c_adapter *i2c) +static int ves1x93_clr_bit (struct ves1x93_state* state) { msleep(10); - ves1x93_writereg (i2c, 0, init_1x93_tab[0] & 0xfe); - ves1x93_writereg (i2c, 0, init_1x93_tab[0]); + ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe); + ves1x93_writereg (state, 0, state->init_1x93_tab[0]); msleep(50); return 0; } - -static int ves1x93_set_inversion (struct i2c_adapter *i2c, fe_spectral_inversion_t inversion) +static int ves1x93_set_inversion (struct ves1x93_state* state, fe_spectral_inversion_t inversion) { u8 val; @@ -300,66 +160,47 @@ return -EINVAL; } - return ves1x93_writereg (i2c, 0x0c, (init_1x93_tab[0x0c] & 0x3f) | val); + return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val); } -static int ves1x93_set_fec (struct i2c_adapter *i2c, fe_code_rate_t fec) +static int ves1x93_set_fec (struct ves1x93_state* state, fe_code_rate_t fec) { if (fec == FEC_AUTO) - return ves1x93_writereg (i2c, 0x0d, 0x08); + return ves1x93_writereg (state, 0x0d, 0x08); else if (fec < FEC_1_2 || fec > FEC_8_9) return -EINVAL; else - return ves1x93_writereg (i2c, 0x0d, fec - FEC_1_2); + return ves1x93_writereg (state, 0x0d, fec - FEC_1_2); } -static fe_code_rate_t ves1x93_get_fec (struct i2c_adapter *i2c) +static fe_code_rate_t ves1x93_get_fec (struct ves1x93_state* state) { - return FEC_1_2 + ((ves1x93_readreg (i2c, 0x0d) >> 4) & 0x7); + return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7); } -static int ves1x93_set_symbolrate (struct i2c_adapter *i2c, u32 srate) +static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate) { u32 BDR; u32 ratio; u8 ADCONF, FCONF, FNR; u32 BDRI; u32 tmp; - u32 XIN, FIN; + u32 FIN; dprintk("%s: srate == %d\n", __FUNCTION__, (unsigned int) srate); - switch (board_type) { - case BOARD_SIEMENS_PCI: - XIN = 90100000UL; - break; - case BOARD_NOKIA_DBOX2: - if (demod_type == DEMOD_VES1893) - XIN = 91000000UL; - else if (demod_type == DEMOD_VES1993) - XIN = 96000000UL; - else - return -EINVAL; - break; - case BOARD_SAGEM_DBOX2: - XIN = 92160000UL; - break; - default: - return -EINVAL; - } - - if (srate > XIN/2) - srate = XIN/2; + if (srate > state->config->xin/2) + srate = state->config->xin/2; if (srate < 500000) srate = 500000; #define MUL (1UL<<26) - FIN = (XIN + 6000) >> 4; + FIN = (state->config->xin + 6000) >> 4; tmp = srate << 6; ratio = tmp / FIN; @@ -404,55 +245,87 @@ if (BDRI > 0xff) BDRI = 0xff; - ves1x93_writereg (i2c, 0x06, 0xff & BDR); - ves1x93_writereg (i2c, 0x07, 0xff & (BDR >> 8)); - ves1x93_writereg (i2c, 0x08, 0x0f & (BDR >> 16)); - - ves1x93_writereg (i2c, 0x09, BDRI); - ves1x93_writereg (i2c, 0x20, ADCONF); - ves1x93_writereg (i2c, 0x21, FCONF); + ves1x93_writereg (state, 0x06, 0xff & BDR); + ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8)); + ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16)); + + ves1x93_writereg (state, 0x09, BDRI); + ves1x93_writereg (state, 0x20, ADCONF); + ves1x93_writereg (state, 0x21, FCONF); if (srate < 6000000) - ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] | 0x80); + ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] | 0x80); else - ves1x93_writereg (i2c, 0x05, init_1x93_tab[0x05] & 0x7f); + ves1x93_writereg (state, 0x05, state->init_1x93_tab[0x05] & 0x7f); /* ves1993 hates this, will lose lock */ - if (demod_type != DEMOD_VES1993) - ves1x93_clr_bit (i2c); + if (state->demod_type != DEMOD_VES1993) + ves1x93_clr_bit (state); return 0; } -static int ves1x93_set_voltage (struct i2c_adapter *i2c, fe_sec_voltage_t voltage) + + + + + + + + + + + + + + +static int ves1x93_init (struct dvb_frontend* fe) { + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + int i; + int val; + + dprintk("%s: init chip\n", __FUNCTION__); + + for (i = 0; i < state->tab_size; i++) { + if (state->init_1x93_wtab[i]) { + val = state->init_1x93_tab[i]; + + if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */ + ves1x93_writereg (state, i, val); + } + } + + if (state->config->pll_init) { + ves1x93_writereg(state, 0x00, 0x11); + state->config->pll_init(fe); + ves1x93_writereg(state, 0x00, 0x01); + } + + return 0; +} + +static int ves1x93_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + switch (voltage) { case SEC_VOLTAGE_13: - return ves1x93_writereg (i2c, 0x1f, 0x20); + return ves1x93_writereg (state, 0x1f, 0x20); case SEC_VOLTAGE_18: - return ves1x93_writereg (i2c, 0x1f, 0x30); + return ves1x93_writereg (state, 0x1f, 0x30); case SEC_VOLTAGE_OFF: - return ves1x93_writereg (i2c, 0x1f, 0x00); + return ves1x93_writereg (state, 0x1f, 0x00); default: return -EINVAL; } } - -static int ves1x93_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct ves1x93_state *state = (struct ves1x93_state*) fe->data; - struct i2c_adapter *i2c = state->i2c; - - switch (cmd) { - case FE_GET_INFO: - memcpy (arg, &ves1x93_info, sizeof(struct dvb_frontend_info)); - break; + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; - case FE_READ_STATUS: - { - fe_status_t *status = arg; - u8 sync = ves1x93_readreg (i2c, 0x0e); + u8 sync = ves1x93_readreg (state, 0x0e); /* * The ves1893 sometimes returns sync values that make no sense, @@ -466,7 +339,7 @@ int maxtry = 10; /* just for safety - let's not get stuck here */ while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) { msleep(10); - sync = ves1x93_readreg (i2c, 0x0e); + sync = ves1x93_readreg (state, 0x0e); } *status = 0; @@ -486,64 +359,78 @@ if ((sync & 0x1f) == 0x1f) *status |= FE_HAS_LOCK; - break; + return 0; } - case FE_READ_BER: + +static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber) { - u32 *ber = (u32 *) arg; + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; - *ber = ves1x93_readreg (i2c, 0x15); - *ber |= (ves1x93_readreg (i2c, 0x16) << 8); - *ber |= ((ves1x93_readreg (i2c, 0x17) & 0x0F) << 16); + *ber = ves1x93_readreg (state, 0x15); + *ber |= (ves1x93_readreg (state, 0x16) << 8); + *ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16); *ber *= 10; - break; + + return 0; } - case FE_READ_SIGNAL_STRENGTH: +static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - u8 signal = ~ves1x93_readreg (i2c, 0x0b); - *((u16*) arg) = (signal << 8) | signal; - break; + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + + u8 signal = ~ves1x93_readreg (state, 0x0b); + *strength = (signal << 8) | signal; + + return 0; } - case FE_READ_SNR: +static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr) { - u8 snr = ~ves1x93_readreg (i2c, 0x1c); - *(u16*) arg = (snr << 8) | snr; - break; + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + + u8 _snr = ~ves1x93_readreg (state, 0x1c); + *snr = (_snr << 8) | _snr; + + return 0; } - case FE_READ_UNCORRECTED_BLOCKS: +static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { - *(u32*) arg = ves1x93_readreg (i2c, 0x18) & 0x7f; + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; - if (*(u32*) arg == 0x7f) - *(u32*) arg = 0xffffffff; /* counter overflow... */ + *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f; - ves1x93_writereg (i2c, 0x18, 0x00); /* reset the counter */ - ves1x93_writereg (i2c, 0x18, 0x80); /* dto. */ - break; + if (*ucblocks == 0x7f) + *ucblocks = 0xffffffff; /* counter overflow... */ + + ves1x93_writereg (state, 0x18, 0x00); /* reset the counter */ + ves1x93_writereg (state, 0x18, 0x80); /* dto. */ + + return 0; } - case FE_SET_FRONTEND: +static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dvb_frontend_parameters *p = arg; + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; - tuner_set_tv_freq (i2c, p->frequency); - ves1x93_set_inversion (i2c, p->inversion); - ves1x93_set_fec (i2c, p->u.qpsk.fec_inner); - ves1x93_set_symbolrate (i2c, p->u.qpsk.symbol_rate); + ves1x93_writereg(state, 0x00, 0x11); + state->config->pll_set(fe, p); + ves1x93_writereg(state, 0x00, 0x01); + ves1x93_set_inversion (state, p->inversion); + ves1x93_set_fec (state, p->u.qpsk.fec_inner); + ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate); state->inversion = p->inversion; - break; + + return 0; } - case FE_GET_FRONTEND: +static int ves1x93_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dvb_frontend_parameters *p = arg; + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; int afc; - afc = ((int)((char)(ves1x93_readreg (i2c, 0x0a) << 1)))/2; + afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2; afc = (afc * (int)(p->u.qpsk.symbol_rate/1000/8))/16; p->frequency -= afc; @@ -553,185 +440,125 @@ * if auto inversion was used */ if (state->inversion == INVERSION_AUTO) - p->inversion = (ves1x93_readreg (i2c, 0x0f) & 2) ? + p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ? INVERSION_OFF : INVERSION_ON; - p->u.qpsk.fec_inner = ves1x93_get_fec (i2c); + p->u.qpsk.fec_inner = ves1x93_get_fec (state); /* XXX FIXME: timing offset !! */ - break; - } - case FE_SLEEP: - if (board_type == BOARD_SIEMENS_PCI) - ves1x93_writereg (i2c, 0x1f, 0x00); /* LNB power off */ - return ves1x93_writereg (i2c, 0x00, 0x08); - - case FE_INIT: - return ves1x93_init (i2c); - - case FE_SET_TONE: - return -EOPNOTSUPP; /* the ves1893 can generate the 22k */ - /* let's implement this when we have */ - /* a box that uses the 22K_0 pin... */ + return 0; +} - case FE_SET_VOLTAGE: - return ves1x93_set_voltage (i2c, (fe_sec_voltage_t) arg); +static int ves1x93_sleep(struct dvb_frontend* fe) +{ + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; - default: - return -EOPNOTSUPP; - }; + return ves1x93_writereg (state, 0x00, 0x08); +} - return 0; +static void ves1x93_release(struct dvb_frontend* fe) +{ + struct ves1x93_state* state = (struct ves1x93_state*) fe->demodulator_priv; + kfree(state); } -static struct i2c_client client_template; +static struct dvb_frontend_ops ves1x93_ops; -static int attach_adapter(struct i2c_adapter *adapter) +struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, + struct i2c_adapter* i2c) { - struct i2c_client *client; - struct ves1x93_state* state; - u8 identity = ves1x93_readreg(adapter, 0x1e); - int ret; + struct ves1x93_state* state = NULL; + u8 identity; + /* allocate memory for the internal state */ + state = (struct ves1x93_state*) kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops)); + state->inversion = INVERSION_OFF; + + /* check if the demod is there + identify it */ + identity = ves1x93_readreg(state, 0x1e); switch (identity) { case 0xdc: /* VES1893A rev1 */ printk("ves1x93: Detected ves1893a rev1\n"); - demod_type = DEMOD_VES1893; - ves1x93_info.name[4] = '8'; + state->demod_type = DEMOD_VES1893; + state->init_1x93_tab = init_1893_tab; + state->init_1x93_wtab = init_1893_wtab; + state->tab_size = sizeof(init_1893_tab); break; + case 0xdd: /* VES1893A rev2 */ printk("ves1x93: Detected ves1893a rev2\n"); - demod_type = DEMOD_VES1893; - ves1x93_info.name[4] = '8'; + state->demod_type = DEMOD_VES1893; + state->init_1x93_tab = init_1893_tab; + state->init_1x93_wtab = init_1893_wtab; + state->tab_size = sizeof(init_1893_tab); break; + case 0xde: /* VES1993 */ printk("ves1x93: Detected ves1993\n"); - demod_type = DEMOD_VES1993; - ves1x93_info.name[4] = '9'; - break; - default: - dprintk("VES1x93 not found (identity %02x)\n", identity); - return -ENODEV; - } - - if ((state = kmalloc(sizeof(struct ves1x93_state), GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(state); - return -ENOMEM; - } - - state->inversion = INVERSION_OFF; - state->i2c = adapter; - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = (0x08>>1); - i2c_set_clientdata(client, (void*)state); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(state); - return -EFAULT; - } - - BUG_ON(!state->dvb); - - ret = dvb_register_frontend(ves1x93_ioctl, state->dvb, state, - &ves1x93_info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - kfree(client); - kfree(state); - return -EFAULT; -} - - return 0; -} - -static int detach_client(struct i2c_client *client) -{ - struct ves1x93_state *state = (struct ves1x93_state*)i2c_get_clientdata(client); - dvb_unregister_frontend(ves1x93_ioctl, state->dvb); - i2c_detach_client(client); - BUG_ON(state->dvb); - kfree(client); - kfree(state); - return 0; -} - -static int command (struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct ves1x93_state *state = (struct ves1x93_state*)i2c_get_clientdata(client); - - dprintk ("%s\n", __FUNCTION__); - - switch (cmd) { - case FE_REGISTER: { - state->dvb = (struct dvb_adapter*)arg; + state->demod_type = DEMOD_VES1993; + state->init_1x93_tab = init_1993_tab; + state->init_1x93_wtab = init_1993_wtab; + state->tab_size = sizeof(init_1993_tab); break; - } - case FE_UNREGISTER: { - state->dvb = NULL; - break; - } - default: - return -EOPNOTSUPP; -} - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "ves1x93", - .id = I2C_DRIVERID_DVBFE_VES1X93, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; -static struct i2c_client client_template = { - I2C_DEVNAME("ves1x93"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_ves1x93 (void) -{ - switch (board_type) { - case BOARD_NOKIA_DBOX2: - dprintk("%s: NOKIA_DBOX2\n", __FILE__); - break; - case BOARD_SAGEM_DBOX2: - dprintk("%s: SAGEM_DBOX2\n", __FILE__); - break; - case BOARD_SIEMENS_PCI: - dprintk("%s: SIEMENS_PCI\n", __FILE__); - break; default: - return -EIO; + goto error; } - return i2c_add_driver(&driver); -} - - -static void __exit exit_ves1x93 (void) -{ - if (i2c_del_driver(&driver)) - printk("vex1x93: driver deregistration failed\n"); -} + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; + } + +static struct dvb_frontend_ops ves1x93_ops = { + + .info = { + .name = "VLSI VES1x93 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* .symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = ves1x93_release, + + .init = ves1x93_init, + .sleep = ves1x93_sleep, + + .set_frontend = ves1x93_set_frontend, + .get_frontend = ves1x93_get_frontend, + + .read_status = ves1x93_read_status, + .read_ber = ves1x93_read_ber, + .read_signal_strength = ves1x93_read_signal_strength, + .read_snr = ves1x93_read_snr, + .read_ucblocks = ves1x93_read_ucblocks, -module_init(init_ves1x93); -module_exit(exit_ves1x93); + .set_voltage = ves1x93_set_voltage, +}; +module_param(debug, int, 0644); -MODULE_DESCRIPTION("VES1x93 DVB-S Frontend"); +MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver"); MODULE_AUTHOR("Ralph Metzler"); MODULE_LICENSE("GPL"); -MODULE_PARM(debug,"i"); -MODULE_PARM(board_type,"i"); +EXPORT_SYMBOL(ves1x93_attach); diff -Nru a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/ves1x93.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,50 @@ +/* + Driver for VES1893 and VES1993 QPSK Demodulators + + Copyright (C) 1999 Convergence Integrated Media GmbH + Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de> + Copyright (C) 2002 Dennis Noermann + Copyright (C) 2002-2003 Andreas Oberritter + + 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 VES1X93_H +#define VES1X93_H + +#include + +struct ves1x93_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* value of XIN to use */ + u32 xin; + + /* should PWM be inverted? */ + u8 invert_pwm:1; + + /* PLL maintenance */ + int (*pll_init)(struct dvb_frontend* fe); + int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); +}; + +extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, + struct i2c_adapter* i2c); + +#endif // VES1X93_H diff -Nru a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig --- a/drivers/media/dvb/ttpci/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/Kconfig 2004-12-12 17:40:52 -08:00 @@ -4,6 +4,12 @@ select FW_LOADER select VIDEO_DEV select VIDEO_SAA7146_VV + select DVB_VES1820 + select DVB_VES1X93 + select DVB_STV0299 + select DVB_TDA8083 + select DVB_SP8870 + select DVB_STV0297 help Support for SAA7146 and AV7110 based DVB cards as produced by Fujitsu-Siemens, Technotrend, Hauppauge and others. @@ -53,6 +59,12 @@ tristate "Budget cards" depends on DVB_CORE && PCI select VIDEO_SAA7146 + select DVB_STV0299 + select DVB_VES1X93 + select DVB_VES1820 + select DVB_L64781 + select DVB_TDA8083 + select DVB_TDA10021 help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard @@ -67,6 +79,8 @@ tristate "Budget cards with onboard CI connector" depends on DVB_CORE && PCI select VIDEO_SAA7146 + select DVB_STV0299 + select DVB_TDA1004X help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard @@ -85,6 +99,7 @@ depends on DVB_CORE && PCI select VIDEO_DEV select VIDEO_SAA7146_VV + select DVB_STV0299 help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard @@ -99,6 +114,9 @@ tristate "AV7110 cards with Budget Patch" depends on DVB_CORE && DVB_BUDGET select DVB_AV7110 + select DVB_STV0299 + select DVB_VES1X93 + select DVB_TDA8083 help Support for Budget Patch (full TS) modification on SAA7146+AV7110 based cards (DVB-S cards). This diff -Nru a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile --- a/drivers/media/dvb/ttpci/Makefile 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/Makefile 2004-12-12 17:40:52 -08:00 @@ -11,7 +11,7 @@ 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/ +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ hostprogs-y := fdump diff -Nru a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c --- a/drivers/media/dvb/ttpci/av7110.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttpci/av7110.c 2004-12-12 17:40:53 -08:00 @@ -94,7 +94,16 @@ static void restart_feeds(struct av7110 *av7110); -int av7110_num = 0; +static int av7110_num = 0; + +#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \ +{\ + if (fe_func != NULL) { \ + av7110_copy = fe_func; \ + fe_func = av7110_func; \ + } \ +} + static void init_av7110_av(struct av7110 *av7110) { @@ -259,15 +268,15 @@ irc_handler = NULL; } -void run_handlers(unsigned long ircom) +static void run_handlers(unsigned long ircom) { if (irc_handler != NULL) (*irc_handler)((u32) ircom); } -DECLARE_TASKLET(irtask,run_handlers,0); +static DECLARE_TASKLET(irtask, run_handlers, 0); -void IR_handle(struct av7110 *av7110, u32 ircom) +static void IR_handle(struct av7110 *av7110, u32 ircom) { dprintk(4, "ircommand = %08x\n", ircom); irtask.data = (unsigned long) ircom; @@ -572,7 +581,7 @@ wake_up(&cibuf->queue); iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - saa7146_wait_for_debi_done(av7110->dev); + saa7146_wait_for_debi_done(av7110->dev, 0); saa7146_write(av7110->dev, IER, saa7146_read(av7110->dev, IER) | MASK_19 ); if (len < 5) @@ -610,7 +619,7 @@ dprintk(8, "GPIO0 PES_PLAY len=%04x\n", len); iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2); iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2); - saa7146_wait_for_debi_done(av7110->dev); + saa7146_wait_for_debi_done(av7110->dev, 0); saa7146_write(av7110->dev, IER, saa7146_read(av7110->dev, IER) | MASK_19 ); @@ -637,7 +646,7 @@ memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); av7110->bmpp+=len; av7110->bmplen-=len; - saa7146_wait_for_debi_done(av7110->dev); + saa7146_wait_for_debi_done(av7110->dev, 0); saa7146_write(av7110->dev, IER, saa7146_read(av7110->dev, IER) | MASK_19 ); if (len < 5) @@ -659,7 +668,7 @@ case DATA_TS_RECORD: case DATA_PES_RECORD: - saa7146_wait_for_debi_done(av7110->dev); + saa7146_wait_for_debi_done(av7110->dev, 0); saa7146_write(av7110->dev, IER, saa7146_read(av7110->dev, IER) | MASK_19); irdebi(av7110, DEBISWAB, DPRAM_BASE+rxbuf, 0, len); @@ -667,7 +676,7 @@ return; case DATA_DEBUG_MESSAGE: - saa7146_wait_for_debi_done(av7110->dev); + saa7146_wait_for_debi_done(av7110->dev, 0); if (!len || len>0xff) { iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; @@ -1090,71 +1099,42 @@ * SEC device file operations ******************************************************************************/ -static int av7110_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct av7110 *av7110 = fe->before_after_data; - dprintk(4, "%p\n", av7110); +static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; - switch (cmd) { - case FE_SET_TONE: - switch ((fe_sec_tone_mode_t) arg) { + switch (tone) { case SEC_TONE_ON: Set22K(av7110, 1); break; case SEC_TONE_OFF: Set22K(av7110, 0); break; + default: return -EINVAL; -}; - break; - - case FE_DISEQC_SEND_MASTER_CMD: - { - struct dvb_diseqc_master_cmd *cmd = arg; - av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); - break; } - case FE_DISEQC_SEND_BURST: - av7110_diseqc_send(av7110, 0, NULL, (unsigned long) arg); - break; - - default: - return -EOPNOTSUPP; -}; - return 0; } - -static void av7110_before_after_tune (fe_status_t s, void *data) +static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) { - struct av7110 *av7110 = data; + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; - dprintk(4, "%p\n", av7110); + av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1); - av7110->fe_synced = (s & FE_HAS_LOCK) ? 1 : 0; + return 0; +} - if (av7110->playing) - return; +static int av7110_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; - if (down_interruptible(&av7110->pid_mutex)) - return; + av7110_diseqc_send(av7110, 0, NULL, minicmd); - if (av7110->fe_synced) { - SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], - av7110->pids[DMX_PES_AUDIO], - av7110->pids[DMX_PES_TELETEXT], 0, - av7110->pids[DMX_PES_PCR]); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); - } else { - SetPIDs(av7110, 0, 0, 0, 0, 0); - av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0); - } - - up(&av7110->pid_mutex); + return 0; } @@ -1170,15 +1150,6 @@ av7110->registered=1; - dvb_add_frontend_notifier (av7110->dvb_adapter, - av7110_before_after_tune, av7110); - - /** - * init DiSEqC stuff - */ - dvb_add_frontend_ioctls (av7110->dvb_adapter, - av7110_diseqc_ioctl, NULL, av7110); - dvbdemux->priv = (void *) av7110; for (i=0; i<32; i++) @@ -1252,12 +1223,7 @@ dvb_dmxdev_release(&av7110->dmxdev); dvb_dmx_release(&av7110->demux); - dvb_remove_frontend_notifier (av7110->dvb_adapter, - av7110_before_after_tune); - - dvb_remove_frontend_ioctls (av7110->dvb_adapter, - av7110_diseqc_ioctl, NULL); - + if (av7110->fe != NULL) dvb_unregister_frontend(av7110->fe); dvb_unregister_device(av7110->osd_dev); av7110_av_unregister(av7110); av7110_ca_unregister(av7110); @@ -1280,6 +1246,7 @@ return i2c_transfer(&av7110->i2c_adap, &msgs, 1); } +#if 0 u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) { u8 mm1[] = {0x00}; @@ -1296,6 +1263,7 @@ return mm2[0]; } +#endif /**************************************************************************** * INITIALIZATION @@ -1408,28 +1376,532 @@ #endif -static int client_register(struct i2c_client *client) +static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { - struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter); - struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (params->frequency + 479500) / 125; + + if (params->frequency > 2000000) pwr = 3; + else if (params->frequency > 1800000) pwr = 2; + else if (params->frequency > 1600000) pwr = 1; + else if (params->frequency > 1200000) pwr = 0; + else if (params->frequency >= 1100000) pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; - /* fixme: check for "type" (ie. frontend type) */ - if (client->driver->command) - return client->driver->command(client, FE_REGISTER, av7110->dvb_adapter); + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; return 0; } -static int client_unregister(struct i2c_client *client) +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, + .pll_set = alps_bsrv2_pll_set, +}; + + +static u8 alps_bsru6_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x52, + 0xff, 0xff +}; + +static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) { - struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter); - struct av7110 *av7110 = (struct av7110*)dev->ext_priv; + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); + + return 0; +} + +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + int ret; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + data[3] = 0xC4; + + if (params->frequency > 1530000) data[3] = 0xc0; + + ret = i2c_transfer (&av7110->i2c_adap, &msg, 1); + if (ret != 1) + return -EIO; + return 0; +} + +static struct stv0299_config alps_bsru6_config = { + + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, + .pll_set = alps_bsru6_pll_set, +}; + + + +static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, + .pll_set = alps_tdbe2_pll_set, +}; + + + + +static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, + .pll_set = grundig_29504_451_pll_set, +}; + + + +static int philips_cd1516_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + u32 div; + u32 f = params->frequency; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (f + 36125000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34); + + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct ves1820_config philips_cd1516_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, + .pll_set = philips_cd1516_pll_set, +}; + + + +static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + u32 div, pwr; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 36200000) / 166666; + + if (params->frequency <= 782000000) + pwr = 1; + else + pwr = 2; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85; + data[3] = pwr << 6; + + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + return request_firmware(fw, name, &av7110->dev->pci->dev); +} + +static struct sp8870_config alps_tdlb7_config = { + + .demod_address = 0x71, + .pll_set = alps_tdlb7_pll_set, + .request_firmware = alps_tdlb7_request_firmware, +}; + + + +static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) }; + struct i2c_msg readmsg = { .addr = 0x63, .flags = I2C_M_RD, .buf = data, .len = 1 }; + int i; + + // this calculation does not match the TDA6405TS datasheet! + div = (params->frequency + 36150000 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0xce; // this value does not match the TDA6405TS datasheet! + + if (params->frequency < 45000000) + return -EINVAL; + else if (params->frequency < 137000000) + data[3] = 0x01; + else if (params->frequency < 403000000) + data[3] = 0x02; + else if (params->frequency < 860000000) + data[3] = 0x04; + else + return -EINVAL; + + stv0297_enable_plli2c(fe); + if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) { + printk("nexusca: pll transfer failed!\n"); + return -EIO; + } + + // wait for PLL lock + for(i=0; i< 20; i++) { + + stv0297_enable_plli2c(fe); + if (i2c_transfer (&av7110->i2c_adap, &readmsg, 1) == 1) + if (data[0] & 0x40) break; + msleep(10); + } + + return 0; +} + +static struct stv0297_config nexusca_stv0297_config = { + + .demod_address = 0x1C, + .pll_set = nexusca_stv0297_pll_set, +}; + + +static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) +{ + msleep (50); + + av7110->fe_synced = (status & FE_HAS_LOCK) ? 1 : 0; + + if (av7110->playing) + return; + + if (down_interruptible(&av7110->pid_mutex)) + return; + + if (av7110->fe_synced) { + SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO], + av7110->pids[DMX_PES_AUDIO], + av7110->pids[DMX_PES_TELETEXT], 0, + av7110->pids[DMX_PES_PCR]); + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); + } else { + SetPIDs(av7110, 0, 0, 0, 0, 0); + av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, FlushTSQueue, 0); + } + + av7110->fe_status = status; + up(&av7110->pid_mutex); +} + +static int av7110_fe_init(struct dvb_frontend* fe) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + av7110_fe_lock_fix(av7110, 0); + return av7110->fe_init(fe); +} + +static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + int ret; + + /* call the real implementation */ + ret = av7110->fe_read_status(fe, status); + if (ret) + return ret; + + if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) { + av7110_fe_lock_fix(av7110, *status); + } - /* fixme: check for "type" (ie. frontend type) */ - if (client->driver->command) - return client->driver->command(client, FE_UNREGISTER, av7110->dvb_adapter); return 0; } +static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + av7110_fe_lock_fix(av7110, 0); + return av7110->fe_diseqc_reset_overload(fe); +} + +static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + av7110_fe_lock_fix(av7110, 0); + return av7110->fe_diseqc_send_master_cmd(fe, cmd); +} + +static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + av7110_fe_lock_fix(av7110, 0); + return av7110->fe_diseqc_send_burst(fe, minicmd); +} + +static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + av7110_fe_lock_fix(av7110, 0); + return av7110->fe_set_tone(fe, tone); +} + +static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + av7110_fe_lock_fix(av7110, 0); + return av7110->fe_set_voltage(fe, voltage); +} + +static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd) +{ + struct av7110* av7110 = (struct av7110*) fe->dvb->priv; + + av7110_fe_lock_fix(av7110, 0); + return av7110->fe_dishnetwork_send_legacy_command(fe, cmd); +} + +static u8 read_pwm(struct av7110* av7110) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static void frontend_init(struct av7110 *av7110) +{ + if (av7110->dev->pci->subsystem_vendor == 0x110a) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) + av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) + break; + break; + } + + } else if (av7110->dev->pci->subsystem_vendor == 0x13c2) { + switch(av7110->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X + case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE + + // try the ALPS BSRV2 first of all + av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops->set_tone = av7110_set_tone; + break; + } + + // try the ALPS BSRU6 now + av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops->set_tone = av7110_set_tone; + break; + } + + // Try the grundig 29504-451 + av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops->set_tone = av7110_set_tone; + break; + } + break; + + case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X + + // ALPS TDLB7 + av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap); + if (av7110->fe) + break; + break; + + case 0x0002: // Hauppauge/TT DVB-C premium rev2.X + + av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) + break; + break; + + case 0x000A: // Hauppauge/TT Nexus-CA rev1.X + + av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b); + if (av7110->fe) { + /* tuner on this needs a slower i2c bus speed */ + av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240; + break; + } + } + } + + if (av7110->fe == NULL) { + printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + av7110->dev->pci->vendor, + av7110->dev->pci->device, + av7110->dev->pci->subsystem_vendor, + av7110->dev->pci->subsystem_device); + } else { + FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init); + FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status); + FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); + FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); + FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); + FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone); + FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;) + FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); + if (dvb_register_frontend(av7110->dvb_adapter, av7110->fe)) { + printk("av7110: Frontend registration failed!\n"); + if (av7110->fe->ops->release) + av7110->fe->ops->release(av7110->fe); + av7110->fe = NULL; + } + } +} + static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext) { struct av7110 *av7110 = NULL; @@ -1446,7 +1918,7 @@ memset(av7110, 0, sizeof(struct av7110)); av7110->card_name = (char*)pci_ext->ext_priv; - av7110->dev=(struct saa7146_dev *)dev; + av7110->dev = dev; dev->ext_priv = av7110; if ((ret = get_firmware(av7110))) { @@ -1460,15 +1932,11 @@ get recognized before the main driver is fully loaded */ saa7146_write(dev, GPIO_CTRL, 0x500000); - av7110->i2c_adap = (struct i2c_adapter) { - .client_register = client_register, - .client_unregister = client_unregister, #ifdef I2C_ADAP_CLASS_TV_DIGITAL - .class = I2C_ADAP_CLASS_TV_DIGITAL, + av7110->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL; #else - .class = I2C_CLASS_TV_DIGITAL, + av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL; #endif - }; strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name)); saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ @@ -1567,6 +2035,9 @@ if (ret) goto err3; + av7110->dvb_adapter->priv = av7110; + frontend_init(av7110); + printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num); av7110->device_initialized = 1; av7110_num++; @@ -1663,33 +2134,29 @@ .ext_priv = x_name, \ .ext = &av7110_extension } -MAKE_AV7110_INFO(fs_1_5, "Siemens cable card PCI rev1.5"); -MAKE_AV7110_INFO(fs_1_3, "Siemens/Technotrend/Hauppauge PCI rev1.3"); -MAKE_AV7110_INFO(tt_1_6, "Technotrend/Hauppauge PCI rev1.3 or 1.6"); -MAKE_AV7110_INFO(tt_2_1, "Technotrend/Hauppauge PCI rev2.1 or 2.2"); -MAKE_AV7110_INFO(tt_t, "Technotrend/Hauppauge PCI DVB-T"); -MAKE_AV7110_INFO(unkwn0, "Technotrend/Hauppauge PCI rev?(unknown0)?"); -MAKE_AV7110_INFO(unkwn1, "Technotrend/Hauppauge PCI rev?(unknown1)?"); -MAKE_AV7110_INFO(unkwn2, "Technotrend/Hauppauge PCI rev?(unknown2)?"); -MAKE_AV7110_INFO(nexus, "Technotrend/Hauppauge Nexus PCI DVB-S"); -MAKE_AV7110_INFO(dvboc11,"Octal/Technotrend DVB-C for iTV"); +MAKE_AV7110_INFO(tts_1_X, "Technotrend/Hauppauge WinTV DVB-S rev1.X"); +MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X"); +MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X"); +MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X"); +MAKE_AV7110_INFO(tts_2_X, "Technotrend/Hauppauge WinTV Nexus-S rev2.X"); +MAKE_AV7110_INFO(tts_1_3se, "Technotrend/Hauppauge WinTV Nexus-S rev1.3"); +MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0xffff), - MAKE_EXTENSION_PCI(fs_1_5, 0x110a, 0x0000), - MAKE_EXTENSION_PCI(fs_1_3, 0x13c2, 0x0000), - MAKE_EXTENSION_PCI(unkwn0, 0x13c2, 0x1002), - MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0001), - MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0002), - MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0003), - MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x0004), - MAKE_EXTENSION_PCI(tt_1_6, 0x13c2, 0x0006), - MAKE_EXTENSION_PCI(tt_t, 0x13c2, 0x0008), - MAKE_EXTENSION_PCI(tt_2_1, 0x13c2, 0x1102), - MAKE_EXTENSION_PCI(unkwn1, 0xffc2, 0x0000), - MAKE_EXTENSION_PCI(unkwn2, 0x00a1, 0x00a1), - MAKE_EXTENSION_PCI(nexus, 0x00a1, 0xa1a0), - MAKE_EXTENSION_PCI(dvboc11,0x13c2, 0x000a), + MAKE_EXTENSION_PCI(tts_1_X, 0x13c2, 0x0000), + MAKE_EXTENSION_PCI(ttt_1_X, 0x13c2, 0x0001), + MAKE_EXTENSION_PCI(ttc_2_X, 0x13c2, 0x0002), + MAKE_EXTENSION_PCI(tts_2_X, 0x13c2, 0x0003), + MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002), + MAKE_EXTENSION_PCI(fsc, 0x110a, 0x0000), + MAKE_EXTENSION_PCI(ttc_1_X, 0x13c2, 0x000a), + +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0004), UNDEFINED CARD */ // Galaxis DVB PC-Sat-Carte +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1 +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0006), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-S v???? +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0008), UNDEFINED CARD */ // TT/Hauppauge WinTV DVB-T v???? +/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v???? + { .vendor = 0, } diff -Nru a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h --- a/drivers/media/dvb/ttpci/av7110.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/av7110.h 2004-12-12 17:40:52 -08:00 @@ -24,6 +24,13 @@ #include "dvb_filter.h" #include "dvb_net.h" #include "dvb_ringbuffer.h" +#include "dvb_frontend.h" +#include "ves1820.h" +#include "ves1x93.h" +#include "stv0299.h" +#include "tda8083.h" +#include "sp8870.h" +#include "stv0297.h" #include @@ -217,6 +224,17 @@ unsigned char *bin_root; unsigned long size_root; + + struct dvb_frontend* fe; + fe_status_t fe_status; + int (*fe_init)(struct dvb_frontend* fe); + int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); + int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); + int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); + int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); + int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); + int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); }; diff -Nru a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c --- a/drivers/media/dvb/ttpci/av7110_av.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/av7110_av.c 2004-12-12 17:40:52 -08:00 @@ -674,7 +674,7 @@ } -int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) +static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) { int i; int c = 0; @@ -936,7 +936,7 @@ return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); } -u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; +static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; #define MIN_IFRAME 400000 diff -Nru a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c --- a/drivers/media/dvb/ttpci/av7110_ca.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttpci/av7110_ca.c 2004-12-12 17:40:53 -08:00 @@ -89,20 +89,20 @@ * CI link layer file ops ******************************************************************************/ -int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size) +static int ci_ll_init(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf, int size) { dvb_ringbuffer_init(cirbuf, vmalloc(size), size); dvb_ringbuffer_init(ciwbuf, vmalloc(size), size); return 0; } -void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +static void ci_ll_flush(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) { dvb_ringbuffer_flush_spinlock_wakeup(cirbuf); dvb_ringbuffer_flush_spinlock_wakeup(ciwbuf); } -void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) +static void ci_ll_release(struct dvb_ringbuffer *cirbuf, struct dvb_ringbuffer *ciwbuf) { vfree(cirbuf->data); cirbuf->data = NULL; @@ -110,7 +110,7 @@ ciwbuf->data = NULL; } -int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, +static int ci_ll_reset(struct dvb_ringbuffer *cibuf, struct file *file, int slots, ca_slot_info_t *slot) { int i; diff -Nru a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c --- a/drivers/media/dvb/ttpci/av7110_hw.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttpci/av7110_hw.c 2004-12-12 17:40:53 -08:00 @@ -53,10 +53,14 @@ { struct saa7146_dev *dev = av7110->dev; - if (count <= 0 || count > 32764) + if (count <= 0 || count > 32764) { + printk("%s: invalid count %d\n", __FUNCTION__, count); return -1; - if (saa7146_wait_for_debi_done(av7110->dev) < 0) + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done failed\n", __FUNCTION__); return -1; + } saa7146_write(dev, DEBI_CONFIG, config); if (count <= 4) /* immediate transfer */ saa7146_write(dev, DEBI_AD, val); @@ -72,10 +76,14 @@ struct saa7146_dev *dev = av7110->dev; u32 result = 0; - if (count > 32764 || count <= 0) + if (count > 32764 || count <= 0) { + printk("%s: invalid count %d\n", __FUNCTION__, count); return 0; - if (saa7146_wait_for_debi_done(av7110->dev) < 0) + } + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #1 failed\n", __FUNCTION__); return 0; + } saa7146_write(dev, DEBI_AD, av7110->debi_bus); saa7146_write(dev, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); @@ -83,7 +91,11 @@ saa7146_write(dev, MC2, (2 << 16) | 2); if (count > 4) return count; - saa7146_wait_for_debi_done(av7110->dev); + if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) { + printk("%s: wait_for_debi_done #2 failed\n", __FUNCTION__); + return 0; + } + result = saa7146_read(dev, DEBI_AD); result &= (0xffffffffUL >> ((4 - count) * 8)); return result; @@ -240,7 +252,7 @@ mwdebi(av7110, DEBISWAB, DPRAM_BASE, bootcode, sizeof(bootcode)); iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - if (saa7146_wait_for_debi_done(av7110->dev)) { + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " "saa7146_wait_for_debi_done() timed out\n"); return -1; @@ -258,7 +270,7 @@ dprintk(1, "load dpram code\n"); mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); - if (saa7146_wait_for_debi_done(av7110->dev)) { + if (saa7146_wait_for_debi_done(av7110->dev, 1)) { printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); return -1; @@ -305,6 +317,8 @@ } } + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2); + #ifndef _NOHANDSHAKE start = jiffies; while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) { @@ -333,6 +347,8 @@ wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2); wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2); + + wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2); #ifdef COM_DEBUG start = jiffies; diff -Nru a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c --- a/drivers/media/dvb/ttpci/av7110_v4l.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/av7110_v4l.c 2004-12-12 17:40:52 -08:00 @@ -162,7 +162,7 @@ .capability = V4L2_AUDCAP_STEREO }; -int av7110_dvb_c_switch(struct saa7146_fh *fh) +static int av7110_dvb_c_switch(struct saa7146_fh *fh) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; @@ -227,7 +227,7 @@ return 0; } -int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { struct saa7146_dev *dev = fh->dev; struct av7110 *av7110 = (struct av7110*) dev->ext_priv; @@ -424,7 +424,7 @@ * INITIALIZATION ****************************************************************************/ -struct saa7146_extension_ioctls ioctls[] = { +static struct saa7146_extension_ioctls ioctls[] = { { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, @@ -684,7 +684,7 @@ .flags = 0, .stds = &standard[0], - .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), + .num_stds = ARRAY_SIZE(standard), .std_callback = &std_callback, .ioctls = &ioctls[0], @@ -698,7 +698,7 @@ .flags = SAA7146_USE_PORT_B_FOR_VBI, .stds = &standard[0], - .num_stds = sizeof(standard) / sizeof(struct saa7146_standard), + .num_stds = ARRAY_SIZE(standard), .std_callback = &std_callback, .ioctls = &ioctls[0], diff -Nru a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c --- a/drivers/media/dvb/ttpci/budget-av.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttpci/budget-av.c 2004-12-12 17:40:53 -08:00 @@ -4,6 +4,9 @@ * * Compiled from various sources by Michael Hunold * + * CI interface support (c) 2004 Olivier Gournet & + * Andrew de Quincey + * * Copyright (C) 2002 Ralph Metzler * * Copyright (C) 1999-2002 Ralph Metzler @@ -31,15 +34,34 @@ */ #include "budget.h" +#include "stv0299.h" +#include "tda10021.h" +#include "tda1004x.h" #include +#include +#include +#include +#include +#include +#include + +#include "dvb_ca_en50221.h" + +#define DEBICICAM 0x02420000 struct budget_av { struct budget budget; struct video_device *vd; int cur_input; int has_saa7113; + struct tasklet_struct ciintf_irq_tasklet; + int slot_status; + struct dvb_ca_en50221 ca; }; +int enable_ci = 0; + + /**************************************************************************** * INITIALIZATION ****************************************************************************/ @@ -55,8 +77,10 @@ msgs[1].flags = I2C_M_RD; msgs[0].addr = msgs[1].addr=id/2; mm1[0] = reg; - msgs[0].len = 1; msgs[1].len = 1; - msgs[0].buf = mm1; msgs[1].buf = mm2; + msgs[0].len = 1; + msgs[1].len = 1; + msgs[0].buf = mm1; + msgs[1].buf = mm2; i2c_transfer(i2c, msgs, 2); @@ -90,6 +114,211 @@ return i2c_transfer(i2c, &msgs, 1); } +static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 0); + + if (result == -ETIMEDOUT) + budget_av->slot_status = 0; + return result; +} + +static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI); + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 0); + + if (result == -ETIMEDOUT) + budget_av->slot_status = 0; + return result; +} + +static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); + + if (result == -ETIMEDOUT) + budget_av->slot_status = 0; + return result; +} + +static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + int result; + + if (slot != 0) + return -EINVAL; + + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); + + if (result == -ETIMEDOUT) + budget_av->slot_status = 0; + return result; +} + +static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_reset\n"); + + /* reset the card */ + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); + msleep(100); + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + msleep(2000); /* horrendous I know, but its the only way to be absolutely sure without an IRQ line! */ + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + return 0; +} + +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_shutdown\n"); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + budget_av->slot_status = 0; + return 0; +} + +static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + + if (slot != 0) + return -EINVAL; + + dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); + + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + return 0; +} + +static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct budget_av *budget_av = (struct budget_av *) ca->data; + struct saa7146_dev *saa = budget_av->budget.dev; + int cam = 0; + + if (slot != 0) + return -EINVAL; + + if (!budget_av->slot_status) { + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + udelay(1); + cam = saa7146_read(saa, PSR) & MASK_06; + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + + if (cam) + budget_av->slot_status = 1; + } else if (!open) { + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) + budget_av->slot_status = 0; + } + + if (budget_av->slot_status == 1) + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + + return 0; +} + +static int ciintf_init(struct budget_av *budget_av) +{ + struct saa7146_dev *saa = budget_av->budget.dev; + int result; + + memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221)); + + /* setup GPIOs */ + saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); + saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + + /* Reset the card */ + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); + msleep(50); + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + msleep(100); + + /* Enable DEBI pins */ + saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); + + /* register CI interface */ + budget_av->ca.owner = THIS_MODULE; + budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem; + budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem; + budget_av->ca.read_cam_control = ciintf_read_cam_control; + budget_av->ca.write_cam_control = ciintf_write_cam_control; + budget_av->ca.slot_reset = ciintf_slot_reset; + budget_av->ca.slot_shutdown = ciintf_slot_shutdown; + budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; + budget_av->ca.poll_slot_status = ciintf_poll_slot_status; + budget_av->ca.data = budget_av; + if ((result = dvb_ca_en50221_init(budget_av->budget.dvb_adapter, + &budget_av->ca, 0, 1)) != 0) { + printk("budget_av: CI interface detected, but initialisation failed.\n"); + goto error; + } + // success! + printk("ciintf_init: CI interface initialised\n"); + budget_av->budget.ci_present = 1; + return 0; + +error: + saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16)); + return result; +} + +static void ciintf_deinit(struct budget_av *budget_av) +{ + struct saa7146_dev *saa = budget_av->budget.dev; + + saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT); + saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); + + /* release the CA device */ + dvb_ca_en50221_release(&budget_av->ca); + + /* disable DEBI pins */ + saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16)); +} + static const u8 saa7113_tab[] = { 0x01, 0x08, @@ -165,6 +394,397 @@ } +static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + u8 m1; + + aclk = 0xb5; + if (srate < 2000000) + bclk = 0x86; + else if (srate < 5000000) + bclk = 0x89; + else if (srate < 15000000) + bclk = 0x8f; + else if (srate < 45000000) + bclk = 0x95; + + m1 = 0x14; + if (srate < 4000000) + m1 = 0x10; + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + stv0299_writereg(fe, 0x0f, 0x80 | m1); + + return 0; +} + +static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct budget_av *budget_av = (struct budget_av *) fe->dvb->priv; + u32 div; + u8 buf[4]; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + buf[3] = 0x20; + + if (params->u.qpsk.symbol_rate < 4000000) + buf[3] |= 1; + + if (params->frequency < 1250000) + buf[3] |= 0; + else if (params->frequency < 1550000) + buf[3] |= 0x40; + else if (params->frequency < 2050000) + buf[3] |= 0x80; + else if (params->frequency < 2150000) + buf[3] |= 0xC0; + + if (i2c_transfer(&budget_av->budget.i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static u8 typhoon_cinergy1200s_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x92, + 0xff, 0xff +}; + +static struct stv0299_config typhoon_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 0, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, + .pll_set = philips_su1278_ty_ci_pll_set, +}; + + +static struct stv0299_config cinergy_1200s_config = { + .demod_address = 0x68, + .inittab = typhoon_cinergy1200s_inittab, + .mclk = 88000000UL, + .invert = 0, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, + .pll_set = philips_su1278_ty_ci_pll_set, +}; + + +static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + u8 buf[4]; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; + +#define TUNER_MUL 62500 + + u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x8e; + buf[3] = (params->frequency < 174500000 ? 0xa1 : + params->frequency < 454000000 ? 0x92 : 0x34); + + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct tda10021_config philips_cu1216_config = { + .demod_address = 0x0c, + .pll_set = philips_cu1216_pll_set, +}; + + + + +static int philips_tu1216_pll_init(struct dvb_frontend *fe) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = + sizeof(tu1216_init) }; + + // setup PLL configuration + if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) { + i2c_transfer(&budget->i2c_adap, &tuner_msg, 1); + } + + return 0; +} + +static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len = + sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + // determine band + if (params->frequency < 49000000) + return -EINVAL; + else if (params->frequency < 159000000) + band = 1; + else if (params->frequency < 444000000) + band = 2; + else if (params->frequency < 861000000) + band = 4; + else + return -EINVAL; + + // setup PLL filter + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_write_byte(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + tda1004x_write_byte(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + tda1004x_write_byte(fe, 0x0C, 0xFF); + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tu1216_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct budget *budget = (struct budget *) fe->dvb->priv; + + return request_firmware(fw, name, &budget->dev->pci->dev); +} + +struct tda1004x_config philips_tu1216_config = { + + .demod_address = 0x8, + .invert = 1, + .pll_init = philips_tu1216_pll_init, + .pll_set = philips_tu1216_pll_set, + .request_firmware = philips_tu1216_request_firmware, +}; + + + + +static u8 read_pwm(struct budget_av *budget_av) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1}, + {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} + }; + + if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + + +static void frontend_init(struct budget_av *budget_av) +{ + switch (budget_av->budget.dev->pci->subsystem_device) { + case 0x4f56: // Typhoon/KNC1 DVB-S budget (stv0299/Philips SU1278(tsa5059)) + budget_av->budget.dvb_frontend = + stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap); + if (budget_av->budget.dvb_frontend != NULL) { + break; + } + break; + + case 0x0020: // KNC1 DVB-C budget (tda10021/Philips CU1216(tua6034)) + budget_av->budget.dvb_frontend = + tda10021_attach(&philips_cu1216_config, + &budget_av->budget.i2c_adap, read_pwm(budget_av)); + if (budget_av->budget.dvb_frontend != NULL) { + break; + } + break; + + case 0x0030: // KNC1 DVB-T budget (tda10046/Philips TU1216(tda6651tt)) + budget_av->budget.dvb_frontend = + tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap); + if (budget_av->budget.dvb_frontend != NULL) { + break; + } + break; + + case 0x1154: // TerraTec Cinergy 1200 DVB-S (stv0299/Philips SU1278(tsa5059)) + budget_av->budget.dvb_frontend = + stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap); + if (budget_av->budget.dvb_frontend != NULL) { + break; + } + break; + + case 0x1156: // Terratec Cinergy 1200 DVB-C (tda10021/Philips CU1216(tua6034)) + budget_av->budget.dvb_frontend = + tda10021_attach(&philips_cu1216_config, + &budget_av->budget.i2c_adap, read_pwm(budget_av)); + if (budget_av->budget.dvb_frontend) { + break; + } + break; + + case 0x1157: // Terratec Cinergy 1200 DVB-T (tda10046/Philips TU1216(tda6651tt)) + budget_av->budget.dvb_frontend = + tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap); + if (budget_av->budget.dvb_frontend) { + break; + } + break; + } + + if (budget_av->budget.dvb_frontend == NULL) { + printk("budget_av: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + budget_av->budget.dev->pci->vendor, + budget_av->budget.dev->pci->device, + budget_av->budget.dev->pci->subsystem_vendor, + budget_av->budget.dev->pci->subsystem_device); + } else { + if (dvb_register_frontend + (budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) { + printk("budget-av: Frontend registration failed!\n"); + if (budget_av->budget.dvb_frontend->ops->release) + budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend); + budget_av->budget.dvb_frontend = NULL; + } + } +} + + +static void budget_av_irq(struct saa7146_dev *dev, u32 * isr) +{ + struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; + + dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av); + + if (*isr & MASK_10) + ttpci_budget_irq10_handler(dev, isr); +} + static int budget_av_detach (struct saa7146_dev *dev) { struct budget_av *budget_av = (struct budget_av*) dev->ext_priv; @@ -180,6 +800,11 @@ saa7146_unregister_device (&budget_av->vd, dev); } + if (budget_av->budget.ci_present) + ciintf_deinit(budget_av); + + if (budget_av->budget.dvb_frontend != NULL) + dvb_unregister_frontend(budget_av->budget.dvb_frontend); err = ttpci_budget_deinit (&budget_av->budget); kfree (budget_av); @@ -189,28 +814,24 @@ static struct saa7146_ext_vv vv_data; -static int budget_av_attach (struct saa7146_dev* dev, - struct saa7146_pci_extension_data *info) +static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) { struct budget_av *budget_av; - struct budget_info *bi = info->ext_priv; u8 *mac; int err; dprintk(2, "dev: %p\n", dev); - if (bi->type != BUDGET_KNC1 && bi->type != BUDGET_CIN1200) { - return -ENODEV; - } - if (!(budget_av = kmalloc(sizeof(struct budget_av), GFP_KERNEL))) return -ENOMEM; memset(budget_av, 0, sizeof(struct budget_av)); + budget_av->budget.ci_present = 0; + dev->ext_priv = budget_av; - if ((err = ttpci_budget_init(&budget_av->budget, dev, info))) { + if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) { kfree(budget_av); return err; } @@ -220,8 +841,6 @@ saa7146_write(dev, DD1_INIT, 0x07000600); saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26); - //test_knc_ci(av7110); - saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTHI); msleep(500); @@ -234,9 +853,7 @@ return err; } - if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", - VFL_TYPE_GRABBER))) - { + if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { /* fixme: proper cleanup here */ ERR(("cannot register capture v4l2 device.\n")); return err; @@ -261,15 +878,20 @@ printk("KNC1-%d: Could not read MAC from KNC1 card\n", budget_av->budget.dvb_adapter->num); memset(mac, 0, 6); - } - else + } else { printk("KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", budget_av->budget.dvb_adapter->num, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - return 0; } + budget_av->budget.dvb_adapter->priv = budget_av; + frontend_init(budget_av); + + if (enable_ci) + ciintf_init(budget_av); + return 0; +} #define KNC1_INPUTS 2 static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { @@ -290,12 +912,9 @@ { struct saa7146_dev *dev = fh->dev; struct budget_av *budget_av = (struct budget_av*) dev->ext_priv; -/* - struct saa7146_vv *vv = dev->vv_data; -*/ + switch(cmd) { - case VIDIOC_ENUMINPUT: - { + case VIDIOC_ENUMINPUT:{ struct v4l2_input *i = arg; dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); @@ -305,8 +924,7 @@ memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); return 0; } - case VIDIOC_G_INPUT: - { + case VIDIOC_G_INPUT:{ int *input = (int *)arg; *input = budget_av->cur_input; @@ -314,8 +932,7 @@ dprintk(1, "VIDIOC_G_INPUT %d.\n", *input); return 0; } - case VIDIOC_S_INPUT: - { + case VIDIOC_S_INPUT:{ int input = *(int *)arg; dprintk(1, "VIDIOC_S_INPUT %d.\n", input); return saa7113_setinput (budget_av, input); @@ -327,17 +944,15 @@ } static struct saa7146_standard standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL, + {.name = "PAL",.id = V4L2_STD_PAL, .v_offset = 0x17, .v_field = 288, .h_offset = 0x14, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768 - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, + .v_max_out = 576,.h_max_out = 768 }, + + {.name = "NTSC",.id = V4L2_STD_NTSC, .v_offset = 0x16, .v_field = 240, .h_offset = 0x06, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - } + .v_max_out = 480,.h_max_out = 640, }, }; static struct saa7146_ext_vv vv_data = { @@ -350,17 +965,22 @@ .ioctl = av_ioctl, }; - - static struct saa7146_extension budget_extension; - -MAKE_BUDGET_INFO(knc1, "KNC1 DVB-S", BUDGET_KNC1); -MAKE_BUDGET_INFO(cin1200, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200); +MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S); +MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); +MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); +MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S); +MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C); +MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T); static struct pci_device_id pci_tbl [] = { - MAKE_EXTENSION_PCI(knc1, 0x1131, 0x4f56), - MAKE_EXTENSION_PCI(cin1200, 0x153b, 0x1154), + MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56), + MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), + MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), + MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154), + MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156), + MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157), { .vendor = 0, } @@ -377,7 +997,7 @@ .detach = budget_av_detach, .irq_mask = MASK_10, - .irq_func = ttpci_budget_irq10_handler, + .irq_func = budget_av_irq, }; static int __init budget_av_init(void) @@ -396,5 +1016,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB w/ analog input (e.g. the KNC cards)"); - + "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); +module_param_named(enable_ci, enable_ci, int, 0644); +MODULE_PARM_DESC(enable_ci, "Turn on/off CI module (default:off)."); diff -Nru a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c --- a/drivers/media/dvb/ttpci/budget-ci.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/budget-ci.c 2004-12-12 17:40:52 -08:00 @@ -39,6 +39,8 @@ #include #include "dvb_ca_en50221.h" +#include "stv0299.h" +#include "tda1004x.h" #define DEBIADDR_IR 0x1234 #define DEBIADDR_CICONTROL 0x0000 @@ -64,72 +66,11 @@ struct input_dev input_dev; struct tasklet_struct msp430_irq_tasklet; struct tasklet_struct ciintf_irq_tasklet; - spinlock_t debilock; int slot_status; struct dvb_ca_en50221 ca; char ir_dev_name[50]; }; -static u32 budget_debiread (struct budget_ci* budget_ci, u32 config, int addr, int count) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - u32 result = 0; - unsigned long flags; - - if (count > 4 || count <= 0) - return 0; - - spin_lock_irqsave(&budget_ci->debilock, flags); - - if (saa7146_wait_for_debi_done(saa) < 0) { - spin_unlock_irqrestore(&budget_ci->debilock, flags); - return 0; - } - - saa7146_write (saa, DEBI_COMMAND, - (count << 17) | 0x10000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, MC2, (2 << 16) | 2); - - saa7146_wait_for_debi_done(saa); - - result = saa7146_read(saa, 0x88); - result &= (0xffffffffUL >> ((4 - count) * 8)); - - spin_unlock_irqrestore(&budget_ci->debilock, flags); - return result; -} - -static u8 budget_debiwrite (struct budget_ci* budget_ci, u32 config, int addr, int count, u32 value) -{ - struct saa7146_dev *saa = budget_ci->budget.dev; - unsigned long flags; - - if (count > 4 || count <= 0) - return 0; - - spin_lock_irqsave(&budget_ci->debilock, flags); - - if (saa7146_wait_for_debi_done(saa) < 0) { - spin_unlock_irqrestore(&budget_ci->debilock, flags); - return 0; - } - - saa7146_write (saa, DEBI_COMMAND, - (count << 17) | 0x00000 | (addr & 0xffff)); - saa7146_write(saa, DEBI_CONFIG, config); - saa7146_write(saa, DEBI_PAGE, 0); - saa7146_write(saa, DEBI_AD, value); - saa7146_write(saa, MC2, (2 << 16) | 2); - - saa7146_wait_for_debi_done(saa); - - spin_unlock_irqrestore(&budget_ci->debilock, flags); - return 0; -} - - /* from reading the following remotes: Zenith Universal 7 / TV Mode 807 / VCR Mode 837 Hauppauge (from NOVA-CI-s box product) @@ -206,7 +147,8 @@ { struct budget_ci *budget_ci = (struct budget_ci*) data; struct input_dev *dev = &budget_ci->input_dev; - unsigned int code = budget_debiread(budget_ci, DEBINOSWAP, DEBIADDR_IR, 2) >> 8; + unsigned int code = + ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; if (code & 0x40) { code &= 0x3f; @@ -221,8 +163,7 @@ } if (!key_map[code]) { - printk ("DVB (%s): no key for %02x!\n", - __FUNCTION__, code); + printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code); return; } @@ -281,79 +222,98 @@ input_unregister_device(dev); } -static int ciintf_read_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address) { +static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) +{ struct budget_ci* budget_ci = (struct budget_ci*) ca->data; - if (slot != 0) return -EINVAL; + if (slot != 0) + return -EINVAL; - return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1); + return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, + DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0); } -static int ciintf_write_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address, u8 value) { +static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) +{ struct budget_ci* budget_ci = (struct budget_ci*) ca->data; - if (slot != 0) return -EINVAL; + if (slot != 0) + return -EINVAL; - return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1, value); + return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, + DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0); } -static int ciintf_read_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address) { +static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) +{ struct budget_ci* budget_ci = (struct budget_ci*) ca->data; - if (slot != 0) return -EINVAL; + if (slot != 0) + return -EINVAL; - return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1); + return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM, + DEBIADDR_IO | (address & 3), 1, 1, 0); } -static int ciintf_write_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value) { +static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) +{ struct budget_ci* budget_ci = (struct budget_ci*) ca->data; - if (slot != 0) return -EINVAL; + if (slot != 0) + return -EINVAL; - return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1, value); + return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM, + DEBIADDR_IO | (address & 3), 1, value, 1, 0); } -static int ciintf_slot_reset(struct dvb_ca_en50221* ca, int slot) { +static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ struct budget_ci* budget_ci = (struct budget_ci*) ca->data; struct saa7146_dev *saa = budget_ci->budget.dev; - if (slot != 0) return -EINVAL; + if (slot != 0) + return -EINVAL; // trigger on RISING edge during reset so we know when READY is re-asserted saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); budget_ci->slot_status = SLOTSTATUS_RESET; - budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); msleep(1); - budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); return 0; } -static int ciintf_slot_shutdown(struct dvb_ca_en50221* ca, int slot) { +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ struct budget_ci* budget_ci = (struct budget_ci*) ca->data; struct saa7146_dev *saa = budget_ci->budget.dev; - if (slot != 0) return -EINVAL; + if (slot != 0) + return -EINVAL; saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); return 0; } -static int ciintf_slot_ts_enable(struct dvb_ca_en50221* ca, int slot) { +static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ struct budget_ci* budget_ci = (struct budget_ci*) ca->data; struct saa7146_dev *saa = budget_ci->budget.dev; int tmp; - if (slot != 0) return -EINVAL; - + if (slot != 0) + return -EINVAL; saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO); - tmp = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1); - budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, tmp | CICONTROL_ENABLETS); + tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + tmp | CICONTROL_ENABLETS, 1, 0); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); return 0; @@ -367,10 +327,11 @@ unsigned int flags; // ensure we don't get spurious IRQs during initialisation - if (!budget_ci->budget.ci_present) return; + if (!budget_ci->budget.ci_present) + return; // read the CAM status - flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1); + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); if (flags & CICONTROL_CAMDETECT) { // GPIO should be set to trigger on falling edge if a CAM is present @@ -379,7 +340,8 @@ if (budget_ci->slot_status & SLOTSTATUS_NONE) { // CAM insertion IRQ budget_ci->slot_status = SLOTSTATUS_PRESENT; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_INSERTED); + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { // CAM ready (reset completed) @@ -401,7 +363,8 @@ if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { // CAM removal IRQ budget_ci->slot_status = SLOTSTATUS_NONE; - dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_REMOVED); + dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); } } } @@ -418,18 +381,18 @@ saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800); // test if it is there - if ((budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CIVERSION, 1) & 0xa0) != 0xa0) { + if ((ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0) & 0xa0) != 0xa0) { result = -ENODEV; goto error; } - // determine whether a CAM is present or not - flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1); + flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0); budget_ci->slot_status = SLOTSTATUS_NONE; - if (flags & CICONTROL_CAMDETECT) budget_ci->slot_status = SLOTSTATUS_PRESENT; - + if (flags & CICONTROL_CAMDETECT) + budget_ci->slot_status = SLOTSTATUS_PRESENT; // register CI interface + budget_ci->ca.owner = THIS_MODULE; budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; budget_ci->ca.read_cam_control = ciintf_read_cam_control; @@ -442,8 +405,7 @@ &budget_ci->ca, DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | DVB_CA_EN50221_FLAG_IRQ_FR | - DVB_CA_EN50221_FLAG_IRQ_DA, - 1)) != 0) { + DVB_CA_EN50221_FLAG_IRQ_DA, 1)) != 0) { printk("budget_ci: CI interface detected, but initialisation failed.\n"); goto error; } @@ -456,7 +418,8 @@ saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI); } saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03); - budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); // success! printk("budget_ci: CI interface initialised\n"); @@ -464,7 +427,8 @@ // forge a fake CI IRQ so the CAM state is setup correctly flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; - if (budget_ci->slot_status != SLOTSTATUS_NONE) flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; + if (budget_ci->slot_status != SLOTSTATUS_NONE) + flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags); return 0; @@ -482,9 +446,10 @@ saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03); saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); tasklet_kill(&budget_ci->ciintf_irq_tasklet); - budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0); msleep(1); - budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET); + ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, + CICONTROL_RESET, 1, 0); // disable TS data stream to CI interface saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT); @@ -513,9 +478,425 @@ } +static u8 alps_bsru6_inittab[] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x52, + 0xff, 0xff +}; + +static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + buf[3] = 0xC4; + + if (params->frequency > 1530000) + buf[3] = 0xc0; + + if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct stv0299_config alps_bsru6_config = { + + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, + .pll_set = alps_bsru6_pll_set, +}; + + + + +static u8 philips_su1278_tt_inittab[] = { + 0x01, 0x0f, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x5b, + 0x05, 0x85, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0x02, + 0x09, 0x00, + 0x0C, 0x01, + 0x0D, 0x81, + 0x0E, 0x44, + 0x0f, 0x14, + 0x10, 0x3c, + 0x11, 0x84, + 0x12, 0xda, + 0x13, 0x97, + 0x14, 0x95, + 0x15, 0xc9, + 0x16, 0x19, + 0x17, 0x8c, + 0x18, 0x59, + 0x19, 0xf8, + 0x1a, 0xfe, + 0x1c, 0x7f, + 0x1d, 0x00, + 0x1e, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x09, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x93, + 0xff, 0xff +}; -static int budget_ci_attach (struct saa7146_dev* dev, - struct saa7146_pci_extension_data *info) +static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) +{ + stv0299_writereg(fe, 0x0e, 0x44); + if (srate >= 10000000) { + stv0299_writereg(fe, 0x13, 0x97); + stv0299_writereg(fe, 0x14, 0x95); + stv0299_writereg(fe, 0x15, 0xc9); + stv0299_writereg(fe, 0x17, 0x8c); + stv0299_writereg(fe, 0x1a, 0xfe); + stv0299_writereg(fe, 0x1c, 0x7f); + stv0299_writereg(fe, 0x2d, 0x09); + } else { + stv0299_writereg(fe, 0x13, 0x99); + stv0299_writereg(fe, 0x14, 0x8d); + stv0299_writereg(fe, 0x15, 0xce); + stv0299_writereg(fe, 0x17, 0x43); + stv0299_writereg(fe, 0x1a, 0x1d); + stv0299_writereg(fe, 0x1c, 0x12); + stv0299_writereg(fe, 0x2d, 0x05); + } + stv0299_writereg(fe, 0x0e, 0x23); + stv0299_writereg(fe, 0x0f, 0x94); + stv0299_writereg(fe, 0x10, 0x39); + stv0299_writereg(fe, 0x15, 0xc9); + + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, (ratio) & 0xf0); + + return 0; +} + +static int philips_su1278_tt_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u32 div; + u8 buf[4]; + struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (500 - 1)) / 500; // round correctly + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; + buf[3] = 0x20; + + if (params->u.qpsk.symbol_rate < 4000000) + buf[3] |= 1; + + if (params->frequency < 1250000) + buf[3] |= 0; + else if (params->frequency < 1550000) + buf[3] |= 0x40; + else if (params->frequency < 2050000) + buf[3] |= 0x80; + else if (params->frequency < 2150000) + buf[3] |= 0xC0; + + if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static struct stv0299_config philips_su1278_tt_config = { + + .demod_address = 0x68, + .inittab = philips_su1278_tt_inittab, + .mclk = 64000000UL, + .invert = 0, + .enhanced_tuning = 1, + .skip_reinit = 1, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 50, + .set_symbol_rate = philips_su1278_tt_set_symbol_rate, + .pll_set = philips_su1278_tt_pll_set, +}; + + + +static int philips_tdm1316l_pll_init(struct dvb_frontend *fe) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = td1316_init,.len = + sizeof(td1316_init) }; + + // setup PLL configuration + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { + i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); + } + + return 0; +} + +static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) + return -EINVAL; + else if (tuner_frequency < 130000000) + cp = 3; + else if (tuner_frequency < 160000000) + cp = 5; + else if (tuner_frequency < 200000000) + cp = 6; + else if (tuner_frequency < 290000000) + cp = 3; + else if (tuner_frequency < 420000000) + cp = 5; + else if (tuner_frequency < 480000000) + cp = 6; + else if (tuner_frequency < 620000000) + cp = 3; + else if (tuner_frequency < 830000000) + cp = 5; + else if (tuner_frequency < 895000000) + cp = 7; + else + return -EINVAL; + + // determine band + if (params->frequency < 49000000) + return -EINVAL; + else if (params->frequency < 159000000) + band = 1; + else if (params->frequency < 444000000) + band = 2; + else if (params->frequency < 861000000) + band = 4; + else + return -EINVAL; + + // setup PLL filter and TDA9889 + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_write_byte(fe, 0x0C, 0x14); + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + tda1004x_write_byte(fe, 0x0C, 0x80); + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + tda1004x_write_byte(fe, 0x0C, 0x14); + filter = 1; + break; + + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) + return -EIO; + + msleep(1); + return 0; +} + +static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, char *name) +{ + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; + + return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); +} + +static struct tda1004x_config philips_tdm1316l_config = { + + .demod_address = 0x8, + .invert = 0, + .pll_init = philips_tdm1316l_pll_init, + .pll_set = philips_tdm1316l_pll_set, + .request_firmware = philips_tdm1316l_request_firmware, +}; + + + +static void frontend_init(struct budget_ci *budget_ci) +{ + switch (budget_ci->budget.dev->pci->subsystem_device) { + case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) + budget_ci->budget.dvb_frontend = + stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + break; + } + break; + + case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) + budget_ci->budget.dvb_frontend = + stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + break; + } + break; + + case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) + budget_ci->budget.dvb_frontend = + tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); + if (budget_ci->budget.dvb_frontend) { + break; + } + break; + } + + if (budget_ci->budget.dvb_frontend == NULL) { + printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + budget_ci->budget.dev->pci->vendor, + budget_ci->budget.dev->pci->device, + budget_ci->budget.dev->pci->subsystem_vendor, + budget_ci->budget.dev->pci->subsystem_device); + } else { + if (dvb_register_frontend + (budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { + printk("budget-ci: Frontend registration failed!\n"); + if (budget_ci->budget.dvb_frontend->ops->release) + budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend); + budget_ci->budget.dvb_frontend = NULL; + } + } +} + +static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) { struct budget_ci *budget_ci; int err; @@ -525,12 +906,11 @@ dprintk(2, "budget_ci: %p\n", budget_ci); - spin_lock_init(&budget_ci->debilock); budget_ci->budget.ci_present = 0; dev->ext_priv = budget_ci; - if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) { + if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) { kfree (budget_ci); return err; } @@ -542,6 +922,9 @@ ciintf_init(budget_ci); + budget_ci->budget.dvb_adapter->priv = budget_ci; + frontend_init(budget_ci); + return 0; } @@ -553,8 +936,10 @@ struct saa7146_dev *saa = budget_ci->budget.dev; int err; - if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci); - + if (budget_ci->budget.ci_present) + ciintf_deinit(budget_ci); + if (budget_ci->budget.dvb_frontend) + dvb_unregister_frontend(budget_ci->budget.dvb_frontend); err = ttpci_budget_deinit (&budget_ci->budget); tasklet_kill (&budget_ci->msp430_irq_tasklet); diff -Nru a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c --- a/drivers/media/dvb/ttpci/budget-core.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/budget-core.c 2004-12-12 17:40:52 -08:00 @@ -74,8 +74,7 @@ memset(budget->grabbing, 0x00, TS_HEIGHT*TS_WIDTH); - saa7146_write(dev, PCI_BT_V1, 0x001c0000 | - (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); budget->tsf=0xff; budget->ttbp=0; @@ -150,14 +149,87 @@ return; if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ - dvb_dmx_swfilter_packets(&budget->demux, - mem+olddma, (newdma-olddma) / 188); + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (newdma - olddma) / 188); } else { /* wraparound, dump olddma..buflen and 0..newdma */ - dvb_dmx_swfilter_packets(&budget->demux, - mem+olddma, (TS_BUFLEN-olddma) / 188); - dvb_dmx_swfilter_packets(&budget->demux, - mem, newdma / 188); + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); + } } + + +int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + int result = 0; + unsigned long flags = 0; + + if (count > 4 || count <= 0) + return 0; + + if (uselocks) + spin_lock_irqsave(&budget->debilock, flags); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff)); + saa7146_write(saa, DEBI_CONFIG, config); + saa7146_write(saa, DEBI_PAGE, 0); + saa7146_write(saa, MC2, (2 << 16) | 2); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + result = saa7146_read(saa, DEBI_AD); + result &= (0xffffffffUL >> ((4 - count) * 8)); + + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + + return result; +} + +int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, + int count, u32 value, int uselocks, int nobusyloop) +{ + struct saa7146_dev *saa = budget->dev; + unsigned long flags = 0; + int result; + + if (count > 4 || count <= 0) + return 0; + + if (uselocks) + spin_lock_irqsave(&budget->debilock, flags); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff)); + saa7146_write(saa, DEBI_CONFIG, config); + saa7146_write(saa, DEBI_PAGE, 0); + saa7146_write(saa, DEBI_AD, value); + saa7146_write(saa, MC2, (2 << 16) | 2); + + if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) { + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return result; + } + + if (uselocks) + spin_unlock_irqrestore(&budget->debilock, flags); + return 0; } @@ -231,13 +303,11 @@ return ret; budget->mem_frontend.source = DMX_MEMORY_FE; - ret=dvbdemux->dmx.add_frontend (&dvbdemux->dmx, - &budget->mem_frontend); + ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend); if (ret<0) return ret; - ret=dvbdemux->dmx.connect_frontend (&dvbdemux->dmx, - &budget->hw_frontend); + ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend); if (ret < 0) return ret; @@ -263,30 +333,9 @@ dvb_dmx_release(&budget->demux); } -/* fixme: can this be unified among all saa7146 based dvb cards? */ -static int client_register(struct i2c_client *client) -{ - struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter); - struct budget *budget = (struct budget*)dev->ext_priv; - - if (client->driver->command) - return client->driver->command(client, FE_REGISTER, budget->dvb_adapter); - return 0; -} - -static int client_unregister(struct i2c_client *client) -{ - struct saa7146_dev *dev = (struct saa7146_dev*)i2c_get_adapdata(client->adapter); - struct budget *budget = (struct budget*)dev->ext_priv; - - if (client->driver->command) - return client->driver->command(client, FE_UNREGISTER, budget->dvb_adapter); - return 0; -} - -int ttpci_budget_init (struct budget *budget, - struct saa7146_dev* dev, - struct saa7146_pci_extension_data *info) +int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, + struct saa7146_pci_extension_data *info, + struct module *owner) { int length = TS_WIDTH*TS_HEIGHT; int ret = 0; @@ -299,7 +348,7 @@ budget->card = bi; budget->dev = (struct saa7146_dev *) dev; - dvb_register_adapter(&budget->dvb_adapter, budget->card->name, THIS_MODULE); + dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner); /* set dd1 stream a & b */ saa7146_write(dev, DD1_STREAM_B, 0x00000000); @@ -313,21 +362,18 @@ else budget->video_port = BUDGET_VIDEO_PORTA; spin_lock_init(&budget->feedlock); + spin_lock_init(&budget->debilock); /* the Siemens DVB needs this if you want to have the i2c chips get recognized before the main driver is loaded */ if (bi->type != BUDGET_FS_ACTIVY) saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */ - budget->i2c_adap = (struct i2c_adapter) { - .client_register = client_register, - .client_unregister = client_unregister, #ifdef I2C_ADAP_CLASS_TV_DIGITAL - .class = I2C_ADAP_CLASS_TV_DIGITAL, + budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL; #else - .class = I2C_CLASS_TV_DIGITAL, + budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL; #endif - }; strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name)); @@ -341,7 +387,8 @@ ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter->proposed_mac); - if( NULL == (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci,length,&budget->pt))) { + if (NULL == + (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) { ret = -ENOMEM; goto err; } @@ -420,8 +467,8 @@ spin_unlock(&budget->feedlock); } - - +EXPORT_SYMBOL_GPL(ttpci_budget_debiread); +EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite); EXPORT_SYMBOL_GPL(ttpci_budget_init); EXPORT_SYMBOL_GPL(ttpci_budget_deinit); EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); diff -Nru a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c --- a/drivers/media/dvb/ttpci/budget-patch.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/budget-patch.c 2004-12-12 17:40:52 -08:00 @@ -33,6 +33,9 @@ #include "av7110.h" #include "av7110_hw.h" #include "budget.h" +#include "stv0299.h" +#include "ves1x93.h" +#include "tda8083.h" #define budget_patch budget @@ -121,16 +124,11 @@ return 0; } - -int budget_patch_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - struct budget_patch *budget = fe->before_after_data; - - dprintk(2, "budget: %p\n", budget); + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; - switch (cmd) { - case FE_SET_TONE: - switch ((fe_sec_tone_mode_t) arg) { + switch (tone) { case SEC_TONE_ON: av7110_set22k (budget, 1); break; @@ -140,27 +138,232 @@ default: return -EINVAL; } - break; - case FE_DISEQC_SEND_MASTER_CMD: + return 0; +} + +static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) { - struct dvb_diseqc_master_cmd *cmd = arg; + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); - break; + + return 0; } - case FE_DISEQC_SEND_BURST: - av7110_send_diseqc_msg (budget, 0, NULL, (int) (long) arg); - break; +static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + + av7110_send_diseqc_msg (budget, 0, NULL, minicmd); - default: - return -EOPNOTSUPP; + return 0; } +static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (params->frequency + 479500) / 125; + + if (params->frequency > 2000000) pwr = 3; + else if (params->frequency > 1800000) pwr = 2; + else if (params->frequency > 1600000) pwr = 1; + else if (params->frequency > 1200000) pwr = 0; + else if (params->frequency >= 1100000) pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; + + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, + .pll_set = alps_bsrv2_pll_set, +}; + +static u8 alps_bsru6_inittab[] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x52, + 0xff, 0xff +}; + +static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); + return 0; } +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + data[3] = 0xC4; + + if (params->frequency > 1530000) data[3] = 0xc0; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct stv0299_config alps_bsru6_config = { + + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, + .pll_set = alps_bsru6_pll_set, +}; + +static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, + .pll_set = grundig_29504_451_pll_set, +}; + +static void frontend_init(struct budget_patch* budget) +{ + switch(budget->dev->pci->subsystem_device) { + case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + + // try the ALPS BSRV2 first of all + budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; + budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst; + budget->dvb_frontend->ops->set_tone = budget_patch_set_tone; + break; + } + + // try the ALPS BSRU6 now + budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; + budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst; + budget->dvb_frontend->ops->set_tone = budget_patch_set_tone; + break; + } + + // Try the grundig 29504-451 + budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; + budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst; + budget->dvb_frontend->ops->set_tone = budget_patch_set_tone; + break; + } + break; + } + + if (budget->dvb_frontend == NULL) { + printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + budget->dev->pci->vendor, + budget->dev->pci->device, + budget->dev->pci->subsystem_vendor, + budget->dev->pci->subsystem_device); + } else { + if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) { + printk("budget-av: Frontend registration failed!\n"); + if (budget->dvb_frontend->ops->release) + budget->dvb_frontend->ops->release(budget->dvb_frontend); + budget->dvb_frontend = NULL; + } + } +} static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) { @@ -173,7 +376,7 @@ dprintk(2, "budget: %p\n", budget); - if ((err = ttpci_budget_init (budget, dev, info))) { + if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { kfree (budget); return err; } @@ -221,11 +424,11 @@ // Enable RPS1 (rFC p33) saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - dvb_add_frontend_ioctls (budget->dvb_adapter, - budget_patch_diseqc_ioctl, NULL, budget); - dev->ext_priv = budget; + budget->dvb_adapter->priv = budget; + frontend_init(budget); + return 0; } @@ -235,8 +438,7 @@ struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; int err; - dvb_remove_frontend_ioctls (budget->dvb_adapter, - budget_patch_diseqc_ioctl, NULL); + if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend); err = ttpci_budget_deinit (budget); diff -Nru a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c --- a/drivers/media/dvb/ttpci/budget.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttpci/budget.c 2004-12-12 17:40:52 -08:00 @@ -35,6 +35,11 @@ */ #include "budget.h" +#include "stv0299.h" +#include "ves1x93.h" +#include "ves1820.h" +#include "l64781.h" +#include "tda8083.h" static void Set22K (struct budget *budget, int state) { @@ -105,89 +110,368 @@ return 0; } - -int budget_diseqc_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +/* + * Routines for the Fujitsu Siemens Activy budget card + * 22 kHz tone and DiSEqC are handled by the frontend. + * Voltage must be set here. + */ +static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) { - struct budget *budget = fe->before_after_data; + struct saa7146_dev *dev=budget->dev; dprintk(2, "budget: %p\n", budget); - switch (cmd) { - case FE_SET_TONE: - switch ((fe_sec_tone_mode_t) arg) { + switch (voltage) { + case SEC_VOLTAGE_13: + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); + break; + case SEC_VOLTAGE_18: + saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + return SetVoltage_Activy (budget, voltage); +} + +static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + switch (tone) { case SEC_TONE_ON: Set22K (budget, 1); break; case SEC_TONE_OFF: Set22K (budget, 0); break; + default: return -EINVAL; - }; - break; + } + + return 0; +} - case FE_DISEQC_SEND_MASTER_CMD: +static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) { - struct dvb_diseqc_master_cmd *cmd = arg; + struct budget* budget = (struct budget*) fe->dvb->priv; SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); - break; + + return 0; } - case FE_DISEQC_SEND_BURST: - SendDiSEqCMsg (budget, 0, NULL, (unsigned long)arg); - break; - - default: - return -EOPNOTSUPP; - }; +static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + + SendDiSEqCMsg (budget, 0, NULL, minicmd); return 0; } +static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 pwr = 0; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + u32 div = (params->frequency + 479500) / 125; + + if (params->frequency > 2000000) pwr = 3; + else if (params->frequency > 1800000) pwr = 2; + else if (params->frequency > 1600000) pwr = 1; + else if (params->frequency > 1200000) pwr = 0; + else if (params->frequency >= 1100000) pwr = 1; + else pwr = 2; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = ((div & 0x18000) >> 10) | 0x95; + buf[3] = (pwr << 6) | 0x30; -/* - * Routines for the Fujitsu Siemens Activy budget card - * 22 kHz tone and DiSEqC are handled by the frontend. - * Voltage must be set here. - */ -static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) + // NOTE: since we're using a prescaler of 2, we set the + // divisor frequency to 62.5kHz and divide by 125 above + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} + +static struct ves1x93_config alps_bsrv2_config = { - struct saa7146_dev *dev=budget->dev; + .demod_address = 0x08, + .xin = 90100000UL, + .invert_pwm = 0, + .pll_set = alps_bsrv2_pll_set, +}; + +static u8 alps_bsru6_inittab[] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x52, + 0xff, 0xff +}; - dprintk(2, "budget: %p\n", budget); +static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; - switch (voltage) { - case SEC_VOLTAGE_13: - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); - break; - case SEC_VOLTAGE_18: - saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); - break; - default: - return -EINVAL; + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); + + return 0; } +static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + data[3] = 0xC4; + + if (params->frequency > 1530000) data[3] = 0xc0; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } +static struct stv0299_config alps_bsru6_config = { -static int budget_ioctl_activy (struct dvb_frontend *fe, unsigned int cmd, void *arg) + .demod_address = 0x68, + .inittab = alps_bsru6_inittab, + .mclk = 88000000UL, + .invert = 1, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, + .pll_set = alps_bsru6_pll_set, +}; + +static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { - struct budget *budget = fe->before_after_data; + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (params->frequency + 35937500 + 31250) / 62500; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85 | ((div >> 10) & 0x60); + data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); - dprintk(2, "budget: %p\n", budget); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; +} - switch (cmd) { - case FE_SET_VOLTAGE: - return SetVoltage_Activy (budget, (fe_sec_voltage_t) arg); - default: - return -EOPNOTSUPP; +static struct ves1820_config alps_tdbe2_config = { + .demod_address = 0x09, + .xin = 57840000UL, + .invert = 1, + .selagc = VES1820_SELAGC_SIGNAMPERR, + .pll_set = alps_tdbe2_pll_set, +}; + +static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 cfg, cpump, band_select; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36125000 + params->frequency) / 166666; + + cfg = 0x88; + + if (params->frequency < 175000000) cpump = 2; + else if (params->frequency < 390000000) cpump = 1; + else if (params->frequency < 470000000) cpump = 2; + else if (params->frequency < 750000000) cpump = 1; + else cpump = 3; + + if (params->frequency < 175000000) band_select = 0x0e; + else if (params->frequency < 470000000) band_select = 0x05; + else band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = (cpump << 6) | band_select; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + return 0; } +static struct l64781_config grundig_29504_401_config = { + .demod_address = 0x55, + .pll_set = grundig_29504_401_pll_set, +}; + +static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; + u32 div; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = params->frequency / 125; + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x8e; + data[3] = 0x00; + + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } +static struct tda8083_config grundig_29504_451_config = { + .demod_address = 0x68, + .pll_set = grundig_29504_451_pll_set, +}; + +static u8 read_pwm(struct budget* budget) +{ + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, + { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; + + if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static void frontend_init(struct budget *budget) +{ + switch(budget->dev->pci->subsystem_device) { + case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) + + // try the ALPS BSRV2 first of all + budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops->set_tone = budget_set_tone; + break; + } + + // try the ALPS BSRU6 now + budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops->set_tone = budget_set_tone; + break; + } + break; + + case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) + + budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); + if (budget->dvb_frontend) break; + break; + + case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) + + budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap); + if (budget->dvb_frontend) break; + break; + + case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI (tda8083/Grundig 29504-451(tsa5522)) + + // grundig 29504-451 + budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; + break; + } + break; + } + + if (budget->dvb_frontend == NULL) { + printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + budget->dev->pci->vendor, + budget->dev->pci->device, + budget->dev->pci->subsystem_vendor, + budget->dev->pci->subsystem_device); + } else { + if (dvb_register_frontend(budget->dvb_adapter, budget->dvb_frontend)) { + printk("budget: Frontend registration failed!\n"); + if (budget->dvb_frontend->ops->release) + budget->dvb_frontend->ops->release(budget->dvb_frontend); + budget->dvb_frontend = NULL; + } + } +} static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) { @@ -203,18 +487,14 @@ dev->ext_priv = budget; - if ((err = ttpci_budget_init (budget, dev, info))) { + if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { printk("==> failed\n"); kfree (budget); return err; } - if (budget->card->type == BUDGET_FS_ACTIVY) - dvb_add_frontend_ioctls (budget->dvb_adapter, - budget_ioctl_activy, NULL, budget); - else - dvb_add_frontend_ioctls (budget->dvb_adapter, - budget_diseqc_ioctl, NULL, budget); + budget->dvb_adapter->priv = budget; + frontend_init(budget); return 0; } @@ -225,12 +505,7 @@ struct budget *budget = (struct budget*) dev->ext_priv; int err; - if (budget->card->type == BUDGET_FS_ACTIVY) - dvb_remove_frontend_ioctls (budget->dvb_adapter, - budget_ioctl_activy, NULL); - else - dvb_remove_frontend_ioctls (budget->dvb_adapter, - budget_diseqc_ioctl, NULL); + if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend); err = ttpci_budget_deinit (budget); @@ -247,18 +522,14 @@ MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); -MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); +/* MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); UNDEFINED HARDWARE - mail linuxtv.org list */ MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY); -/* Uncomment for Budget Patch */ -/*MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH);*/ static struct pci_device_id pci_tbl[] = { - /* Uncomment for Budget Patch */ - /*MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000),*/ MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), - MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), +/* MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */ MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61), { .vendor = 0, diff -Nru a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h --- a/drivers/media/dvb/ttpci/budget.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttpci/budget.h 2004-12-12 17:40:53 -08:00 @@ -9,6 +9,7 @@ #include "dvb_filter.h" #include "dvb_net.h" +#include #include extern int budget_debug; @@ -61,7 +62,10 @@ spinlock_t feedlock; + spinlock_t debilock; + struct dvb_adapter *dvb_adapter; + struct dvb_frontend *dvb_frontend; void *priv; }; @@ -82,20 +86,27 @@ #define BUDGET_TT 0 #define BUDGET_TT_HW_DISEQC 1 -#define BUDGET_KNC1 2 #define BUDGET_PATCH 3 #define BUDGET_FS_ACTIVY 4 -#define BUDGET_CIN1200 5 +#define BUDGET_CIN1200S 5 +#define BUDGET_CIN1200C 6 +#define BUDGET_CIN1200T 7 +#define BUDGET_KNC1S 8 +#define BUDGET_KNC1C 9 +#define BUDGET_KNC1T 10 #define BUDGET_VIDEO_PORTA 0 #define BUDGET_VIDEO_PORTB 1 -extern int ttpci_budget_init (struct budget *budget, - struct saa7146_dev* dev, - struct saa7146_pci_extension_data *info); +extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, + struct saa7146_pci_extension_data *info, + struct module *owner); extern int ttpci_budget_deinit (struct budget *budget); extern void ttpci_budget_irq10_handler (struct saa7146_dev* dev, u32 *isr); extern void ttpci_budget_set_video_port(struct saa7146_dev* dev, int video_port); +extern int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count, + int uselocks, int nobusyloop); +extern int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr, int count, u32 value, + int uselocks, int nobusyloop); #endif - diff -Nru a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig --- a/drivers/media/dvb/ttusb-budget/Kconfig 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttusb-budget/Kconfig 2004-12-12 17:40:52 -08:00 @@ -1,6 +1,8 @@ config DVB_TTUSB_BUDGET tristate "Technotrend/Hauppauge Nova-USB devices" depends on DVB_CORE && USB + select DVB_CX22700 + select DVB_TDA1004X help Support for external USB adapters designed by Technotrend and produced by Hauppauge, shipped under the brand name 'Nova-USB'. diff -Nru a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile --- a/drivers/media/dvb/ttusb-budget/Makefile 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttusb-budget/Makefile 2004-12-12 17:40:53 -08:00 @@ -1,3 +1,3 @@ obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o -EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends diff -Nru a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c 2004-12-12 17:40:53 -08:00 @@ -24,6 +24,8 @@ #include "dmxdev.h" #include "dvb_demux.h" #include "dvb_net.h" +#include "cx22700.h" +#include "tda1004x.h" #include #include @@ -132,6 +134,8 @@ #if 0 devfs_handle_t stc_devfs_handle; #endif + + struct dvb_frontend* fe; }; /* ugly workaround ... don't know why it's neccessary to read */ @@ -461,9 +465,10 @@ } #ifdef TTUSB_DISEQC -static int ttusb_send_diseqc(struct ttusb *ttusb, +static int ttusb_send_diseqc(struct dvb_frontend* fe, const struct dvb_diseqc_master_cmd *cmd) { + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; int err; @@ -484,6 +489,7 @@ } #endif +#if 0 static int ttusb_update_lnb(struct ttusb *ttusb) { u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, @@ -501,41 +507,25 @@ return err; } -static int ttusb_set_voltage(struct ttusb *ttusb, fe_sec_voltage_t voltage) +static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + ttusb->voltage = voltage; return ttusb_update_lnb(ttusb); } #ifdef TTUSB_TONE -static int ttusb_set_tone(struct ttusb *ttusb, fe_sec_tone_mode_t tone) +static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + ttusb->tone = tone; return ttusb_update_lnb(ttusb); } #endif - -static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct ttusb *ttusb = fe->before_after_data; - - switch (cmd) { - case FE_SET_VOLTAGE: - return ttusb_set_voltage(ttusb, (fe_sec_voltage_t) arg); -#ifdef TTUSB_TONE - case FE_SET_TONE: - return ttusb_set_tone(ttusb, (fe_sec_tone_mode_t) arg); -#endif -#ifdef TTUSB_DISEQC - case FE_DISEQC_SEND_MASTER_CMD: - return ttusb_send_diseqc(ttusb, - (struct dvb_diseqc_master_cmd *) - arg); #endif - default: - return -EOPNOTSUPP; - }; -} + #if 0 static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq) @@ -560,7 +550,7 @@ const u8 * data, int len); #endif -int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid; +static int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid; static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, int len) @@ -1071,38 +1061,183 @@ }; #endif -u32 functionality(struct i2c_adapter *adapter) +static u32 functionality(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; } -static struct i2c_algorithm ttusb_dec_algo = { - .name = "ttusb dec i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = master_xfer, - .functionality = functionality, -}; -static int client_register(struct i2c_client *client) + +static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { - struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter); + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 data[4]; + struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; + u32 div; + + div = (params->frequency + 36166667) / 166667; - if (client->driver->command) - return client->driver->command(client, FE_REGISTER, ttusb->adapter); + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | 0x85; + data[3] = params->frequency < 592000000 ? 0x40 : 0x80; + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } -static int client_unregister(struct i2c_client *client) +struct cx22700_config alps_tdmb7_config = { + .demod_address = 0x43, + .pll_set = alps_tdmb7_pll_set, +}; + + + + + +static int philips_tdm1316l_pll_init(struct dvb_frontend* fe) { - struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter); + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) }; + + // setup PLL configuration + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1); + } - if (client->driver->command) - return client->driver->command(client, FE_UNREGISTER, ttusb->adapter); + return 0; +} + +static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) return -EINVAL; + else if (tuner_frequency < 130000000) cp = 3; + else if (tuner_frequency < 160000000) cp = 5; + else if (tuner_frequency < 200000000) cp = 6; + else if (tuner_frequency < 290000000) cp = 3; + else if (tuner_frequency < 420000000) cp = 5; + else if (tuner_frequency < 480000000) cp = 6; + else if (tuner_frequency < 620000000) cp = 3; + else if (tuner_frequency < 830000000) cp = 5; + else if (tuner_frequency < 895000000) cp = 7; + else return -EINVAL; + + // determine band + if (params->frequency < 49000000) return -EINVAL; + else if (params->frequency < 159000000) band = 1; + else if (params->frequency < 444000000) band = 2; + else if (params->frequency < 861000000) band = 4; + else return -EINVAL; + + // setup PLL filter + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_write_byte(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + tda1004x_write_byte(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + tda1004x_write_byte(fe, 0x0C, 0xFF); + filter = 1; + break; + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; + + msleep(1); return 0; } +static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + return request_firmware(fw, name, &ttusb->dev->dev); +} + +static struct tda1004x_config philips_tdm1316l_config = { + + .demod_address = 0x8, + .invert = 1, + .pll_init = philips_tdm1316l_pll_init, + .pll_set = philips_tdm1316l_pll_set, + .request_firmware = philips_tdm1316l_request_firmware, +}; + + + +static void frontend_init(struct ttusb* ttusb) +{ + switch(ttusb->dev->descriptor.idProduct) { + case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) + // try the ALPS TDMB7 first + ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) break; + + // Philips td1316 + ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) break; + break; + } + + if (ttusb->fe == NULL) { + printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n", + ttusb->dev->descriptor.idVendor, + ttusb->dev->descriptor.idProduct); + } else { + if (dvb_register_frontend(ttusb->adapter, ttusb->fe)) { + printk("dvb-ttusb-budget: Frontend registration failed!\n"); + if (ttusb->fe->ops->release) + ttusb->fe->ops->release(ttusb->fe); + ttusb->fe = NULL; + } + } +} + + + +static struct i2c_algorithm ttusb_dec_algo = { + .name = "ttusb dec i2c algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = master_xfer, + .functionality = functionality, +}; + static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev; @@ -1140,6 +1275,7 @@ up(&ttusb->sem); dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE); + ttusb->adapter->priv = ttusb; /* i2c */ memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter)); @@ -1155,8 +1291,6 @@ ttusb->i2c_adap.algo = &ttusb_dec_algo; ttusb->i2c_adap.algo_data = NULL; ttusb->i2c_adap.id = I2C_ALGO_BIT; - ttusb->i2c_adap.client_register = client_register; - ttusb->i2c_adap.client_unregister = client_unregister; result = i2c_add_adapter(&ttusb->i2c_adap); if (result) { @@ -1164,9 +1298,6 @@ return result; } - dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL, - ttusb); - memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); ttusb->dvb_demux.dmx.capabilities = @@ -1218,9 +1349,10 @@ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, &stc_fops, ttusb); #endif - usb_set_intfdata(intf, (void *) ttusb); + frontend_init(ttusb); + return 0; } @@ -1238,7 +1370,7 @@ dvb_net_release(&ttusb->dvbnet); dvb_dmxdev_release(&ttusb->dmxdev); dvb_dmx_release(&ttusb->dvb_demux); - + if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe); i2c_del_adapter(&ttusb->i2c_adap); dvb_unregister_adapter(ttusb->adapter); @@ -1250,8 +1382,8 @@ } static struct usb_device_id ttusb_table[] = { - {USB_DEVICE(0xb48, 0x1003)}, - {USB_DEVICE(0xb48, 0x1004)}, /* to be confirmed ???? */ +/* {USB_DEVICE(0xb48, 0x1003)},UNDEFINED HARDWARE - mail linuxtv.org list */ +/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */ {USB_DEVICE(0xb48, 0x1005)}, {} }; diff -Nru a/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h b/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h 2004-12-12 17:40:52 -08:00 @@ -1,7 +1,7 @@ #include -u8 dsp_bootcode [] = { +static u8 dsp_bootcode [] = { 0x08, 0xaa, 0x00, 0x18, 0x00, 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x80, 0x18, 0x5f, 0x00, 0x00, 0x01, 0x80, 0x77, 0x18, 0x2a, 0xeb, diff -Nru a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile --- a/drivers/media/dvb/ttusb-dec/Makefile 2004-12-12 17:40:52 -08:00 +++ b/drivers/media/dvb/ttusb-dec/Makefile 2004-12-12 17:40:52 -08:00 @@ -1,3 +1,3 @@ -obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o +obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ diff -Nru a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2004-12-12 17:40:53 -08:00 @@ -30,11 +30,7 @@ #include #include #include -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) #include -#else -#warning "CRC checking of firmware not available" -#endif #include #include "dmxdev.h" @@ -42,6 +38,7 @@ #include "dvb_filter.h" #include "dvb_frontend.h" #include "dvb_net.h" +#include "ttusbdecfe.h" static int debug; static int output_pva; @@ -69,9 +66,6 @@ #define MAX_PVA_LENGTH 6144 -#define LOF_HI 10600000 -#define LOF_LO 9750000 - enum ttusb_dec_model { TTUSB_DEC2000T, TTUSB_DEC2540T, @@ -102,12 +96,9 @@ struct dvb_demux demux; struct dmx_frontend frontend; struct dvb_net dvb_net; - struct dvb_frontend_info *frontend_info; - int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *); + struct dvb_frontend* fe; u16 pid[DMX_PES_OTHER]; - int hi_band; - int voltage; /* USB bits */ struct usb_device *udev; @@ -166,32 +157,6 @@ struct list_head filter_info_list; }; -static struct dvb_frontend_info dec2000t_frontend_info = { - .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", - .type = FE_OFDM, - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; - -static struct dvb_frontend_info dec3000s_frontend_info = { - .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; - static void ttusb_dec_set_model(struct ttusb_dec *dec, enum ttusb_dec_model model); @@ -1170,10 +1135,9 @@ u16 firmware_csum = 0; u16 firmware_csum_ns; u32 firmware_size_nl; -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) u32 crc32_csum, crc32_check, tmp; -#endif const struct firmware *fw_entry = NULL; + dprintk("%s\n", __FUNCTION__); if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { @@ -1194,7 +1158,6 @@ /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored at offset 56 of file, so use it to check if the firmware file is valid. */ -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; memcpy(&tmp, &firmware[56], 4); crc32_check = htonl(tmp); @@ -1204,7 +1167,6 @@ __FUNCTION__, crc32_csum, crc32_check); return -1; } -#endif memcpy(idstring, &firmware[36], 20); idstring[20] = '\0'; printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); @@ -1404,6 +1366,7 @@ dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); + if (dec->fe) dvb_unregister_frontend(dec->fe); dvb_unregister_adapter(dec->adapter); } @@ -1435,264 +1398,6 @@ } } -static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd, - void *arg) -{ - struct ttusb_dec *dec = fe->data; - - dprintk("%s\n", __FUNCTION__); - - switch (cmd) { - - case FE_GET_INFO: - dprintk("%s: FE_GET_INFO\n", __FUNCTION__); - memcpy(arg, dec->frontend_info, - sizeof (struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: { - fe_status_t *status = (fe_status_t *)arg; - dprintk("%s: FE_READ_STATUS\n", __FUNCTION__); - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - } - - case FE_READ_BER: { - u32 *ber = (u32 *)arg; - dprintk("%s: FE_READ_BER\n", __FUNCTION__); - *ber = 0; - return -ENOSYS; - break; - } - - case FE_READ_SIGNAL_STRENGTH: { - dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__); - *(s32 *)arg = 0xFF; - return -ENOSYS; - break; - } - - case FE_READ_SNR: - dprintk("%s: FE_READ_SNR\n", __FUNCTION__); - *(s32 *)arg = 0; - return -ENOSYS; - break; - - case FE_READ_UNCORRECTED_BLOCKS: - dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__); - *(u32 *)arg = 0; - return -ENOSYS; - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *)arg; - u8 b[] = { 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff }; - u32 freq; - - dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__); - - dprintk(" frequency->%d\n", p->frequency); - dprintk(" symbol_rate->%d\n", - p->u.qam.symbol_rate); - dprintk(" inversion->%d\n", p->inversion); - - freq = htonl(p->frequency / 1000); - memcpy(&b[4], &freq, sizeof (u32)); - ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL); - - break; - } - - case FE_GET_FRONTEND: - dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__); - break; - - case FE_SLEEP: - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - return -ENOSYS; - break; - - case FE_INIT: - dprintk("%s: FE_INIT\n", __FUNCTION__); - break; - - default: - dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd); - return -EINVAL; - - } - - return 0; -} - -static int ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe, - unsigned int cmd, void *arg) -{ - struct ttusb_dec *dec = fe->data; - - dprintk("%s\n", __FUNCTION__); - - switch (cmd) { - - case FE_GET_INFO: - dprintk("%s: FE_GET_INFO\n", __FUNCTION__); - memcpy(arg, dec->frontend_info, - sizeof (struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: { - fe_status_t *status = (fe_status_t *)arg; - dprintk("%s: FE_READ_STATUS\n", __FUNCTION__); - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - } - - case FE_READ_BER: { - u32 *ber = (u32 *)arg; - dprintk("%s: FE_READ_BER\n", __FUNCTION__); - *ber = 0; - return -ENOSYS; - break; - } - - case FE_READ_SIGNAL_STRENGTH: { - dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__); - *(s32 *)arg = 0xFF; - return -ENOSYS; - break; - } - - case FE_READ_SNR: - dprintk("%s: FE_READ_SNR\n", __FUNCTION__); - *(s32 *)arg = 0; - return -ENOSYS; - break; - - case FE_READ_UNCORRECTED_BLOCKS: - dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__); - *(u32 *)arg = 0; - return -ENOSYS; - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *)arg; - u8 b[] = { 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - u32 freq; - u32 sym_rate; - u32 band; - u32 lnb_voltage; - - dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__); - - dprintk(" frequency->%d\n", p->frequency); - dprintk(" symbol_rate->%d\n", - p->u.qam.symbol_rate); - dprintk(" inversion->%d\n", p->inversion); - - freq = htonl(p->frequency + - (dec->hi_band ? LOF_HI : LOF_LO)); - memcpy(&b[4], &freq, sizeof(u32)); - sym_rate = htonl(p->u.qam.symbol_rate); - memcpy(&b[12], &sym_rate, sizeof(u32)); - band = htonl(dec->hi_band ? LOF_HI : LOF_LO); - memcpy(&b[24], &band, sizeof(u32)); - lnb_voltage = htonl(dec->voltage); - memcpy(&b[28], &lnb_voltage, sizeof(u32)); - - ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL); - - break; - } - - case FE_GET_FRONTEND: - dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__); - break; - - case FE_SLEEP: - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - return -ENOSYS; - break; - - case FE_INIT: - dprintk("%s: FE_INIT\n", __FUNCTION__); - break; - - case FE_DISEQC_SEND_MASTER_CMD: { - u8 b[] = { 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; - struct dvb_diseqc_master_cmd *cmd = arg; - memcpy(&b[4], cmd->msg, cmd->msg_len); - dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__); - ttusb_dec_send_command(dec, 0x72, - sizeof(b) - (6 - cmd->msg_len), b, - NULL, NULL); - break; - } - - case FE_DISEQC_SEND_BURST: - dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__); - break; - - case FE_SET_TONE: { - fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg; - dprintk("%s: FE_SET_TONE\n", __FUNCTION__); - dec->hi_band = (SEC_TONE_ON == tone); - break; - } - - case FE_SET_VOLTAGE: - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - switch ((fe_sec_voltage_t) arg) { - case SEC_VOLTAGE_13: - dec->voltage = 13; - break; - case SEC_VOLTAGE_18: - dec->voltage = 18; - break; - default: - return -EINVAL; - break; - } - break; - - default: - dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd); - return -EINVAL; - - } - - return 0; -} - -static void ttusb_dec_init_frontend(struct ttusb_dec *dec) -{ - int ret; - ret = dvb_register_frontend(dec->frontend_ioctl, dec->adapter, dec, dec->frontend_info, THIS_MODULE); -} - -static void ttusb_dec_exit_frontend(struct ttusb_dec *dec) -{ - dvb_unregister_frontend(dec->frontend_ioctl, dec->adapter); -} - static void ttusb_dec_init_filters(struct ttusb_dec *dec) { INIT_LIST_HEAD(&dec->filter_info_list); @@ -1711,6 +1416,18 @@ } } +int fe_send_command(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) +{ + struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv; + return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); +} + +struct ttusbdecfe_config fe_config = { + .send_command = fe_send_command +}; + static int ttusb_dec_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1752,7 +1469,32 @@ return 0; } ttusb_dec_init_dvb(dec); - ttusb_dec_init_frontend(dec); + + dec->adapter->priv = dec; + switch (id->idProduct) { + case 0x1006: + dec->fe = ttusbdecfe_dvbs_attach(&fe_config); + break; + + case 0x1008: + case 0x1009: + dec->fe = ttusbdecfe_dvbt_attach(&fe_config); + break; + } + + if (dec->fe == NULL) { + printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n", + dec->udev->descriptor.idVendor, + dec->udev->descriptor.idProduct); + } else { + if (dvb_register_frontend(dec->adapter, dec->fe)) { + printk("budget-ci: Frontend registration failed!\n"); + if (dec->fe->ops->release) + dec->fe->ops->release(dec->fe); + dec->fe = NULL; + } + } + ttusb_dec_init_v_pes(dec); ttusb_dec_init_filters(dec); ttusb_dec_init_tasklet(dec); @@ -1776,7 +1518,6 @@ ttusb_dec_exit_tasklet(dec); ttusb_dec_exit_filters(dec); ttusb_dec_exit_usb(dec); - ttusb_dec_exit_frontend(dec); ttusb_dec_exit_dvb(dec); } @@ -1792,22 +1533,16 @@ case TTUSB_DEC2000T: dec->model_name = "DEC2000-t"; dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; - dec->frontend_info = &dec2000t_frontend_info; - dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl; break; case TTUSB_DEC2540T: dec->model_name = "DEC2540-t"; dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; - dec->frontend_info = &dec2000t_frontend_info; - dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl; break; case TTUSB_DEC3000S: dec->model_name = "DEC3000-s"; dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; - dec->frontend_info = &dec3000s_frontend_info; - dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl; break; } } diff -Nru a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,255 @@ +/* + * TTUSB DEC Frontend Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * 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 "dvb_frontend.h" +#include "ttusbdecfe.h" + + +#define LOF_HI 10600000 +#define LOF_LO 9750000 + +struct ttusbdecfe_state { + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct ttusbdecfe_config* config; + + struct dvb_frontend frontend; + + u8 hi_band; + u8 voltage; +}; + + +static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + + return 0; +} + +static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff }; + + u32 freq = htonl(p->frequency / 1000); + memcpy(&b[4], &freq, sizeof (u32)); + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + u8 b[] = { 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + u32 freq; + u32 sym_rate; + u32 band; + u32 lnb_voltage; + + freq = htonl(p->frequency + + (state->hi_band ? LOF_HI : LOF_LO)); + memcpy(&b[4], &freq, sizeof(u32)); + sym_rate = htonl(p->u.qam.symbol_rate); + memcpy(&b[12], &sym_rate, sizeof(u32)); + band = htonl(state->hi_band ? LOF_HI : LOF_LO); + memcpy(&b[24], &band, sizeof(u32)); + lnb_voltage = htonl(state->voltage); + memcpy(&b[28], &lnb_voltage, sizeof(u32)); + + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + + memcpy(&b[4], cmd->msg, cmd->msg_len); + + state->config->send_command(fe, 0x72, + sizeof(b) - (6 - cmd->msg_len), b, + NULL, NULL); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + state->hi_band = (SEC_TONE_ON == tone); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + state->voltage = 13; + break; + case SEC_VOLTAGE_18: + state->voltage = 18; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void ttusbdecfe_release(struct dvb_frontend* fe) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops; + +struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; + +struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->voltage = 0; + state->hi_band = 0; + memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { + + .info = { + .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbt_set_frontend, + + .read_status = ttusbdecfe_read_status, +}; + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { + + .info = { + .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbs_set_frontend, + + .read_status = ttusbdecfe_read_status, + + .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, + .set_voltage = ttusbdecfe_dvbs_set_voltage, + .set_tone = ttusbdecfe_dvbs_set_tone, +}; + +MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver"); +MODULE_AUTHOR("Alex Woods/Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(ttusbdecfe_dvbt_attach); +EXPORT_SYMBOL(ttusbdecfe_dvbs_attach); diff -Nru a/drivers/media/dvb/ttusb-dec/ttusbdecfe.h b/drivers/media/dvb/ttusb-dec/ttusbdecfe.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,38 @@ +/* + * TTUSB DEC Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * 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 TTUSBDECFE_H +#define TTUSBDECFE_H + +#include + +struct ttusbdecfe_config +{ + int (*send_command)(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]); +}; + +extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config); + +extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config); + +#endif // TTUSBDECFE_H diff -Nru a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c --- a/drivers/media/video/msp3400.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/media/video/msp3400.c 2004-12-12 17:40:53 -08:00 @@ -1511,9 +1511,12 @@ msp->opmode = opmode; if (OPMODE_AUTO == msp->opmode) { +#if 0 /* seems to work for ivtv only, disable by default for now ... */ if (HAVE_SIMPLER(msp)) msp->opmode = OPMODE_SIMPLER; - else if (HAVE_SIMPLE(msp)) + else +#endif + if (HAVE_SIMPLE(msp)) msp->opmode = OPMODE_SIMPLE; else msp->opmode = OPMODE_MANUAL; diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c --- a/drivers/message/fusion/mptbase.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/message/fusion/mptbase.c 2004-12-12 17:40:53 -08:00 @@ -155,7 +155,6 @@ static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS]; static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS]; -static int FusionInitCalled = 0; static int mpt_base_index = -1; static int last_drv_idx = -1; @@ -337,15 +336,13 @@ ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); - if ((int)ioc->chip_type <= (int)FC929) + if (ioc->bus_type == FC) mpt_fc_log_info(ioc, log_info); - else + else if (ioc->bus_type == SCSI) mpt_sp_log_info(ioc, log_info); } if (ioc_stat & MPI_IOCSTATUS_MASK) { - if ((int)ioc->chip_type <= (int)FC929) - ; - else + if (ioc->bus_type == SCSI) mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); } } else { @@ -392,7 +389,7 @@ } #ifdef MPT_DEBUG_IRQ - if ((int)ioc->chip_type > (int)FC929) { + if (ioc->bus_type == SCSI) { /* Verify mf, mr are reasonable. */ if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth)) @@ -603,22 +600,6 @@ last_drv_idx = -1; -#ifndef MODULE - /* - * Handle possibility of the mptscsih_detect() routine getting - * called *before* fusion_init! - */ - if (!FusionInitCalled) { - dprintk((KERN_INFO MYNAM ": Hmmm, calling fusion_init from mpt_register!\n")); - /* - * NOTE! We'll get recursion here, as fusion_init() - * calls mpt_register()! - */ - fusion_init(); - FusionInitCalled++; - } -#endif - /* * Search for empty callback slot in this order: {N,...,7,6,5,...,1} * (slot/handle 0 is reserved!) @@ -1220,22 +1201,21 @@ ioc->pio_chip = (SYSIF_REGS __iomem *)pmem; } - ioc->chip_type = FCUNK; if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { - ioc->chip_type = FC909; ioc->prod_name = "LSIFC909"; + ioc->bus_type = FC; } if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { - ioc->chip_type = FC929; ioc->prod_name = "LSIFC929"; + ioc->bus_type = FC; } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) { - ioc->chip_type = FC919; ioc->prod_name = "LSIFC919"; + ioc->bus_type = FC; } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { - ioc->chip_type = FC929X; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + ioc->bus_type = FC; if (revision < XL_929) { ioc->prod_name = "LSIFC929X"; /* 929X Chip Fix. Set Split transactions level @@ -1254,8 +1234,8 @@ } } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { - ioc->chip_type = FC919X; ioc->prod_name = "LSIFC919X"; + ioc->bus_type = FC; /* 919X Chip Fix. Set Split transactions level * for PCIX. Set MOST bits to zero. */ @@ -1264,8 +1244,8 @@ pci_write_config_byte(pdev, 0x6a, pcixcmd); } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { - ioc->chip_type = C1030; ioc->prod_name = "LSI53C1030"; + ioc->bus_type = SCSI; /* 1030 Chip Fix. Disable Split transactions * for PCIX. Set MOST bits to zero if Rev < C0( = 8). */ @@ -1277,8 +1257,8 @@ } } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { - ioc->chip_type = C1035; ioc->prod_name = "LSI53C1035"; + ioc->bus_type = SCSI; } sprintf(ioc->name, "ioc%d", ioc->id); @@ -1326,9 +1306,7 @@ /* NEW! 20010220 -sralston * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. */ - if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) - || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X)) - mpt_detect_bound_ports(ioc, pdev); + mpt_detect_bound_ports(ioc, pdev); if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { @@ -1760,7 +1738,7 @@ * and we try GetLanConfigPages again... */ if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { - if ((int)ioc->chip_type <= (int)FC929) { + if (ioc->bus_type == FC) { /* * Pre-fetch FC port WWN and stuff... * (FCPortPage0_t stuff) @@ -2103,20 +2081,8 @@ } /* Is it already READY? */ - if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) { - if ((int)ioc->chip_type <= (int)FC929) - return 0; - else { - return 0; - /* Workaround from broken 1030 FW. - * Force a diagnostic reset if fails. - */ -/* if ((r = SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag)) == 0) - return 0; - else - statefault = 4; */ - } - } + if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) + return 0; /* * Check to see if IOC is in FAULT state. @@ -2513,11 +2479,11 @@ ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n", ioc->name, ioc->upload_fw, ioc->facts.Flags)); - if ((int)ioc->chip_type <= (int)FC929) { + if (ioc->bus_type == FC) ioc_init.MaxDevices = MPT_MAX_FC_DEVICES; - } else { + else ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES; - } + ioc_init.MaxBuses = MPT_MAX_BUS; ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ @@ -2622,7 +2588,7 @@ /* RAID FW may take a long time to enable */ - if ((int)ioc->chip_type <= (int)FC929) { + if (ioc->bus_type == FC) { ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag); } else { @@ -2992,7 +2958,7 @@ int cnt,cntdn; dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); - if ((int)ioc->chip_type > (int)FC929) { + if (ioc->bus_type == SCSI) { /* Always issue a Msg Unit Reset first. This will clear some * SCSI bus hang conditions. */ @@ -3420,7 +3386,7 @@ dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n", ioc->name, numSGE, num_sge, num_chain)); - if ((int) ioc->chip_type > (int) FC929) + if (ioc->bus_type == SCSI) num_chain *= MPT_SCSI_CAN_QUEUE; else num_chain *= MPT_FC_CAN_QUEUE; @@ -5277,7 +5243,7 @@ len += sprintf(buf+len, " PortNumber = %d (of %d)\n", p+1, ioc->facts.NumberOfPorts); - if ((int)ioc->chip_type <= (int)FC929) { + if (ioc->bus_type == FC) { if (ioc->pfacts[p].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow; len += sprintf(buf+len, " LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", @@ -5920,11 +5886,6 @@ { int i; int r; - - if (FusionInitCalled++) { - dprintk((KERN_INFO MYNAM ": INFO - Driver late-init entry point called\n")); - return 0; - } show_mptmod_ver(my_NAME, my_VERSION); printk(KERN_INFO COPYRIGHT "\n"); diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h --- a/drivers/message/fusion/mptbase.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/message/fusion/mptbase.h 2004-12-12 17:40:52 -08:00 @@ -83,8 +83,8 @@ #define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.01.17" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.17" +#define MPT_LINUX_VERSION_COMMON "3.01.18" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.18" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -296,23 +296,6 @@ SGESimple64_t sge[1]; } MPT_SGL64_HDR; - -/* - * Chip-specific stuff... FC929 delineates break between - * FC and Parallel SCSI parts. Do NOT re-order. - */ - -typedef enum { - FC919X = 0x0819, - FC929X = 0x0829, - FC909 = 0x0909, - FC919 = 0x0919, - FC929 = 0x0929, - C1030 = 0x1030, - C1035 = 0x1035, - FCUNK = 0xFBAD -} CHIP_TYPE; - /* * System interface register set */ @@ -517,6 +500,7 @@ char *prod_name; /* "LSIFC9x9" */ SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */ SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */ + u8 bus_type; u32 mem_phys; /* == f4020000 (mmap) */ u32 pio_mem_phys; /* Programmed IO (downloadboot) */ int mem_size; /* mmap memory size */ @@ -543,7 +527,6 @@ dma_addr_t ChainBufferDMA; struct list_head FreeChainQ; spinlock_t FreeChainQlock; - CHIP_TYPE chip_type; /* We (host driver) get to manage our own RequestQueue! */ dma_addr_t req_frames_dma; MPT_FRAME_HDR *req_frames; /* Request msg frames - rounded up! */ @@ -573,12 +556,6 @@ int eventTypes; /* Event logging parameters */ int eventContext; /* Next event context */ int eventLogSize; /* Max number of cached events */ -#ifdef MPTSCSIH_DBG_TIMEOUT - int timeout_hard; - int timeout_delta; - int timeout_cnt; - int timeout_maxcnt; -#endif struct _mpt_ioctl_events *events; /* pointer to event log */ u8 *cached_fw; /* Pointer to FW */ dma_addr_t cached_fw_dma; @@ -894,6 +871,12 @@ #define TM_STATE_IN_PROGRESS (1) #define TM_STATE_ERROR (2) +typedef enum { + FC, + SCSI, + SAS +} BUS_TYPE; + typedef struct _MPT_SCSI_HOST { MPT_ADAPTER *ioc; int port; @@ -909,7 +892,6 @@ */ u8 tmPending; u8 resetPending; - u8 is_spi; /* Parallel SCSI i/f */ u8 negoNvram; /* DV disabled, nego NVRAM */ u8 pad1; u8 tmState; diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c --- a/drivers/message/fusion/mptctl.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/message/fusion/mptctl.c 2004-12-12 17:40:52 -08:00 @@ -1218,7 +1218,7 @@ /* Fill in the data and return the structure to the calling * program */ - if ((int)ioc->chip_type <= (int) FC929) + if (ioc->bus_type == FC) karg->adapterType = MPT_IOCTL_INTERFACE_FC; else karg->adapterType = MPT_IOCTL_INTERFACE_SCSI; @@ -1518,7 +1518,7 @@ #ifdef MFCNT karg.chip_type = ioc->mfcnt; #else - karg.chip_type = ioc->chip_type; + karg.chip_type = ioc->pcidev->device; #endif strncpy (karg.name, ioc->name, MPT_MAX_NAME); karg.name[MPT_MAX_NAME-1]='\0'; @@ -2470,7 +2470,7 @@ karg.base_io_addr = pci_resource_start(pdev, 0); - if ((int)ioc->chip_type <= (int) FC929) + if (ioc->bus_type == FC) karg.bus_phys_width = HP_BUS_WIDTH_UNK; else karg.bus_phys_width = HP_BUS_WIDTH_16; @@ -2559,7 +2559,7 @@ /* There is nothing to do for FCP parts. */ - if ((int) ioc->chip_type <= (int) FC929) + if (ioc->bus_type == FC) return 0; if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL)) diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/message/fusion/mptscsih.c 2004-12-12 17:40:53 -08:00 @@ -96,10 +96,22 @@ MODULE_DESCRIPTION(my_NAME); MODULE_LICENSE("GPL"); -/* Set string for command line args from insmod */ #ifdef MODULE -char *mptscsih = NULL; -module_param(mptscsih, charp, 0); +static int dv = MPTSCSIH_DOMAIN_VALIDATION; +module_param(dv, int, 0); +MODULE_PARM_DESC(dv, "DV Algorithm: enhanced = 1, basic = 0 (default=MPTSCSIH_DOMAIN_VALIDATION=1)"); + +static int width = MPTSCSIH_MAX_WIDTH; +module_param(width, int, 0); +MODULE_PARM_DESC(width, "Max Bus Width: wide = 1, narrow = 0 (default=MPTSCSIH_MAX_WIDTH=1)"); + +static ushort factor = MPTSCSIH_MIN_SYNC; +module_param(factor, ushort, 0); +MODULE_PARM_DESC(factor, "Min Sync Factor: (default=MPTSCSIH_MIN_SYNC=0x08)"); + +static int saf_te = MPTSCSIH_SAF_TE; +module_param(saf_te, int, 0); +MODULE_PARM_DESC(saf_te, "Force enabling SEP Processor: (default=MPTSCSIH_SAF_TE=0)"); #endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -200,9 +212,6 @@ static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage); static void mptscsih_fillbuf(char *buffer, int size, int index, int width); #endif -#ifdef MODULE -static int mptscsih_setup(char *str); -#endif /* module entry point */ static int __init mptscsih_init (void); static void __exit mptscsih_exit (void); @@ -245,15 +254,9 @@ static int scandv_wait_done = 1; -/* Driver default setup +/* Driver command line structure */ -static struct mptscsih_driver_setup - driver_setup = MPTSCSIH_DRIVER_SETUP; - -#ifdef MPTSCSIH_DBG_TIMEOUT -static struct scsi_cmnd *foo_to[8]; -#endif - +static struct mptscsih_driver_setup driver_setup; static struct scsi_host_template driver_template; /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -653,27 +656,6 @@ pScsiReq = (SCSIIORequest_t *) mf; pScsiReply = (SCSIIOReply_t *) mr; -#ifdef MPTSCSIH_DBG_TIMEOUT - if (ioc->timeout_cnt > 0) { - int ii, left = 0; - - for (ii=0; ii < 8; ii++) { - if (sc == foo_to[ii]) { - printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n", - ioc->name, sc, jiffies); - foo_to[ii] = NULL; - } - if (foo_to[ii] != NULL) - left++; - } - - if (left == 0) { - ioc->timeout_maxcnt = 0; - ioc->timeout_cnt = 0; - } - } -#endif - if (pScsiReply == NULL) { /* special context reply handling */ ; @@ -686,13 +668,14 @@ scsi_state = pScsiReply->SCSIState; scsi_status = pScsiReply->SCSIStatus; xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); + sc->resid = sc->request_bufflen - xfer_cnt; - dreplyprintk((KERN_NOTICE " Reply (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", - ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], - mf, mr, sc)); - dreplyprintk((KERN_NOTICE "IOCStatus=%04xh SCSIState=%02xh" - " SCSIStatus=%02xh xfer_cnt=%08xh\n", - status, scsi_state, scsi_status, xfer_cnt)); + dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n" + "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n" + "resid=%d bufflen=%d xfer_cnt=%d\n", + ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], + status, scsi_state, scsi_status, sc->resid, + sc->request_bufflen, xfer_cnt)); if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) copy_sense_data(sc, hd, mf, pScsiReply); @@ -737,12 +720,11 @@ sc->result = DID_RESET << 16; /* GEM Workaround. */ - if (hd->is_spi) + if (ioc->bus_type == SCSI) mptscsih_no_negotiate(hd, sc->device->id); break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ - sc->resid = sc->request_bufflen - xfer_cnt; if ( xfer_cnt >= sc->underflow ) { /* Sufficient data transfer occurred */ sc->result = (DID_OK << 16) | scsi_status; @@ -771,7 +753,7 @@ */ ; } else { - if ( (xfer_cnt == 0) || (sc->underflow > xfer_cnt)) { + if (xfer_cnt < sc->underflow) { sc->result = DID_SOFT_ERROR << 16; } if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { @@ -785,15 +767,9 @@ } } - /* Give report and update residual count. - */ dreplyprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); dreplyprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); - - sc->resid = sc->request_bufflen - xfer_cnt; - dreplyprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); - /* Report Queue Full */ if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL) @@ -848,7 +824,7 @@ break; case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ - sc->result = DID_SOFT_ERROR << 16; + sc->result = DID_SOFT_ERROR << 16; break; case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ @@ -1132,7 +1108,7 @@ * max_lun = 1 + actual last lun, * see hosts.h :o( */ - if ((int)ioc->chip_type > (int)FC929) { + if (ioc->bus_type == SCSI) { sh->max_id = MPT_MAX_SCSI_DEVICES; } else { /* For FC, increase the queue depth @@ -1191,9 +1167,6 @@ hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = ioc; - if ((int)ioc->chip_type > (int)FC929) - hd->is_spi = 1; - /* SCSI needs scsi_cmnd lookup table! * (with size equal to req_depth*PtrSz!) */ @@ -1259,15 +1232,7 @@ /* Moved Earlier Pam D */ /* ioc->sh = sh; */ -#ifdef MPTSCSIH_DBG_TIMEOUT - ioc->timeout_hard = 0; - ioc->timeout_delta = 30 * HZ; - ioc->timeout_maxcnt = 0; - ioc->timeout_cnt = 0; - for (ii=0; ii < 8; ii++) - foo_to[ii] = NULL; -#endif - if (hd->is_spi) { + if (ioc->bus_type == SCSI) { /* Update with the driver setup * values. */ @@ -1278,9 +1243,9 @@ } if (ioc->spi_data.minSyncFactor < - driver_setup.min_sync_fac) { + driver_setup.min_sync_factor) { ioc->spi_data.minSyncFactor = - driver_setup.min_sync_fac; + driver_setup.min_sync_factor; } if (ioc->spi_data.minSyncFactor == MPT_ASYNC) { @@ -1307,7 +1272,7 @@ "dv %x width %x factor %x saf_te %x\n", ioc->name, driver_setup.dv, driver_setup.max_width, - driver_setup.min_sync_fac, + driver_setup.min_sync_factor, driver_setup.saf_te)); } @@ -1374,11 +1339,11 @@ hd = (MPT_SCSI_HOST *)host->hostdata; if (hd != NULL) { - int sz1, sz3, sztarget=0; + int sz1; mptscsih_shutdown(&pdev->dev); - sz1 = sz3 = 0; + sz1=0; if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); @@ -1387,36 +1352,16 @@ } if (hd->Targets != NULL) { - int max, ii; - - /* - * Free any target structures that were allocated. - */ - if (hd->is_spi) { - max = MPT_MAX_SCSI_DEVICES; - } else { - max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; - } - for (ii=0; ii < max; ii++) { - if (hd->Targets[ii]) { - kfree(hd->Targets[ii]); - hd->Targets[ii] = NULL; - sztarget += sizeof(VirtDevice); - } - } - /* * Free pointer array. */ - sz3 = max * sizeof(void *); kfree(hd->Targets); hd->Targets = NULL; } dprintk((MYIOC_s_INFO_FMT - "Free'd ScsiLookup (%d) Target (%d+%d) memory\n", - hd->ioc->name, sz1, sz3, sztarget)); - dprintk(("Free'd done and free Q (%d) memory\n", szQ)); + "Free'd ScsiLookup (%d) memory\n", + hd->ioc->name, sz1)); /* NULL the Scsi_Host pointer */ @@ -1545,9 +1490,15 @@ } #ifdef MODULE - /* Evaluate the command line arguments, if any */ - if (mptscsih) - mptscsih_setup(mptscsih); + dinitprintk((KERN_INFO MYNAM + ": Command Line Args: dv=%d max_width=%d " + "factor=0x%x saf_te=%d\n", + dv, width, factor, saf_te)); + + driver_setup.dv = (dv) ? 1 : 0; + driver_setup.max_width = (width) ? 1 : 0; + driver_setup.min_sync_factor = factor; + driver_setup.saf_te = (saf_te) ? 1 : 0;; #endif if(mpt_device_driver_register(&mptscsih_driver, @@ -1676,129 +1627,6 @@ return ((info.pos > info.offset) ? info.pos - info.offset : 0); } -#ifndef MPTSCSIH_DBG_TIMEOUT -static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len) -{ - /* Not yet implemented */ - return len; -} -#else -#define is_digit(c) ((c) >= '0' && (c) <= '9') -#define digit_to_bin(c) ((c) - '0') -#define is_space(c) ((c) == ' ' || (c) == '\t') - -#define UC_DBG_TIMEOUT 0x01 -#define UC_DBG_HARDRESET 0x02 - -static int skip_spaces(char *ptr, int len) -{ - int cnt, c; - - for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt --); - - return (len - cnt); -} - -static int get_int_arg(char *ptr, int len, ulong *pv) -{ - int cnt, c; - ulong v; - for (v = 0, cnt = len; cnt > 0 && (c=*ptr++) && is_digit(c); cnt --) { - v = (v * 10) + digit_to_bin(c); - } - - if (pv) - *pv = v; - - return (len - cnt); -} - - -static int is_keyword(char *ptr, int len, char *verb) -{ - int verb_len = strlen(verb); - - if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) - return verb_len; - else - return 0; -} - -#define SKIP_SPACES(min_spaces) \ - if ((arg_len = skip_spaces(ptr,len)) < (min_spaces)) \ - return -EINVAL; \ - ptr += arg_len; \ - len -= arg_len; - -#define GET_INT_ARG(v) \ - if (!(arg_len = get_int_arg(ptr,len, &(v)))) \ - return -EINVAL; \ - ptr += arg_len; \ - len -= arg_len; - -static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length) -{ - char *ptr = buffer; - char btmp[24]; /* REMOVE */ - int arg_len; - int len = length; - int cmd; - ulong number = 1; - ulong delta = 10; - - if ((len > 0) && (ptr[len -1] == '\n')) - --len; - - if (len < 22) { - strncpy(btmp, buffer, len); - btmp[len+1]='\0'; - } else { - strncpy(btmp, buffer, 22); - btmp[23]='\0'; - } - printk("user_command: ioc %d, buffer %s, length %d\n", - ioc->id, btmp, length); - - if ((arg_len = is_keyword(ptr, len, "timeout")) != 0) - cmd = UC_DBG_TIMEOUT; - else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0) - cmd = UC_DBG_HARDRESET; - else - return -EINVAL; - - ptr += arg_len; - len -= arg_len; - - switch(cmd) { - case UC_DBG_TIMEOUT: - SKIP_SPACES(1); - GET_INT_ARG(number); - SKIP_SPACES(1); - GET_INT_ARG(delta); - break; - } - - printk("user_command: cnt=%ld delta=%ld\n", number, delta); - - if (len) - return -EINVAL; - else { - if (cmd == UC_DBG_HARDRESET) { - ioc->timeout_hard = 1; - } else if (cmd == UC_DBG_TIMEOUT) { - /* process this command ... - */ - ioc->timeout_maxcnt = 0; - ioc->timeout_delta = delta < 2 ? 2 : delta; - ioc->timeout_cnt = 0; - ioc->timeout_maxcnt = number < 8 ? number: 8; - } - } - /* Not yet implemented */ - return length; -} -#endif - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_proc_info - Return information about MPT adapter @@ -1812,7 +1640,7 @@ * hostno: scsi host number * func: if write = 1; if read = 0 */ -static int +static int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func) { @@ -1821,7 +1649,9 @@ int size = 0; if (func) { - size = mptscsih_user_command(ioc, buffer, length); + /* + * write is not supported + */ } else { if (start) *start = buffer; @@ -1832,7 +1662,6 @@ return size; } - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #define ADD_INDEX_LOG(req_ent) do { } while(0) @@ -1863,11 +1692,7 @@ u32 cmd_len; int my_idx; int ii; - int rc; - int did_errcode; - int issueCmd; - did_errcode = 0; hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; target = SCpnt->device->id; lun = SCpnt->device->lun; @@ -1966,84 +1791,66 @@ /* Now add the SG list * Always have a SGE even if null length. */ - rc = SUCCESS; if (datalen == 0) { /* Add a NULL SGE */ mptscsih_add_sge((char *)&pScsiReq->SGL, MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1); } else { /* Add a 32 or 64 bit SGE */ - rc = mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx); + if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS) + goto fail; } - - if (rc == SUCCESS) { - hd->ScsiLookup[my_idx] = SCpnt; - SCpnt->host_scribble = NULL; - - /* SCSI specific processing */ - issueCmd = 1; - if (hd->is_spi) { - int dvStatus = hd->ioc->spi_data.dvStatus[target]; - - if (dvStatus || hd->ioc->spi_data.forceDv) { + hd->ScsiLookup[my_idx] = SCpnt; + SCpnt->host_scribble = NULL; #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION - if ((dvStatus & MPT_SCSICFG_NEED_DV) || - (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) { - unsigned long lflags; - /* Schedule DV if necessary */ - spin_lock_irqsave(&dvtaskQ_lock, lflags); - if (!dvtaskQ_active) { - dvtaskQ_active = 1; - spin_unlock_irqrestore(&dvtaskQ_lock, lflags); - INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); - - schedule_work(&mptscsih_dvTask); - } else { - spin_unlock_irqrestore(&dvtaskQ_lock, lflags); - } - hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV; - } + if (hd->ioc->bus_type == SCSI) { + int dvStatus = hd->ioc->spi_data.dvStatus[target]; + int issueCmd = 1; + + if (dvStatus || hd->ioc->spi_data.forceDv) { + + if ((dvStatus & MPT_SCSICFG_NEED_DV) || + (hd->ioc->spi_data.forceDv & MPT_SCSICFG_NEED_DV)) { + unsigned long lflags; + /* Schedule DV if necessary */ + spin_lock_irqsave(&dvtaskQ_lock, lflags); + if (!dvtaskQ_active) { + dvtaskQ_active = 1; + spin_unlock_irqrestore(&dvtaskQ_lock, lflags); + INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); - /* Trying to do DV to this target, extend timeout. - * Wait to issue until flag is clear - */ - if (dvStatus & MPT_SCSICFG_DV_PENDING) { - mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); - issueCmd = 0; + schedule_work(&mptscsih_dvTask); + } else { + spin_unlock_irqrestore(&dvtaskQ_lock, lflags); } + hd->ioc->spi_data.forceDv &= ~MPT_SCSICFG_NEED_DV; + } - /* Set the DV flags. - */ - if (dvStatus & MPT_SCSICFG_DV_NOT_DONE) - mptscsih_set_dvflags(hd, pScsiReq); -#endif + /* Trying to do DV to this target, extend timeout. + * Wait to issue until flag is clear + */ + if (dvStatus & MPT_SCSICFG_DV_PENDING) { + mod_timer(&SCpnt->eh_timeout, jiffies + 40 * HZ); + issueCmd = 0; } - } -#ifdef MPTSCSIH_DBG_TIMEOUT - if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) { - foo_to[hd->ioc->timeout_cnt] = SCpnt; - hd->ioc->timeout_cnt++; - //mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta); - issueCmd = 0; - printk(MYIOC_s_WARN_FMT - "to pendingQ: (sc=%p, mf=%p, time=%ld)\n", - hd->ioc->name, SCpnt, mf, jiffies); + /* Set the DV flags. + */ + if (dvStatus & MPT_SCSICFG_DV_NOT_DONE) + mptscsih_set_dvflags(hd, pScsiReq); + + if (!issueCmd) + goto fail; } + } #endif - if (issueCmd) { - mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); - dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", - hd->ioc->name, SCpnt, mf, my_idx)); - DBG_DUMP_REQUEST_FRAME(mf) - } else - goto fail; - } else - goto fail; - + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc, mf); + dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", + hd->ioc->name, SCpnt, mf, my_idx)); + DBG_DUMP_REQUEST_FRAME(mf) return 0; fail: @@ -2216,11 +2023,6 @@ } } -#ifdef MPTSCSIH_DBG_TIMEOUT - if (hd->ioc->timeout_hard) - rc = 1; -#endif - /* Only fall through to the HRH if this is a bus reset */ if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc || @@ -2457,9 +2259,9 @@ printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n", hd->ioc->name, SCpnt); - /* Unsupported for SCSI. Supported for FCP + /* Supported for FC only. */ - if (hd->is_spi) + if (hd->ioc->bus_type == SCSI) return FAILED; spin_unlock_irq(host_lock); @@ -2767,39 +2569,56 @@ mptscsih_slave_alloc(struct scsi_device *device) { struct Scsi_Host *host = device->host; - MPT_SCSI_HOST *hd; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; VirtDevice *vdev; - - hd = (MPT_SCSI_HOST *)host->hostdata; + uint target = device->id; if (hd == NULL) return -ENODEV; - if ((vdev = hd->Targets[device->id]) == NULL) { - if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) { - printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%d) FAILED!\n", - hd->ioc->name, (int)sizeof(VirtDevice)); - return -ENOMEM; - } else { - memset(vdev, 0, sizeof(VirtDevice)); - vdev->tflags = MPT_TARGET_FLAGS_Q_YES; - vdev->ioc_id = hd->ioc->id; - vdev->target_id = device->id; - vdev->bus_id = device->channel; - vdev->raidVolume = 0; - hd->Targets[device->id] = vdev; - if (hd->is_spi) { - if (hd->ioc->spi_data.isRaid & (1 << device->id)) { - vdev->raidVolume = 1; - ddvtprintk((KERN_INFO - "RAID Volume @ id %d\n", device->id)); - } - } else { - vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; - } + if ((vdev = hd->Targets[target]) != NULL) + goto out; + + vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdev) { + printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", + hd->ioc->name, sizeof(VirtDevice)); + return -ENOMEM; + } + + memset(vdev, 0, sizeof(VirtDevice)); + vdev->tflags = MPT_TARGET_FLAGS_Q_YES; + vdev->ioc_id = hd->ioc->id; + vdev->target_id = device->id; + vdev->bus_id = device->channel; + vdev->raidVolume = 0; + hd->Targets[device->id] = vdev; + if (hd->ioc->bus_type == SCSI) { + if (hd->ioc->spi_data.isRaid & (1 << device->id)) { + vdev->raidVolume = 1; + ddvtprintk((KERN_INFO + "RAID Volume @ id %d\n", device->id)); } + } else { + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; } + + out: vdev->num_luns++; + return 0; +} + +static int mptscsih_is_raid_volume(MPT_SCSI_HOST *hd, uint id) +{ + int i; + + if (!hd->ioc->spi_data.isRaid || !hd->ioc->spi_data.pIocPg3) + return 0; + + for (i = 0; i < hd->ioc->spi_data.pIocPg3->NumPhysDisks; i++) { + if (id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID) + return 1; + } return 0; } @@ -2812,59 +2631,37 @@ mptscsih_slave_destroy(struct scsi_device *device) { struct Scsi_Host *host = device->host; - MPT_SCSI_HOST *hd; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; VirtDevice *vdev; - int raid_volume=0; - - hd = (MPT_SCSI_HOST *)host->hostdata; + uint target = device->id; + uint lun = device->lun; if (hd == NULL) return; - mptscsih_search_running_cmds(hd, device->id, device->lun); - - /* Free memory and reset all flags for this target - */ - if ((vdev = hd->Targets[device->id]) != NULL) { - vdev->num_luns--; - - if (vdev->luns[0] & (1 << device->lun)) - vdev->luns[0] &= ~(1 << device->lun); - - /* Free device structure only if number of luns is 0. - */ - if (vdev->num_luns == 0) { - kfree(hd->Targets[device->id]); - hd->Targets[device->id] = NULL; - - if (!hd->is_spi) - return; + mptscsih_search_running_cmds(hd, target, lun); - if((hd->ioc->spi_data.isRaid) && (hd->ioc->spi_data.pIocPg3)) { - int i; - for(i=0;iioc->spi_data.pIocPg3->NumPhysDisks && - raid_volume==0;i++) - - if(device->id == - hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID) { - raid_volume=1; - hd->ioc->spi_data.forceDv |= - MPT_SCSICFG_RELOAD_IOC_PG3; - } - } + vdev = hd->Targets[target]; + vdev->luns[0] &= ~(1 << lun); + if (--vdev->num_luns) + return; - if(!raid_volume){ - hd->ioc->spi_data.dvStatus[device->id] = + kfree(hd->Targets[target]); + hd->Targets[target] = NULL; + + if (hd->ioc->bus_type == SCSI) { + if (mptscsih_is_raid_volume(hd, target)) { + hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3; + } else { + hd->ioc->spi_data.dvStatus[target] = MPT_SCSICFG_NEGOTIATE; - if (hd->negoNvram == 0) - hd->ioc->spi_data.dvStatus[device->id] - |= MPT_SCSICFG_DV_NOT_DONE; + if (!hd->negoNvram) { + hd->ioc->spi_data.dvStatus[target] |= + MPT_SCSICFG_DV_NOT_DONE; } } } - - return; } static void @@ -2874,7 +2671,7 @@ int max_depth; int tagged; - if ( hd->is_spi ) { + if (hd->ioc->bus_type == SCSI) { if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) max_depth = 1; @@ -2989,7 +2786,6 @@ return count; } - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Private routines... @@ -3125,10 +2921,6 @@ mpt_free_msg_frame(ioc, hd->tmPtr); } -#ifdef MPTSCSIH_DBG_TIMEOUT - ioc->timeout_hard = 0; -#endif - dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name)); } else { @@ -3158,7 +2950,7 @@ /* 4. Renegotiate to all devices, if SCSI */ - if (hd->is_spi) { + if (ioc->bus_type == SCSI) { dnegoprintk(("writeSDP1: ALL_IDS USE_NVRAM\n")); mptscsih_writeSDP1(hd, 0, 0, MPT_SCSICFG_ALL_IDS | MPT_SCSICFG_USE_NVRAM); } @@ -3187,7 +2979,7 @@ /* 7. Set flag to force DV and re-read IOC Page 3 */ - if (hd->is_spi) { + if (ioc->bus_type == SCSI) { ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3; ddvtprintk(("Set reload IOC Pg3 Flag\n")); } @@ -3218,7 +3010,7 @@ hd = NULL; if (ioc->sh) { hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if (hd && (hd->is_spi) && (hd->soft_resets < -1)) + if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1)) hd->soft_resets++; } break; @@ -3247,7 +3039,7 @@ if (ioc->sh) hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if (hd && (hd->is_spi) && (hd->negoNvram == 0)) { + if (hd && (ioc->bus_type == SCSI) && (hd->negoNvram == 0)) { ScsiCfgData *pSpi; Ioc3PhysDisk_t *pPDisk; int numPDisk; @@ -3394,7 +3186,7 @@ indexed_lun = (lun % 32); vdev->luns[lun_index] |= (1 << indexed_lun); - if (hd->is_spi) { + if (hd->ioc->bus_type == SCSI) { if ((data[0] == TYPE_PROCESSOR) && (hd->ioc->spi_data.Saf_Te)) { /* Treat all Processors as SAF-TE if * command line option is set */ @@ -4675,7 +4467,7 @@ /* Write SDP1 for all SCSI devices * Alloc memory and set up config buffer */ - if (hd->is_spi) { + if (ioc->bus_type == SCSI) { if (ioc->spi_data.sdp1length > 0) { pcfg1Data = (SCSIDevicePage1_t *)pci_alloc_consistent(ioc->pcidev, ioc->spi_data.sdp1length * 4, &cfg1_dma_addr); @@ -4818,7 +4610,7 @@ msleep(250); /* DV only to SCSI adapters */ - if ((int)ioc->chip_type <= (int)FC929) + if (ioc->bus_type != SCSI) continue; /* Make sure everything looks ok */ @@ -6289,107 +6081,6 @@ #endif /* ~MPTSCSIH_ENABLE_DOMAIN_VALIDATION */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Commandline Parsing routines and defines. - * - * insmod format: - * insmod mptscsih mptscsih="width:1 dv:n factor:0x09 saf-te:1" - * boot format: - * mptscsih=width:1,dv:n,factor:0x8,saf-te:1 - * - */ -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - -#ifdef MODULE -static char setup_token[] __initdata = - "dv:" - "width:" - "factor:" - "saf-te:" - ; /* DO NOT REMOVE THIS ';' */ -#endif - -#define OPT_DV 1 -#define OPT_MAX_WIDTH 2 -#define OPT_MIN_SYNC_FACTOR 3 -#define OPT_SAF_TE 4 - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -#ifdef MODULE -static int -get_setup_token(char *p) -{ - char *cur = setup_token; - char *pc; - int i = 0; - - while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { - ++pc; - ++i; - if (!strncmp(p, cur, pc - cur)) - return i; - cur = pc; - } - return 0; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static int -mptscsih_setup(char *str) -{ - char *cur = str; - char *pc, *pv; - unsigned long val; - int c; - - while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { - char *pe; - - val = 0; - pv = pc; - c = *++pv; - - if (c == 'n') - val = 0; - else if (c == 'y') - val = 1; - else - val = (int) simple_strtoul(pv, &pe, 0); - - printk("Found Token: %s, value %x\n", cur, (int)val); - switch (get_setup_token(cur)) { - case OPT_DV: - driver_setup.dv = val; - break; - - case OPT_MAX_WIDTH: - driver_setup.max_width = val; - break; - - case OPT_MIN_SYNC_FACTOR: - driver_setup.min_sync_fac = val; - break; - - case OPT_SAF_TE: - driver_setup.saf_te = val; - break; - - default: - printk("mptscsih_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); - break; - } - - if ((cur = strchr(cur, ARG_SEP)) != NULL) - ++cur; - } - return 1; -} -#endif -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - module_init(mptscsih_init); module_exit(mptscsih_exit); diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h --- a/drivers/message/fusion/mptscsih.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/message/fusion/mptscsih.h 2004-12-12 17:40:53 -08:00 @@ -95,17 +95,8 @@ { u8 dv; u8 max_width; - u8 min_sync_fac; + u8 min_sync_factor; u8 saf_te; }; - - -#define MPTSCSIH_DRIVER_SETUP \ -{ \ - MPTSCSIH_DOMAIN_VALIDATION, \ - MPTSCSIH_MAX_WIDTH, \ - MPTSCSIH_MIN_SYNC, \ - MPTSCSIH_SAF_TE, \ -} #endif diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c --- a/drivers/net/eepro100.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/net/eepro100.c 2004-12-12 17:40:53 -08:00 @@ -2328,6 +2328,8 @@ outl(PortPartialReset, ioaddr + SCBPort); /* XXX call pci_set_power_state ()? */ + pci_disable_device(pdev); + pci_set_power_state (pdev, 3); return 0; } @@ -2337,7 +2339,10 @@ struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; + pci_set_power_state(pdev, 0); pci_restore_state(pdev); + pci_enable_device(pdev); + pci_set_master(pdev); if (!netif_running(dev)) return 0; diff -Nru a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c --- a/drivers/net/ibmveth.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/net/ibmveth.c 2004-12-12 17:40:52 -08:00 @@ -96,6 +96,7 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static inline void ibmveth_schedule_replenishing(struct ibmveth_adapter*); #ifdef CONFIG_PROC_FS #define IBMVETH_PROC_DIR "ibmveth" @@ -104,7 +105,7 @@ static const char ibmveth_driver_name[] = "ibmveth"; static const char ibmveth_driver_string[] = "IBM i/pSeries Virtual Ethernet Driver"; -#define ibmveth_driver_version "1.02" +#define ibmveth_driver_version "1.03" MODULE_AUTHOR("Santiago Leon "); MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver"); @@ -271,6 +272,8 @@ adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8); atomic_inc(&adapter->not_replenishing); + + ibmveth_schedule_replenishing(adapter); } /* kick the replenish tasklet if we need replenishing and it isn't already running */ diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c --- a/drivers/net/irda/irda-usb.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/net/irda/irda-usb.c 2004-12-12 17:40:52 -08:00 @@ -52,7 +52,7 @@ /*------------------------------------------------------------------*/ #include - +#include #include #include #include @@ -88,10 +88,10 @@ /* * Important note : - * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not compliant - * with the USB-IrDA specification (and actually very very different), and - * there is no way this driver can support those devices, apart from - * a complete rewrite... + * Devices based on the SigmaTel chipset (0x66f, 0x4200) are not designed + * using the "USB-IrDA specification" (yes, there exist such a thing), and + * therefore not supported by this driver (don't add them above). + * There is a Linux driver, stir4200, that support those USB devices. * Jean II */ @@ -1007,9 +1007,9 @@ } /* Cancel Tx and speed URB - need to be synchronous to avoid races */ self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK; - usb_unlink_urb(self->tx_urb); + usb_kill_urb(self->tx_urb); self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK; - usb_unlink_urb(self->speed_urb); + usb_kill_urb(self->speed_urb); /* Stop and remove instance of IrLAP */ if (self->irlap) @@ -1520,9 +1520,9 @@ /* Cancel Tx and speed URB. * Toggle flags to make sure it's synchronous. */ self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK; - usb_unlink_urb(self->tx_urb); + usb_kill_urb(self->tx_urb); self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK; - usb_unlink_urb(self->speed_urb); + usb_kill_urb(self->speed_urb); } /* Cleanup the device stuff */ @@ -1593,7 +1593,7 @@ /* * Module parameters */ -MODULE_PARM(qos_mtt_bits, "i"); +module_param(qos_mtt_bits, int, 0); MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli and Jean Tourrilhes "); MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); diff -Nru a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c --- a/drivers/net/irda/stir4200.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/net/irda/stir4200.c 2004-12-12 17:40:52 -08:00 @@ -705,7 +705,7 @@ static void receive_stop(struct stir_cb *stir) { stir->receiving = 0; - usb_unlink_urb(stir->rx_urb); + usb_kill_urb(stir->rx_urb); if (stir->rx_buff.in_frame) stir->stats.collisions++; @@ -974,7 +974,7 @@ kfree(stir->fifo_status); /* Mop up receive urb's */ - usb_unlink_urb(stir->rx_urb); + usb_kill_urb(stir->rx_urb); kfree(stir->io_buf); usb_free_urb(stir->rx_urb); diff -Nru a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c --- a/drivers/net/irda/via-ircc.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/net/irda/via-ircc.c 2004-12-12 17:40:52 -08:00 @@ -75,6 +75,9 @@ /* We can't guess the type of connected dongle, user *must* supply it. */ MODULE_PARM(dongle_id, "i"); +/* FIXME : we should not need this, because instances should be automatically + * managed by the PCI layer. Especially that we seem to only be using the + * first entry. Jean II */ /* Max 4 instances for now */ static struct via_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; @@ -153,11 +156,9 @@ IRDA_DEBUG(3, "%s()\n", __FUNCTION__); rc = pci_register_driver(&via_driver); - if (rc < 1) { + if (rc < 0) { IRDA_DEBUG(0, "%s(): error rc = %d, returning -ENODEV...\n", __FUNCTION__, rc); - if (rc == 0) - pci_unregister_driver (&via_driver); return -ENODEV; } return 0; @@ -288,15 +289,27 @@ { IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + /* FIXME : This is ugly. We should use pci_get_drvdata(pdev); + * to get our driver instance and call directly via_ircc_close(). + * See vlsi_ir for details... + * Jean II */ via_ircc_clean(); + /* FIXME : This should be in via_ircc_close(), because here we may + * theoritically disable still configured devices :-( - Jean II */ + pci_disable_device(pdev); } static void __exit via_ircc_cleanup(void) { IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + /* FIXME : This should be redundant, as pci_unregister_driver() + * should call via_remove_one() on each device. + * Jean II */ via_ircc_clean(); + + /* Cleanup all instances of the driver */ pci_unregister_driver (&via_driver); } @@ -323,6 +336,10 @@ self->netdev = dev; spin_lock_init(&self->lock); + /* FIXME : We should store our driver instance in the PCI layer, + * using pci_set_drvdata(), not in this array. + * See vlsi_ir for details... - Jean II */ + /* FIXME : 'i' is always 0 (see via_init_one()) :-( - Jean II */ /* Need to store self somewhere */ dev_self[i] = self; self->index = i; diff -Nru a/drivers/net/r8169.c b/drivers/net/r8169.c --- a/drivers/net/r8169.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/net/r8169.c 2004-12-12 17:40:52 -08:00 @@ -150,6 +150,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = { {0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x1186, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,}, }; diff -Nru a/drivers/net/smc91x.c b/drivers/net/smc91x.c --- a/drivers/net/smc91x.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/net/smc91x.c 2004-12-12 17:40:53 -08:00 @@ -1244,6 +1244,11 @@ spin_lock(&lp->lock); + /* A preamble may be used when there is a potential race + * between the interruptible transmit functions and this + * ISR. */ + SMC_INTERRUPT_PREAMBLE; + saved_pointer = SMC_GET_PTR(); mask = SMC_GET_INT_MASK(); SMC_SET_INT_MASK(0); diff -Nru a/drivers/net/smc91x.h b/drivers/net/smc91x.h --- a/drivers/net/smc91x.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/net/smc91x.h 2004-12-12 17:40:53 -08:00 @@ -193,6 +193,53 @@ #define RPC_LSA_DEFAULT RPC_LED_TX_RX #define RPC_LSB_DEFAULT RPC_LED_100_10 +#elif defined(CONFIG_MACH_LPD7A400) || defined(CONFIG_MACH_LPD7A404) + +/* The LPD7A40X_IOBARRIER is necessary to overcome a mismatch between + * the way that the CPU handles chip selects and the way that the SMC + * chip expects the chip select to operate. Refer to + * Documentation/arm/Sharp-LH/IOBarrier for details. The read from + * IOBARRIER is a byte as a least-common denominator of possible + * regions to use as the barrier. It would be wasteful to read 32 + * bits from a byte oriented region. + * + * There is no explicit protection against interrupts intervening + * between the writew and the IOBARRIER. In SMC ISR there is a + * preamble that performs an IOBARRIER in the extremely unlikely event + * that the driver interrupts itself between a writew to the chip an + * the IOBARRIER that follows *and* the cache is large enough that the + * first off-chip access while handing the interrupt is to the SMC + * chip. Other devices in the same address space as the SMC chip must + * be aware of the potential for trouble and perform a similar + * IOBARRIER on entry to their ISR. + */ + +#include /* IOBARRIER_VIRT */ + +#define SMC_CAN_USE_8BIT 0 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 0 +#define SMC_NOWAIT 0 +#define LPD7A40X_IOBARRIER readb (IOBARRIER_VIRT) + +#define SMC_inw(a,r) readw ((void*) ((a) + (r))) +#define SMC_insw(a,r,p,l) readsw ((void*) ((a) + (r)), p, l) +#define SMC_outw(v,a,r) ({ writew ((v), (a) + (r)); LPD7A40X_IOBARRIER; }) + +static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) +{ + unsigned short* ps = (unsigned short*) p; + while (l-- > 0) { + writew (*ps++, a + r); + LPD7A40X_IOBARRIER; + } +} + +#define SMC_INTERRUPT_PREAMBLE LPD7A40X_IOBARRIER + +#define RPC_LSA_DEFAULT RPC_LED_TX_RX +#define RPC_LSB_DEFAULT RPC_LED_100_10 + #else #define SMC_CAN_USE_8BIT 1 @@ -894,5 +941,8 @@ }) #endif +#if !defined (SMC_INTERRUPT_PREAMBLE) +# define SMC_INTERRUPT_PREAMBLE +#endif #endif /* _SMC91X_H_ */ diff -Nru a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h --- a/drivers/s390/scsi/zfcp_def.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/s390/scsi/zfcp_def.h 2004-12-12 17:40:52 -08:00 @@ -34,8 +34,7 @@ #ifndef ZFCP_DEF_H #define ZFCP_DEF_H -/* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_DEF_REVISION "$Revision: 1.110 $" +#define ZFCP_DEF_REVISION "$Revision: 1.111 $" /*************************** INCLUDES *****************************************/ @@ -70,6 +69,7 @@ /********************* GENERAL DEFINES *********************************/ +/* zfcp version number, it consists of major, minor, and patch-level number */ #define ZFCP_VERSION "4.2.0" /** diff -Nru a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c --- a/drivers/s390/scsi/zfcp_erp.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/s390/scsi/zfcp_erp.c 2004-12-12 17:40:52 -08:00 @@ -31,8 +31,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP -/* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_ERP_REVISION "$Revision: 1.83 $" +#define ZFCP_ERP_REVISION "$Revision: 1.85 $" #include "zfcp_ext.h" @@ -3482,9 +3481,8 @@ debug_text_event(adapter->erp_dbf, 3, "p_access_block"); debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof(wwn_t)); read_lock_irqsave(&zfcp_data.config_lock, flags); - zfcp_erp_modify_port_status(port, - ZFCP_STATUS_COMMON_ERP_FAILED | ZFCP_STATUS_COMMON_ACCESS_DENIED, - ZFCP_SET); + zfcp_erp_modify_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); read_unlock_irqrestore(&zfcp_data.config_lock, flags); } @@ -3500,9 +3498,8 @@ debug_text_event(adapter->erp_dbf, 3, "u_access_block"); debug_event(adapter->erp_dbf, 3, &unit->fcp_lun, sizeof(fcp_lun_t)); - zfcp_erp_modify_unit_status(unit, - ZFCP_STATUS_COMMON_ERP_FAILED | ZFCP_STATUS_COMMON_ACCESS_DENIED, - ZFCP_SET); + zfcp_erp_modify_unit_status(unit, ZFCP_STATUS_COMMON_ERP_FAILED | + ZFCP_STATUS_COMMON_ACCESS_DENIED, ZFCP_SET); } /* @@ -3541,19 +3538,21 @@ debug_text_event(adapter->erp_dbf, 3, "p_access_unblock"); debug_event(adapter->erp_dbf, 3, &port->wwpn, sizeof(wwn_t)); - if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status)) { + if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, + &port->status)) { if (!atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) list_for_each_entry(unit, &port->unit_list_head, list) zfcp_erp_unit_access_changed(unit); return; } - ZFCP_LOG_NORMAL("Trying to reopen port 0x%016Lx on adapter %s " - "due to update to access control table\n", + ZFCP_LOG_NORMAL("reopen of port 0x%016Lx on adapter %s " + "(due to ACT update)\n", port->wwpn, zfcp_get_busid_by_adapter(adapter)); if (zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED) != 0) - ZFCP_LOG_NORMAL("Reopen of port 0x%016Lx on adapter %s failed\n", - port->wwpn, zfcp_get_busid_by_adapter(adapter)); + ZFCP_LOG_NORMAL("failed reopen of port" + "(adapter %s, wwpn=0x%016Lx)\n", + zfcp_get_busid_by_adapter(adapter), port->wwpn); } /* @@ -3572,16 +3571,15 @@ if (!atomic_test_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status)) return; - ZFCP_LOG_NORMAL("Trying to reopen unit 0x%016Lx " - "on port 0x%016Lx on adapter %s " - "due to update to access control table\n", + ZFCP_LOG_NORMAL("reopen of unit 0x%016Lx on port 0x%016Lx " + " on adapter %s (due to ACT update)\n", unit->fcp_lun, unit->port->wwpn, zfcp_get_busid_by_adapter(adapter)); if (zfcp_erp_unit_reopen(unit, ZFCP_STATUS_COMMON_ERP_FAILED) != 0) - ZFCP_LOG_NORMAL("Reopen of unit 0x%016Lx " - "on port 0x%016Lx on adapter %s failed\n", - unit->fcp_lun, unit->port->wwpn, - zfcp_get_busid_by_adapter(adapter)); + ZFCP_LOG_NORMAL("failed reopen of unit (adapter %s, " + "wwpn=0x%016Lx, fcp_lun=0x%016Lx)\n", + zfcp_get_busid_by_adapter(adapter), + unit->port->wwpn, unit->fcp_lun); } #undef ZFCP_LOG_AREA diff -Nru a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h --- a/drivers/s390/scsi/zfcp_ext.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/s390/scsi/zfcp_ext.h 2004-12-12 17:40:52 -08:00 @@ -31,8 +31,8 @@ #ifndef ZFCP_EXT_H #define ZFCP_EXT_H -/* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_EXT_REVISION "$Revision: 1.61 $" + +#define ZFCP_EXT_REVISION "$Revision: 1.62 $" #include "zfcp_def.h" diff -Nru a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c --- a/drivers/s390/scsi/zfcp_fsf.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/s390/scsi/zfcp_fsf.c 2004-12-12 17:40:53 -08:00 @@ -30,8 +30,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_FSF_C_REVISION "$Revision: 1.86 $" +#define ZFCP_FSF_C_REVISION "$Revision: 1.88 $" #include "zfcp_ext.h" @@ -1737,7 +1736,7 @@ adapter = els->adapter; ret = zfcp_fsf_req_create(adapter, FSF_QTCB_SEND_ELS, - ZFCP_WAIT_FOR_SBAL|ZFCP_REQ_AUTO_CLEANUP, + ZFCP_REQ_AUTO_CLEANUP, NULL, &lock_flags, &fsf_req); if (ret < 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " @@ -3094,57 +3093,11 @@ exclusive = bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE; readwrite = bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER; - if (!adapter->supported_features & FSF_FEATURE_CFDC) - goto no_cfdc; - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_UNIT_SHARED | ZFCP_STATUS_UNIT_READONLY, &unit->status); - if (!allowed) - atomic_set_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &unit->status); - - if (!adapter->supported_features & FSF_FEATURE_LUN_SHARING) - goto no_lun_sharing; - - if (!exclusive) - atomic_set_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); - - if (!readwrite) { - atomic_set_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); - ZFCP_LOG_NORMAL("Unit 0x%016Lx on port 0x%016Lx on adapter %s " - "accessed read-only\n", unit->fcp_lun, - unit->port->wwpn, zfcp_get_busid_by_unit(unit)); - } - - if (exclusive && !readwrite) { - ZFCP_LOG_NORMAL("Exclusive access of read-only unit not " - "supported\n"); - zfcp_erp_unit_failed(unit); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - goto skip_fsfstatus; - } - if (!exclusive && readwrite) { - ZFCP_LOG_NORMAL("Shared access of read-write unit is not " - "supported\n"); - zfcp_erp_unit_failed(unit); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - goto skip_fsfstatus; - } - - no_lun_sharing: - no_cfdc: - if (!(adapter->supported_features & FSF_FEATURE_CFDC) && - (adapter->supported_features & FSF_FEATURE_LUN_SHARING)) { - ZFCP_LOG_NORMAL("LUN sharing without access control is not " - "supported.\n"); - zfcp_erp_unit_failed(unit); - fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; - goto skip_fsfstatus; - } - - /* evaluate FSF status in QTCB */ switch (header->fsf_status) { @@ -3196,6 +3149,8 @@ } debug_text_event(adapter->erp_dbf, 1, "fsf_s_access"); zfcp_erp_unit_access_denied(unit); + atomic_clear_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); + atomic_clear_mask(ZFCP_STATUS_UNIT_READONLY, &unit->status); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; diff -Nru a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c --- a/drivers/s390/scsi/zfcp_scsi.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/s390/scsi/zfcp_scsi.c 2004-12-12 17:40:53 -08:00 @@ -31,8 +31,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI -/* this drivers version (do not edit !!! generated and updated by cvs) */ -#define ZFCP_SCSI_REVISION "$Revision: 1.73 $" +#define ZFCP_SCSI_REVISION "$Revision: 1.74 $" #include "zfcp_ext.h" diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig 2004-12-12 17:40:53 -08:00 +++ b/drivers/scsi/Kconfig 2004-12-12 17:40:53 -08:00 @@ -1767,7 +1767,7 @@ config ZFCP tristate "FCP host bus adapter driver for IBM eServer zSeries" - depends on ARCH_S390 && SCSI + depends on ARCH_S390 && QDIO && SCSI select SCSI_FC_ATTRS help If you want to access SCSI devices attached to your IBM eServer diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c --- a/drivers/scsi/aacraid/aachba.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/aacraid/aachba.c 2004-12-12 17:40:52 -08:00 @@ -645,9 +645,31 @@ dev->adapter_info.serial[1]); dev->nondasd_support = 0; + dev->raid_scsi_mode = 0; if(dev->adapter_info.options & AAC_OPT_NONDASD){ dev->nondasd_support = 1; } + + /* + * If the firmware supports ROMB RAID/SCSI mode and we are currently + * in RAID/SCSI mode, set the flag. For now if in this mode we will + * force nondasd support on. If we decide to allow the non-dasd flag + * additional changes changes will have to be made to support + * RAID/SCSI. the function aac_scsi_cmd in this module will have to be + * changed to support the new dev->raid_scsi_mode flag instead of + * leaching off of the dev->nondasd_support flag. Also in linit.c the + * function aac_detect will have to be modified where it sets up the + * max number of channels based on the aac->nondasd_support flag only. + */ + if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) && + (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) { + dev->nondasd_support = 1; + dev->raid_scsi_mode = 1; + } + if (dev->raid_scsi_mode != 0) + printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n", + dev->name, dev->id); + if(nondasd != -1) { dev->nondasd_support = (nondasd!=0); } @@ -1137,7 +1159,7 @@ char *cp; dprintk((KERN_DEBUG "READ CAPACITY command.\n")); - if (fsa_dev_ptr[cid].size <= 0x100000000) + if (fsa_dev_ptr[cid].size <= 0x100000000LL) capacity = fsa_dev_ptr[cid].size - 1; else capacity = (u32)-1; @@ -1446,8 +1468,17 @@ if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER || (b==TYPE_DISK && (b1&0x80)) ){ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + /* + * We will allow disk devices if in RAID/SCSI mode and + * the channel is 2 + */ + } else if ((dev->raid_scsi_mode) && + (scsicmd->device->channel == 2)) { + scsicmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8; } else { - scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; + scsicmd->result = DID_NO_CONNECT << 16 | + COMMAND_COMPLETE << 8; } } else { scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; @@ -1479,8 +1510,17 @@ if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER || (b==TYPE_DISK && (b1&0x80)) ){ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + /* + * We will allow disk devices if in RAID/SCSI mode and + * the channel is 2 + */ + } else if ((dev->raid_scsi_mode) && + (scsicmd->device->channel == 2)) { + scsicmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8; } else { - scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; + scsicmd->result = DID_NO_CONNECT << 16 | + COMMAND_COMPLETE << 8; } break; } diff -Nru a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h --- a/drivers/scsi/aacraid/aacraid.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/aacraid/aacraid.h 2004-12-12 17:40:52 -08:00 @@ -805,6 +805,8 @@ #define AAC_OPT_SGMAP_HOST64 cpu_to_le32(1<<10) #define AAC_OPT_ALARM cpu_to_le32(1<<11) #define AAC_OPT_NONDASD cpu_to_le32(1<<12) +#define AAC_OPT_SCSI_MANAGED cpu_to_le32(1<<13) +#define AAC_OPT_RAID_SCSI_MODE cpu_to_le32(1<<14) struct aac_dev { @@ -877,6 +879,7 @@ */ u8 nondasd_support; u8 dac_support; + u8 raid_scsi_mode; }; #define aac_adapter_interrupt(dev) \ diff -Nru a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c --- a/drivers/scsi/ahci.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/ahci.c 2004-12-12 17:40:52 -08:00 @@ -229,7 +229,8 @@ { .sht = &ahci_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO, + ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | + ATA_FLAG_PIO_DMA, .pio_mask = 0x03, /* pio3-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h --- a/drivers/scsi/aic7xxx/aic79xx_osm.h 2004-12-12 17:40:53 -08:00 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h 2004-12-12 17:40:53 -08:00 @@ -540,7 +540,7 @@ uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ - dma_addr_t hw_dma_mask; + uint64_t hw_dma_mask; ahd_linux_softc_flags flags; }; diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2004-12-12 17:40:52 -08:00 @@ -170,24 +170,22 @@ if (sizeof(dma_addr_t) > 4) { uint64_t memsize; - dma_addr_t mask_64bit; - dma_addr_t mask_39bit; + const uint64_t mask_39bit = 0x7FFFFFFFFFULL; memsize = ahd_linux_get_memsize(); - mask_64bit = (dma_addr_t)0xFFFFFFFFFFFFFFFFULL; - mask_39bit = (dma_addr_t)0x7FFFFFFFFFULL; + if (memsize >= 0x8000000000ULL - && pci_set_dma_mask(pdev, mask_64bit) == 0) { + && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { ahd->flags |= AHD_64BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = mask_64bit; + ahd->platform_data->hw_dma_mask = DMA_64BIT_MASK; } else if (memsize > 0x80000000 && pci_set_dma_mask(pdev, mask_39bit) == 0) { ahd->flags |= AHD_39BIT_ADDRESSING; ahd->platform_data->hw_dma_mask = mask_39bit; } } else { - pci_set_dma_mask(pdev, 0xFFFFFFFF); - ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; + pci_set_dma_mask(pdev, DMA_32BIT_MASK); + ahd->platform_data->hw_dma_mask = DMA_32BIT_MASK; } ahd->dev_softc = pci; error = ahd_pci_config(ahd, entry); diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h 2004-12-12 17:40:52 -08:00 @@ -545,7 +545,7 @@ uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ - dma_addr_t hw_dma_mask; + uint64_t hw_dma_mask; ahc_linux_softc_flags flags; }; diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c 2004-12-12 17:40:52 -08:00 @@ -175,7 +175,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { char buf[80]; - dma_addr_t mask_39bit; + const uint64_t mask_39bit = 0x7FFFFFFFFFULL; struct ahc_softc *ahc; ahc_dev_softc_t pci; struct ahc_pci_identity *entry; @@ -226,18 +226,17 @@ } pci_set_master(pdev); - mask_39bit = 0x7FFFFFFFFFULL; if (sizeof(dma_addr_t) > 4 && ahc_linux_get_memsize() > 0x80000000 && pci_set_dma_mask(pdev, mask_39bit) == 0) { ahc->flags |= AHC_39BIT_ADDRESSING; ahc->platform_data->hw_dma_mask = mask_39bit; } else { - if (pci_set_dma_mask(pdev, 0xFFFFFFFF)) { + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); return (-ENODEV); } - ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; + ahc->platform_data->hw_dma_mask = DMA_32BIT_MASK; } #endif ahc->dev_softc = pci; diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/libata-core.c 2004-12-12 17:40:52 -08:00 @@ -1950,8 +1950,6 @@ sg->page = virt_to_page(buf); sg->offset = (unsigned long) buf & ~PAGE_MASK; sg_dma_len(sg) = buflen; - - WARN_ON(buflen > PAGE_SIZE); } void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, @@ -2693,6 +2691,30 @@ VPRINTK("EXIT\n"); } +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_DMA: + case ATA_PROT_ATAPI_DMA: + return 1; + + case ATA_PROT_ATAPI: + case ATA_PROT_PIO: + case ATA_PROT_PIO_MULT: + 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 @@ -2713,12 +2735,16 @@ { struct ata_port *ap = qc->ap; - if (qc->flags & ATA_QCFLAG_SG) { - if (ata_sg_setup(qc)) - goto err_out; - } else if (qc->flags & ATA_QCFLAG_SINGLE) { - if (ata_sg_setup_one(qc)) - goto err_out; + if (ata_should_dma_map(qc)) { + if (qc->flags & ATA_QCFLAG_SG) { + if (ata_sg_setup(qc)) + goto err_out; + } else if (qc->flags & ATA_QCFLAG_SINGLE) { + if (ata_sg_setup_one(qc)) + goto err_out; + } + } else { + qc->flags &= ~ATA_QCFLAG_DMAMAP; } ap->ops->qc_prep(qc); diff -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c --- a/drivers/scsi/libata-scsi.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/libata-scsi.c 2004-12-12 17:40:52 -08:00 @@ -898,7 +898,7 @@ }; memcpy(rbuf, hdr, sizeof(hdr)); - if (buflen > (ATA_SERNO_LEN + 4)) + if (buflen > (ATA_SERNO_LEN + 4 - 1)) ata_dev_id_string(args->id, (unsigned char *) &rbuf[4], ATA_ID_SERNO_OFS, ATA_SERNO_LEN); @@ -927,7 +927,7 @@ rbuf[3] = 4 + strlen(inq_83_str); /* page len */ /* our one and only identification descriptor (vendor-specific) */ - if (buflen > (strlen(inq_83_str) + 4 + 4)) { + if (buflen > (strlen(inq_83_str) + 4 + 4 - 1)) { rbuf[4 + 0] = 2; /* code set: ASCII */ rbuf[4 + 3] = strlen(inq_83_str); memcpy(rbuf + 4 + 4, inq_83_str, strlen(inq_83_str)); diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c --- a/drivers/scsi/scsi_devinfo.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/scsi_devinfo.c 2004-12-12 17:40:52 -08:00 @@ -118,6 +118,7 @@ * Other types of devices that have special flags. * Note that all USB devices should have the BLIST_INQUIRY_36 flag. */ + {"3PARdata", "VV", NULL, BLIST_REPORTLUN2}, {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, {"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN}, diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/scsi_lib.c 2004-12-12 17:40:52 -08:00 @@ -728,7 +728,7 @@ req->sense_len = len; } } else - req->data_len -= cmd->bufflen; + req->data_len = cmd->resid; } /* diff -Nru a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c --- a/drivers/scsi/scsi_transport_spi.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/scsi/scsi_transport_spi.c 2004-12-12 17:40:52 -08:00 @@ -361,9 +361,8 @@ enum spi_signal_type type = spi_signal_to_value(buf); if (type != SPI_SIGNAL_UNKNOWN) - return count; + i->f->set_signalling(shost, type); - i->f->set_signalling(shost, type); return count; } static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR, @@ -635,7 +634,11 @@ /* OK, now we have our initial speed set by the read only inquiry * test, now try an echo buffer test (if the device allows it) */ - if ((len = spi_dv_device_get_echo_buffer(sreq, buffer)) == 0) { + len = 0; + if (sdev->ppr) + len = spi_dv_device_get_echo_buffer(sreq, buffer); + + if (len == 0) { SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n"); return; } diff -Nru a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c --- a/drivers/serial/serial_core.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/serial/serial_core.c 2004-12-12 17:40:52 -08:00 @@ -584,8 +584,10 @@ tmp.flags = port->flags; tmp.xmit_fifo_size = port->fifosize; tmp.baud_base = port->uartclk / 16; - tmp.close_delay = state->close_delay; - tmp.closing_wait = state->closing_wait; + tmp.close_delay = state->close_delay / 10; + tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ? + ASYNC_CLOSING_WAIT_NONE : + state->closing_wait / 10; tmp.custom_divisor = port->custom_divisor; tmp.hub6 = port->hub6; tmp.io_type = port->iotype; @@ -603,8 +605,8 @@ struct serial_struct new_serial; struct uart_port *port = state->port; unsigned long new_port; - unsigned int change_irq, change_port, old_flags; - unsigned int old_custom_divisor; + unsigned int change_irq, change_port, old_flags, closing_wait; + unsigned int old_custom_divisor, close_delay; int retval = 0; if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) @@ -615,6 +617,9 @@ new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; new_serial.irq = irq_canonicalize(new_serial.irq); + close_delay = new_serial.close_delay * 10; + closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? + USF_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; /* * This semaphore protects state->count. It is also @@ -646,8 +651,8 @@ retval = -EPERM; if (change_irq || change_port || (new_serial.baud_base != port->uartclk / 16) || - (new_serial.close_delay != state->close_delay) || - (new_serial.closing_wait != state->closing_wait) || + (close_delay != state->close_delay) || + (closing_wait != state->closing_wait) || (new_serial.xmit_fifo_size != port->fifosize) || (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0)) goto exit; @@ -751,8 +756,8 @@ port->flags = (port->flags & ~UPF_CHANGE_MASK) | (new_serial.flags & UPF_CHANGE_MASK); port->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay * HZ / 100; - state->closing_wait = new_serial.closing_wait * HZ / 100; + state->close_delay = close_delay; + state->closing_wait = closing_wait; port->fifosize = new_serial.xmit_fifo_size; if (state->info->tty) state->info->tty->low_latency = @@ -1191,7 +1196,7 @@ tty->closing = 1; if (state->closing_wait != USF_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, state->closing_wait); + tty_wait_until_sent(tty, msecs_to_jiffies(state->closing_wait)); /* * At this point, we stop accepting input. To do this, we @@ -1219,9 +1224,8 @@ state->info->tty = NULL; if (state->info->blocked_open) { - if (state->close_delay) { - msleep_interruptible(jiffies_to_msecs(state->close_delay)); - } + if (state->close_delay) + msleep_interruptible(state->close_delay); } else if (!uart_console(port)) { uart_change_pm(state, 3); } @@ -2082,8 +2086,8 @@ for (i = 0; i < drv->nr; i++) { struct uart_state *state = drv->state + i; - state->close_delay = 5 * HZ / 10; - state->closing_wait = 30 * HZ; + state->close_delay = 500; /* .5 seconds */ + state->closing_wait = 30000; /* 30 seconds */ init_MUTEX(&state->sem); } diff -Nru a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c --- a/drivers/serial/sunsab.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/serial/sunsab.c 2004-12-12 17:40:52 -08:00 @@ -143,6 +143,11 @@ writeb(SAB82532_CMDR_RMC, &up->regs->w.cmdr); } + /* Count may be zero for BRK, so we check for it here */ + if ((stat->sreg.isr1 & SAB82532_ISR1_BRK) && + (up->port.line == up->port.cons->index)) + saw_console_brk = 1; + for (i = 0; i < count; i++) { unsigned char ch = buf[i]; @@ -172,8 +177,6 @@ stat->sreg.isr0 &= ~(SAB82532_ISR0_PERR | SAB82532_ISR0_FERR); up->port.icount.brk++; - if (up->port.line == up->port.cons->index) - saw_console_brk = 1; /* * We do the SysRQ and SAK checking * here because otherwise the break @@ -325,8 +328,9 @@ tty = NULL; if (status.stat) { - if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | - SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) + if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | + SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || + (status.sreg.isr1 & SAB82532_ISR1_BRK)) tty = receive_chars(up, &status, regs); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & SAB82532_ISR1_CSC)) @@ -352,8 +356,10 @@ tty = NULL; if (status.stat) { - if (status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | - SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) + if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME | + SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) || + (status.sreg.isr1 & SAB82532_ISR1_BRK)) + tty = receive_chars(up, &status, regs); if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) || (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC))) diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c --- a/drivers/usb/core/inode.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/usb/core/inode.c 2004-12-12 17:40:52 -08:00 @@ -695,7 +695,7 @@ for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) { struct usb_config_descriptor *config = (struct usb_config_descriptor *)dev->rawdescriptors[i]; - i_size += le16_to_cpu (config->wTotalLength); + i_size += le16_to_cpu ((__force __le16)config->wTotalLength); } if (dev->usbfs_dentry->d_inode) dev->usbfs_dentry->d_inode->i_size = i_size; @@ -715,6 +715,7 @@ } while (!list_empty(&dev->filelist)) { ds = list_entry(dev->filelist.next, struct dev_state, list); + wake_up_all(&ds->wait); list_del_init(&ds->list); if (ds->discsignr) { sinfo.si_signo = SIGPIPE; diff -Nru a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig --- a/drivers/usb/host/Kconfig 2004-12-12 17:40:53 -08:00 +++ b/drivers/usb/host/Kconfig 2004-12-12 17:40:53 -08:00 @@ -100,14 +100,16 @@ To compile this driver as a module, choose M here: the module will be called uhci-hcd. -config USB_SL811HS - tristate "SL811HS support" - depends on ARM && USB +config USB_SL811_HCD + tristate "SL811HS HCD support" + depends on USB + default N help - Say Y here if you have a SL811HS USB host controller in your system. - - If you do not know what this is, please say N. + The SL811HS is a single-port USB controller that supports either + host side or peripheral side roles. Enable this option if your + board has this chip, and you want to use it as a host controller. + If unsure, say N. To compile this driver as a module, choose M here: the - module will be called hc_sl811. + module will be called sl811-hcd. diff -Nru a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile --- a/drivers/usb/host/Makefile 2004-12-12 17:40:53 -08:00 +++ b/drivers/usb/host/Makefile 2004-12-12 17:40:53 -08:00 @@ -6,6 +6,5 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o - -obj-$(CONFIG_USB_SL811HS) += hc_sl811.o +obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o diff -Nru a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c --- a/drivers/usb/host/ehci-hub.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/usb/host/ehci-hub.c 2004-12-12 17:40:53 -08:00 @@ -286,7 +286,7 @@ if (HCS_INDICATOR (ehci->hcs_params)) temp |= 0x0080; /* per-port indicators (LEDs) */ #endif - desc->wHubCharacteristics = cpu_to_le16 (temp); + desc->wHubCharacteristics = (__force __u16)cpu_to_le16 (temp); } /*-------------------------------------------------------------------------*/ diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c --- a/drivers/usb/host/ehci-q.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/usb/host/ehci-q.c 2004-12-12 17:40:53 -08:00 @@ -83,19 +83,59 @@ /*-------------------------------------------------------------------------*/ -/* update halted (but potentially linked) qh */ - static inline void qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) { + /* writes to an active overlay are unsafe */ + BUG_ON(qh->qh_state != QH_STATE_IDLE); + qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END; + /* Except for control endpoints, we make hardware maintain data + * toggle (like OHCI) ... here (re)initialize the toggle in the QH, + * and set the pseudo-toggle in udev. Only usb_clear_halt() will + * ever clear it. + */ + if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) { + unsigned is_out, epnum; + + is_out = !(qtd->hw_token & cpu_to_le32(1 << 8)); + epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f; + if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { + qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE); + usb_settoggle (qh->dev, epnum, is_out, 1); + } + } + /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING); } +/* if it weren't for a common silicon quirk (writing the dummy into the qh + * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault + * recovery (including urb dequeue) would need software changes to a QH... + */ +static void +qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + struct ehci_qtd *qtd; + + if (list_empty (&qh->qtd_list)) + qtd = qh->dummy; + else { + qtd = list_entry (qh->qtd_list.next, + struct ehci_qtd, qtd_list); + /* first qtd may already be partially processed */ + if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current) + qtd = NULL; + } + + if (qtd) + qh_update (ehci, qh, qtd); +} + /*-------------------------------------------------------------------------*/ static void qtd_copy_status ( @@ -226,6 +266,11 @@ spin_lock (&ehci->lock); } +static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); + +static void intr_deschedule (struct ehci_hcd *ehci, + struct ehci_qh *qh, int wait); +static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); /* * Process and free completed qtds for a qh, returning URBs to drivers. @@ -369,21 +414,27 @@ /* restore original state; caller must unlink or relink */ qh->qh_state = state; - /* update qh after fault cleanup */ - if (unlikely (stopped != 0) - /* some EHCI 0.95 impls will overlay dummy qtds */ - || qh->hw_qtd_next == EHCI_LIST_END) { - if (list_empty (&qh->qtd_list)) - end = qh->dummy; - else { - end = list_entry (qh->qtd_list.next, - struct ehci_qtd, qtd_list); - /* first qtd may already be partially processed */ - if (cpu_to_le32 (end->qtd_dma) == qh->hw_current) - end = NULL; + /* be sure the hardware's done with the qh before refreshing + * it after fault cleanup, or recovering from silicon wrongly + * overlaying the dummy qtd (which reduces DMA chatter). + */ + if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) { + switch (state) { + case QH_STATE_IDLE: + qh_refresh(ehci, qh); + break; + case QH_STATE_LINKED: + /* should be rare for periodic transfers, + * except maybe high bandwidth ... + */ + if (qh->period) { + intr_deschedule (ehci, qh, 1); + (void) qh_schedule (ehci, qh); + } else + start_unlink_async (ehci, qh); + break; + /* otherwise, unlink already started */ } - if (end) - qh_update (ehci, qh, end); } return count; @@ -557,21 +608,6 @@ /*-------------------------------------------------------------------------*/ -/* - * Hardware maintains data toggle (like OHCI) ... here we (re)initialize - * the hardware data toggle in the QH, and set the pseudo-toggle in udev - * so we can see if usb_clear_halt() was called. NOP for control, since - * we set up qh->hw_info1 to always use the QTD toggle bits. - */ -static inline void -clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh) -{ - vdbg ("clear toggle, dev %d ep 0x%x-%s", - udev->devnum, ep, is_out ? "out" : "in"); - qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE); - usb_settoggle (udev, ep, is_out, 1); -} - // Would be best to create all qh's from config descriptors, // when each interface/altsetting is established. Unlink // any previous qh and cancel its urbs first; endpoints are @@ -651,11 +687,11 @@ qh->period = urb->interval; } - - /* support for tt scheduling */ - qh->dev = usb_get_dev (urb->dev); } + /* support for tt scheduling, and access to toggles */ + qh->dev = usb_get_dev (urb->dev); + /* using TT? */ switch (urb->dev->speed) { case USB_SPEED_LOW: @@ -715,8 +751,8 @@ qh->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_le32 (info1); qh->hw_info2 = cpu_to_le32 (info2); - qh_update (ehci, qh, qh->dummy); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); + qh_refresh (ehci, qh); return qh; } @@ -745,7 +781,9 @@ } } - qh->hw_token &= ~HALT_BIT; + /* clear halt and/or toggle; and maybe recover from silicon quirk */ + if (qh->qh_state == QH_STATE_IDLE) + qh_refresh (ehci, qh); /* splice right after start */ qh->qh_next = head->qh_next; @@ -820,27 +858,8 @@ qh->hw_info1 &= ~QH_ADDR_MASK; } - /* usb_clear_halt() means qh data toggle gets reset */ - if (unlikely (!usb_gettoggle (urb->dev, - (epnum & 0x0f), !(epnum & 0x10))) - && !usb_pipecontrol (urb->pipe)) { - /* "never happens": drivers do stall cleanup right */ - if (qh->qh_state != QH_STATE_IDLE - && !list_empty (&qh->qtd_list) - && qh->qh_state != QH_STATE_COMPLETING) - ehci_warn (ehci, "clear toggle dev%d " - "ep%d%s: not idle\n", - usb_pipedevice (urb->pipe), - epnum & 0x0f, - usb_pipein (urb->pipe) - ? "in" : "out"); - /* else we know this overlay write is safe */ - clear_toggle (urb->dev, - epnum & 0x0f, !(epnum & 0x10), qh); - } - /* just one way to queue requests: swap with the dummy qtd. - * only hc or qh_completions() usually modify the overlay. + * only hc or qh_refresh() ever modify the overlay. */ if (likely (qtd != 0)) { struct ehci_qtd *dummy; @@ -935,8 +954,6 @@ /*-------------------------------------------------------------------------*/ /* the async qh for the qtds being reclaimed are now unlinked from the HC */ - -static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) { diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/usb/host/ehci-sched.c 2004-12-12 17:40:52 -08:00 @@ -325,7 +325,7 @@ status = disable_periodic (ehci); else { status = 0; - vdbg ("periodic schedule still enabled"); + ehci_vdbg (ehci, "periodic schedule still enabled\n"); } /* @@ -342,7 +342,7 @@ * the race is very short. then if qh also isn't * rescheduled soon, it won't matter. otherwise... */ - vdbg ("intr_deschedule..."); + ehci_vdbg (ehci, "intr_deschedule...\n"); } } else qh->hw_next = EHCI_LIST_END; @@ -450,6 +450,7 @@ __le32 c_mask; unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ + qh_refresh(ehci, qh); qh->hw_next = EHCI_LIST_END; frame = qh->start; diff -Nru a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c --- a/drivers/usb/host/hc_crisv10.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/usb/host/hc_crisv10.c 2004-12-12 17:40:53 -08:00 @@ -30,7 +30,7 @@ #include <../drivers/usb/core/hcd.h> #include <../drivers/usb/core/usb.h> -#include "usb-host.h" +#include "hc_crisv10.h" #define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR #define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR diff -Nru a/drivers/usb/host/hc_simple.c b/drivers/usb/host/hc_simple.c --- a/drivers/usb/host/hc_simple.c 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,1039 +0,0 @@ -/*-------------------------------------------------------------------------*/ -/*-------------------------------------------------------------------------* - * simple generic USB HCD frontend Version 0.9.5 (10/28/2001) - * for embedded HCs (SL811HS) - * - * USB URB handling, hci_ hcs_ - * URB queueing, qu_ - * Transfer scheduling, sh_ - * - * - *-------------------------------------------------------------------------* - * 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 - * - *-------------------------------------------------------------------------*/ - -/* main lock for urb access */ -static spinlock_t usb_urb_lock = SPIN_LOCK_UNLOCKED; - -/*-------------------------------------------------------------------------*/ -/*-------------------------------------------------------------------------*/ -/* URB HCD API function layer - * * * */ - -/*************************************************************************** - * Function Name : hcs_urb_queue - * - * This function initializes the urb status and length before queueing the - * urb. - * - * Input: hci = data structure for the host controller - * urb = USB request block data structure - * - * Return: 0 - **************************************************************************/ -static inline int hcs_urb_queue (hci_t * hci, struct urb * urb) -{ - int i; - - DBGFUNC ("enter hcs_urb_queue\n"); - if (usb_pipeisoc (urb->pipe)) { - DBGVERBOSE ("hcs_urb_queue: isoc pipe\n"); - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].actual_length = 0; - urb->iso_frame_desc[i].status = -EXDEV; - } - - /* urb->next hack : 1 .. resub, 0 .. single shot */ - /* urb->interval = urb->next ? 1 : 0; */ - } - - urb->status = -EINPROGRESS; - urb->actual_length = 0; - urb->error_count = 0; - - if (usb_pipecontrol (urb->pipe)) - hc_flush_data_cache (hci, urb->setup_packet, 8); - if (usb_pipeout (urb->pipe)) - hc_flush_data_cache (hci, urb->transfer_buffer, - urb->transfer_buffer_length); - - qu_queue_urb (hci, urb); - - return 0; -} - -/*************************************************************************** - * Function Name : hcs_return_urb - * - * This function the return path of URB back to the USB core. It calls the - * the urb complete function if exist, and also handles the resubmition of - * interrupt URBs. - * - * Input: hci = data structure for the host controller - * urb = USB request block data structure - * resub_ok = resubmit flag: 1 = submit urb again, 0 = not submit - * - * Return: 0 - **************************************************************************/ -static int hcs_return_urb (hci_t * hci, struct urb * urb, int resub_ok) -{ - struct usb_device *dev = urb->dev; - int resubmit = 0; - - DBGFUNC ("enter hcs_return_urb, urb pointer = 0x%x, " - "transferbuffer point = 0x%x, " - " setup packet pointer = 0x%x, context pointer = 0x%x \n", - (__u32 *) urb, (__u32 *) urb->transfer_buffer, - (__u32 *) urb->setup_packet, (__u32 *) urb->context); - if (urb_debug) - urb_print (urb, "RET", usb_pipeout (urb->pipe)); - - resubmit = urb->interval && resub_ok; - - urb->dev = urb->hcpriv = NULL; - - if (urb->complete) { - urb->complete (urb, NULL); /* call complete */ - } - - if (resubmit) { - /* requeue the URB */ - urb->dev = dev; - hcs_urb_queue (hci, urb); - } else { - usb_put_urb(urb); - } - - return 0; -} - -/*************************************************************************** - * Function Name : hci_submit_urb - * - * This function is called by the USB core API when an URB is available to - * process. This function does the following - * - * 1) Check the validity of the URB - * 2) Parse the device number from the URB - * 3) Pass the URB to the root hub routine if its intended for the hub, else - * queue the urb for the attached device. - * - * Input: urb = USB request block data structure - * - * Return: 0 if success or error code - **************************************************************************/ -static int hci_submit_urb (struct urb * urb, int mem_flags) -{ - hci_t *hci; - unsigned int pipe = urb->pipe; - unsigned long flags; - int ret; - - DBGFUNC ("enter hci_submit_urb, pipe = 0x%x\n", urb->pipe); - if (!urb->dev || !urb->dev->bus || urb->hcpriv) - return -EINVAL; - - hci = (hci_t *) urb->dev->bus->hcpriv; - - /* a request to the virtual root hub */ - if (usb_pipedevice (pipe) == hci->rh.devnum) { - if (urb_debug > 1) - urb_print (urb, "SUB-RH", usb_pipein (pipe)); - - return rh_submit_urb (urb); - } - - /* increment urb's reference count, we now control it. */ - urb = usb_get_urb (urb); - - /* queue the URB to its endpoint-queue */ - spin_lock_irqsave (&usb_urb_lock, flags); - ret = hcs_urb_queue (hci, urb); - if (ret != 0) { - /* error on return */ - DBGERR ("hci_submit_urb: return err, ret = 0x%x, urb->status = 0x%x\n", - ret, urb->status); - usb_put_urb (urb); - } - - spin_unlock_irqrestore (&usb_urb_lock, flags); - - return ret; - -} - -/*************************************************************************** - * Function Name : hci_unlink_urb - * - * This function mark the URB to unlink - * - * Input: urb = USB request block data structure - * - * Return: 0 if success or error code - **************************************************************************/ -static int hci_unlink_urb (struct urb * urb, int status) -{ - unsigned long flags; - hci_t *hci; - DECLARE_WAITQUEUE (wait, current); - void *comp = NULL; - - DBGFUNC ("enter hci_unlink_urb\n"); - - if (!urb) /* just to be sure */ - return -EINVAL; - - if (!urb->dev || !urb->dev->bus) - return -ENODEV; - - hci = (hci_t *) urb->dev->bus->hcpriv; - - /* a request to the virtual root hub */ - if (usb_pipedevice (urb->pipe) == hci->rh.devnum) { - return rh_unlink_urb (urb); - } - - if (urb_debug) - urb_print (urb, "UNLINK", 1); - - spin_lock_irqsave (&usb_urb_lock, flags); - - if (!list_empty (&urb->urb_list) && urb->status == -EINPROGRESS) { - /* URB active? */ - - /* asynchronous with callback */ - /* relink the urb to the del list */ - list_move (&urb->urb_list, &hci->del_list); - urb->status = status; - spin_unlock_irqrestore (&usb_urb_lock, flags); - } else { - /* hcd does not own URB but we keep the driver happy anyway */ - spin_unlock_irqrestore (&usb_urb_lock, flags); - - if (urb->complete) { - urb->status = status; - urb->actual_length = 0; - urb->complete (urb, NULL); - if (urb->reject) - wake_up (&usb_kill_urb_queue); - } - } - - return 0; -} - -/*************************************************************************** - * Function Name : hci_alloc_dev - * - * This function allocates private data space for the usb device and - * initialize the endpoint descriptor heads. - * - * Input: usb_dev = pointer to the usb device - * - * Return: 0 if success or error code - **************************************************************************/ -static int hci_alloc_dev (struct usb_device *usb_dev) -{ - struct hci_device *dev; - int i; - - DBGFUNC ("enter hci_alloc_dev\n"); - dev = kmalloc (sizeof (*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - memset (dev, 0, sizeof (*dev)); - - for (i = 0; i < 32; i++) { - INIT_LIST_HEAD (&(dev->ed[i].urb_queue)); - dev->ed[i].pipe_head = NULL; - } - - usb_dev->hcpriv = dev; - - DBGVERBOSE ("USB HC dev alloc %d bytes\n", sizeof (*dev)); - - return 0; - -} - -/*************************************************************************** - * Function Name : hci_free_dev - * - * This function de-allocates private data space for the usb devic - * - * Input: usb_dev = pointer to the usb device - * - * Return: 0 - **************************************************************************/ -static int hci_free_dev (struct usb_device *usb_dev) -{ - DBGFUNC ("enter hci_free_dev\n"); - - if (usb_dev->hcpriv) - kfree (usb_dev->hcpriv); - - usb_dev->hcpriv = NULL; - - return 0; -} - -/*************************************************************************** - * Function Name : hci_get_current_frame_number - * - * This function get the current USB frame number - * - * Input: usb_dev = pointer to the usb device - * - * Return: frame number - **************************************************************************/ -static int hci_get_current_frame_number (struct usb_device *usb_dev) -{ - hci_t *hci = usb_dev->bus->hcpriv; - DBGFUNC ("enter hci_get_current_frame_number, frame = 0x%x \r\n", - hci->frame_number); - - return (hci->frame_number); -} - -/*************************************************************************** - * List of all io-functions - **************************************************************************/ - -static struct usb_operations hci_device_operations = { - .allocate = hci_alloc_dev, - .deallocate = hci_free_dev, - .get_frame_number = hci_get_current_frame_number, - .submit_urb = hci_submit_urb, - .unlink_urb = hci_unlink_urb, -}; - -/*************************************************************************** - * URB queueing: - * - * For each type of transfer (INTR, BULK, ISO, CTRL) there is a list of - * active URBs. - * (hci->intr_list, hci->bulk_list, hci->iso_list, hci->ctrl_list) - * For every endpoint the head URB of the queued URBs is linked to one of - * those lists. - * - * The rest of the queued URBs of an endpoint are linked into a - * private URB list for each endpoint. (hci_dev->ed [endpoint_io].urb_queue) - * hci_dev->ed [endpoint_io].pipe_head .. points to the head URB which is - * in one of the active URB lists. - * - * The index of an endpoint consists of its number and its direction. - * - * The state of an intr and iso URB is 0. - * For ctrl URBs the states are US_CTRL_SETUP, US_CTRL_DATA, US_CTRL_ACK - * Bulk URBs states are US_BULK and US_BULK0 (with 0-len packet) - * - **************************************************************************/ - -/*************************************************************************** - * Function Name : qu_urb_timeout - * - * This function is called when the URB timeout. The function unlinks the - * URB. - * - * Input: lurb: URB - * - * Return: none - **************************************************************************/ -#ifdef HC_URB_TIMEOUT -static void qu_urb_timeout (unsigned long lurb) -{ - struct urb *urb = (struct urb *) lurb; - - DBGFUNC ("enter qu_urb_timeout\n"); - hci_unlink_urb (urb); -} -#endif - -/*************************************************************************** - * Function Name : qu_pipeindex - * - * This function gets the index of the pipe. - * - * Input: pipe: the urb pipe - * - * Return: index - **************************************************************************/ -static inline int qu_pipeindex (__u32 pipe) -{ - DBGFUNC ("enter qu_pipeindex\n"); - return (usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe) ? 0 : usb_pipeout (pipe)); -} - -/*************************************************************************** - * Function Name : qu_seturbstate - * - * This function set the state of the URB. - * - * control pipe: 3 states -- Setup, data, status - * interrupt and bulk pipe: 1 state -- data - * - * Input: urb = USB request block data structure - * state = the urb state - * - * Return: none - **************************************************************************/ -static inline void qu_seturbstate (struct urb * urb, int state) -{ - DBGFUNC ("enter qu_seturbstate\n"); - urb->pipe &= ~0x1f; - urb->pipe |= state & 0x1f; -} - -/*************************************************************************** - * Function Name : qu_urbstate - * - * This function get the current state of the URB. - * - * Input: urb = USB request block data structure - * - * Return: none - **************************************************************************/ -static inline int qu_urbstate (struct urb * urb) -{ - - DBGFUNC ("enter qu_urbstate\n"); - - return urb->pipe & 0x1f; -} - -/*************************************************************************** - * Function Name : qu_queue_active_urb - * - * This function adds the urb to the appropriate active urb list and set - * the urb state. - * - * There are four active lists: isochoronous list, interrupt list, - * control list, and bulk list. - * - * Input: hci = data structure for the host controller - * urb = USB request block data structure - * ed = endpoint descriptor - * - * Return: none - **************************************************************************/ -static inline void qu_queue_active_urb (hci_t * hci, struct urb * urb, epd_t * ed) -{ - int urb_state = 0; - DBGFUNC ("enter qu_queue_active_urb\n"); - switch (usb_pipetype (urb->pipe)) { - case PIPE_CONTROL: - list_add (&urb->urb_list, &hci->ctrl_list); - urb_state = US_CTRL_SETUP; - break; - - case PIPE_BULK: - list_add (&urb->urb_list, &hci->bulk_list); - if ((urb->transfer_flags & URB_ZERO_PACKET) - && urb->transfer_buffer_length > 0 - && - ((urb->transfer_buffer_length % - usb_maxpacket (urb->dev, urb->pipe, - usb_pipeout (urb->pipe))) == 0)) { - urb_state = US_BULK0; - } - break; - - case PIPE_INTERRUPT: - urb->start_frame = hci->frame_number; - list_add (&urb->urb_list, &hci->intr_list); - break; - - case PIPE_ISOCHRONOUS: - list_add (&urb->urb_list, &hci->iso_list); - break; - } - -#ifdef HC_URB_TIMEOUT - if (urb->timeout) { - ed->timeout.data = (unsigned long) urb; - ed->timeout.expires = urb->timeout + jiffies; - ed->timeout.function = qu_urb_timeout; - add_timer (&ed->timeout); - } -#endif - - qu_seturbstate (urb, urb_state); -} - -/*************************************************************************** - * Function Name : qu_queue_urb - * - * This function adds the urb to the endpoint descriptor list - * - * Input: hci = data structure for the host controller - * urb = USB request block data structure - * - * Return: none - **************************************************************************/ -static int qu_queue_urb (hci_t * hci, struct urb * urb) -{ - struct hci_device *hci_dev = usb_to_hci (urb->dev); - epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)]; - - DBGFUNC ("Enter qu_queue_urb\n"); - - /* for ISOC transfers calculate start frame index */ - - if (usb_pipeisoc (urb->pipe) && urb->transfer_flags & URB_ISO_ASAP) { - urb->start_frame = ((ed->pipe_head) ? (ed->last_iso + 1) : hci_get_current_frame_number (urb-> dev) + 1) & 0xffff; - } - - if (ed->pipe_head) { - __list_add (&urb->urb_list, ed->urb_queue.prev, - &(ed->urb_queue)); - } else { - ed->pipe_head = urb; - qu_queue_active_urb (hci, urb, ed); - if (++hci->active_urbs == 1) - hc_start_int (hci); - } - - return 0; -} - -/*************************************************************************** - * Function Name : qu_next_urb - * - * This function removes the URB from the queue and add the next URB to - * active list. - * - * Input: hci = data structure for the host controller - * urb = USB request block data structure - * resub_ok = resubmit flag - * - * Return: pointer to the next urb - **************************************************************************/ -static struct urb *qu_next_urb (hci_t * hci, struct urb * urb, int resub_ok) -{ - struct hci_device *hci_dev = usb_to_hci (urb->dev); - epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)]; - - DBGFUNC ("enter qu_next_urb\n"); - list_del_init(&urb->urb_list); - - if (ed->pipe_head == urb) { -#ifdef HC_URB_TIMEOUT - if (urb->timeout) - del_timer (&ed->timeout); -#endif - - if (!--hci->active_urbs) - hc_stop_int (hci); - - if (!list_empty (&ed->urb_queue)) { - urb = list_entry (ed->urb_queue.next, struct urb, urb_list); - list_del_init (&urb->urb_list); - ed->pipe_head = urb; - qu_queue_active_urb (hci, urb, ed); - } else { - ed->pipe_head = NULL; - urb = NULL; - } - } - return urb; -} - -/*************************************************************************** - * Function Name : qu_return_urb - * - * This function is part of the return path. - * - * Input: hci = data structure for the host controller - * urb = USB request block data structure - * resub_ok = resubmit flag - * - * Return: pointer to the next urb - **************************************************************************/ -static struct urb *qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok) -{ - struct urb *next_urb; - - DBGFUNC ("enter qu_return_rub\n"); - next_urb = qu_next_urb (hci, urb, resub_ok); - hcs_return_urb (hci, urb, resub_ok); - return next_urb; -} - -/*************************************************************************** - * Function Name : sh_scan_iso_urb_list - * - * This function goes through the isochronous urb list and schedule the - * the transfer. - * - * Note: This function has not tested yet - * - * Input: hci = data structure for the host controller - * list_lh = pointer to the isochronous list - * frame_number = the frame number - * - * Return: 0 = unsuccessful; 1 = successful - **************************************************************************/ -static int sh_scan_iso_urb_list (hci_t * hci, struct list_head *list_lh, - int frame_number) -{ - struct list_head *lh = list_lh->next; - struct urb *urb; - - DBGFUNC ("enter sh_scan_iso_urb_list\n"); - hci->td_array->len = 0; - - while (lh != list_lh) { - urb = list_entry (lh, struct urb, urb_list); - lh = lh->next; - if (((frame_number - urb->start_frame) & 0x7ff) < - urb->number_of_packets) { - if (!sh_add_packet (hci, urb)) { - return 0; - } else { - if (((frame_number - - urb->start_frame) & 0x7ff) > 0x400) { - if (qu_urbstate (urb) > 0) - urb = qu_return_urb (hci, urb, 1); - else - urb = qu_next_urb (hci, urb, 1); - - if (lh == list_lh && urb) - lh = &urb->urb_list; - } - } - } - } - return 1; -} - -/*************************************************************************** - * Function Name : sh_scan_urb_list - * - * This function goes through the urb list and schedule the - * the transaction. - * - * Input: hci = data structure for the host controller - * list_lh = pointer to the isochronous list - * - * Return: 0 = unsuccessful; 1 = successful - **************************************************************************/ -static int sh_scan_urb_list (hci_t * hci, struct list_head *list_lh) -{ - struct list_head *lh = NULL; - struct urb *urb; - - if (list_lh == NULL) { - DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n"); - } - - DBGFUNC ("enter sh_scan_urb_list: frame# \n"); - - list_for_each (lh, list_lh) { - urb = list_entry (lh, struct urb, urb_list); - if (urb == NULL) - return 1; - if (!usb_pipeint (urb->pipe) - || (((hci->frame_number - urb->start_frame) - & 0x7ff) >= urb->interval)) { - DBGVERBOSE ("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n", - urb->start_frame, hci->frame_number, urb->interval, - usb_pipeint (urb->pipe)); - if (!sh_add_packet (hci, urb)) { - return 0; - } else { - DBGVERBOSE ("INT: start: %d fr_no: %d int: %d pint: %d\n", - urb->start_frame, hci->frame_number, - urb->interval, usb_pipeint (urb->pipe)); - urb->start_frame = hci->frame_number; - return 0; - - } - } - } - return 1; -} - -/*************************************************************************** - * Function Name : sh_shedule_trans - * - * This function schedule the USB transaction. - * This function will process the endpoint in the following order: - * interrupt, control, and bulk. - * - * Input: hci = data structure for the host controller - * isSOF = flag indicate if Start Of Frame has occurred - * - * Return: 0 - **************************************************************************/ -static int sh_schedule_trans (hci_t * hci, int isSOF) -{ - int units_left = 1; - struct list_head *lh; - - if (hci == NULL) { - DBGERR ("sh_schedule_trans: hci == NULL\n"); - return 0; - } - if (hci->td_array == NULL) { - DBGERR ("sh_schedule_trans: hci->td_array == NULL\n"); - return 0; - } - - if (hci->td_array->len != 0) { - DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n", - hci->td_array->len); - } - - /* schedule the next available interrupt transfer or the next - * stage of the interrupt transfer */ - - if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) { - units_left = sh_scan_urb_list (hci, &hci->intr_list); - } - - /* schedule the next available control transfer or the next - * stage of the control transfer */ - - if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) { - units_left = sh_scan_urb_list (hci, &hci->ctrl_list); - } - - /* schedule the next available bulk transfer or the next - * stage of the bulk transfer */ - - if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) { - sh_scan_urb_list (hci, &hci->bulk_list); - - /* be fair to each BULK URB (move list head around) - * only when the new SOF happens */ - - lh = hci->bulk_list.next; - list_move (&hci->bulk_list, lh); - } - return 0; -} - -/*************************************************************************** - * Function Name : sh_add_packet - * - * This function forms the packet and transmit the packet. This function - * will handle all endpoint type: isochoronus, interrupt, control, and - * bulk. - * - * Input: hci = data structure for the host controller - * urb = USB request block data structure - * - * Return: 0 = unsucessful; 1 = successful - **************************************************************************/ -static int sh_add_packet (hci_t * hci, struct urb * urb) -{ - __u8 *data = NULL; - int len = 0; - int toggle = 0; - int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)); - int endpoint = usb_pipeendpoint (urb->pipe); - int address = usb_pipedevice (urb->pipe); - int slow = (((urb->pipe) >> 26) & 1); - int out = usb_pipeout (urb->pipe); - int pid = 0; - int ret; - int i = 0; - int iso = 0; - - DBGFUNC ("enter sh_add_packet\n"); - if (maxps == 0) - maxps = 8; - - /* calculate len, toggle bit and add the transaction */ - switch (usb_pipetype (urb->pipe)) { - case PIPE_ISOCHRONOUS: - pid = out ? PID_OUT : PID_IN; - iso = 1; - i = hci->frame_number - urb->start_frame; - data = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - len = urb->iso_frame_desc[i].length; - break; - - case PIPE_BULK: /* BULK and BULK0 */ - case PIPE_INTERRUPT: - pid = out ? PID_OUT : PID_IN; - len = urb->transfer_buffer_length - urb->actual_length; - data = urb->transfer_buffer + urb->actual_length; - toggle = usb_gettoggle (urb->dev, endpoint, out); - break; - - case PIPE_CONTROL: - switch (qu_urbstate (urb)) { - case US_CTRL_SETUP: - len = 8; - pid = PID_SETUP; - data = urb->setup_packet; - toggle = 0; - break; - - case US_CTRL_DATA: - if (!hci->last_packet_nak) { - /* The last packet received is not a nak: - * reset the nak count - */ - - hci->nakCnt = 0; - } - if (urb->transfer_buffer_length != 0) { - pid = out ? PID_OUT : PID_IN; - len = urb->transfer_buffer_length - urb->actual_length; - data = urb->transfer_buffer + urb->actual_length; - toggle = (urb->actual_length & maxps) ? 0 : 1; - usb_settoggle (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe), toggle); - break; - } else { - /* correct state and fall through */ - qu_seturbstate (urb, US_CTRL_ACK); - } - - case US_CTRL_ACK: - len = 0; - - /* reply in opposite direction */ - pid = !out ? PID_OUT : PID_IN; - toggle = 1; - usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe), toggle); - break; - } - } - - ret = - hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint, - address, pid, iso, qu_urbstate (urb)); - - DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x " - "max:%d\n len:%d ret:%d data:%p left:%d\n", - address, endpoint, pid, toggle, iso, slow, - maxps, len, ret, data, hci->hp.units_left); - - if (ret >= 0) { - hci->td_array->td[hci->td_array->len].urb = urb; - hci->td_array->td[hci->td_array->len].len = ret; - hci->td_array->td[hci->td_array->len].iso_index = i; - hci->td_array->len++; - hci->active_trans = 1; - return 1; - } - return 0; -} - -/*************************************************************************** - * Function Name : cc_to_error - * - * This function maps the SL811HS hardware error code to the linux USB error - * code. - * - * Input: cc = hardware error code - * - * Return: USB error code - **************************************************************************/ -static int cc_to_error (int cc) -{ - int errCode = 0; - if (cc & SL11H_STATMASK_ERROR) { - errCode |= -EILSEQ; - } else if (cc & SL11H_STATMASK_OVF) { - errCode |= -EOVERFLOW; - } else if (cc & SL11H_STATMASK_STALL) { - errCode |= -EPIPE; - } - return errCode; -} - -/*************************************************************************** - * Function Name : sh_done_list - * - * This function process the packet when it has done finish transfer. - * - * 1) It handles hardware error - * 2) It updates the URB state - * 3) If the USB transaction is complete, it start the return stack path. - * - * Input: hci = data structure for the host controller - * isExcessNak = flag tells if there excess NAK condition occurred - * - * Return: urb_state or -1 if the transaction has complete - **************************************************************************/ -static int sh_done_list (hci_t * hci, int *isExcessNak) -{ - int actbytes = 0; - int active = 0; - void *data = NULL; - int cc; - int maxps; - int toggle; - struct urb *urb; - int urb_state = 0; - int ret = 1; /* -1 parse abbort, 1 parse ok, 0 last element */ - int trans = 0; - int len; - int iso_index = 0; - int out; - int pid = 0; - int debugLen = 0; - - *isExcessNak = 0; - - DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n", - hci->td_array->len); - - debugLen = hci->td_array->len; - if (debugLen > 1) - DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n", - hci->td_array->len); - - for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS; - trans++) { - urb = hci->td_array->td[trans].urb; - len = hci->td_array->td[trans].len; - out = usb_pipeout (urb->pipe); - - if (usb_pipeisoc (urb->pipe)) { - iso_index = hci->td_array->td[trans].iso_index; - data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset; - toggle = 0; - } else { - data = urb->transfer_buffer + urb->actual_length; - toggle = usb_gettoggle (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe)); - - } - urb_state = qu_urbstate (urb); - pid = out ? PID_OUT : PID_IN; - ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len, - pid, urb_state); - maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)); - - if (maxps == 0) - maxps = 8; - - active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1))); - - /* If the transfer is not bulk in, then it is necessary to get all - * data specify by the urb->transfer_len. - */ - - if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe))) - active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes); - - if (urb->transfer_buffer_length == urb->actual_length + actbytes) - active = 0; - - if ((cc & - (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | - SL11H_STATMASK_OVF | SL11H_STATMASK_STALL)) - && !(cc & SL11H_STATMASK_NAK)) { - if (++urb->error_count > 3) { - DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n", - urb->error_count, cc); - urb_state = 0; - active = 0; - } else { - DBGERR ("done_list: packet err, cc = 0x%x, " - " urb->length = 0x%x, actual_len = 0x%x," - " urb_state =0x%x\n", - cc, urb->transfer_buffer_length, - urb->actual_length, urb_state); -// if (cc & SL11H_STATMASK_STALL) { - /* The USB function is STALLED on a control pipe (0), - * then it needs to send the SETUP command again to - * clear the STALL condition - */ - -// if (usb_pipeendpoint (urb->pipe) == 0) { -// urb_state = 2; -// active = 0; -// } -// } else - active = 1; - } - } else { - if (cc & SL11H_STATMASK_NAK) { - if (hci->nakCnt < 0x10000) { - hci->nakCnt++; - hci->last_packet_nak = 1; - active = 1; - *isExcessNak = 0; - } else { - DBGERR ("done_list: nak count exceed limit\n"); - active = 0; - *isExcessNak = 1; - hci->nakCnt = 0; - } - } else { - hci->nakCnt = 0; - hci->last_packet_nak = 0; - } - - if (urb_state != US_CTRL_SETUP) { - /* no error */ - urb->actual_length += actbytes; - usb_settoggle (urb->dev, - usb_pipeendpoint (urb->pipe), - usb_pipeout (urb->pipe), toggle); - } - if (usb_pipeisoc (urb->pipe)) { - urb->iso_frame_desc[iso_index].actual_length = actbytes; - urb->iso_frame_desc[iso_index].status = cc_to_error (cc); - active = (iso_index < urb->number_of_packets); - } - } - if (!active) { - if (!urb_state) { - urb->status = cc_to_error (cc); - if (urb->status) { - DBGERR ("error on received packet: urb->status = 0x%x\n", - urb->status); - } - hci->td_array->len = 0; - qu_return_urb (hci, urb, 1); - return -1; - } else { - /* We do not want to decrement the urb_state if exceeded nak, - * because we need to finish the data stage of the control - * packet - */ - - if (!(*isExcessNak)) - urb_state--; - qu_seturbstate (urb, urb_state); - } - } - } - - if (urb_state < 0) - DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n", - urb_state); - if (debugLen != hci->td_array->len) { - DBGERR ("ERROR: done_list, debugLen!= td_array->len," - "debugLen = 0x%x, hci->td_array->len = 0x%x\n", - debugLen, hci->td_array->len); - } - - hci->td_array->len = 0; - - return urb_state; -} diff -Nru a/drivers/usb/host/hc_simple.h b/drivers/usb/host/hc_simple.h --- a/drivers/usb/host/hc_simple.h 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,231 +0,0 @@ -/*-------------------------------------------------------------------------*/ -/* list of all controllers using this driver - * */ - -static LIST_HEAD (hci_hcd_list); - -/* URB states (urb_state) */ -/* isoc, interrupt single state */ - -/* bulk transfer main state and 0-length packet */ -#define US_BULK 0 -#define US_BULK0 1 -/* three setup states */ -#define US_CTRL_SETUP 2 -#define US_CTRL_DATA 1 -#define US_CTRL_ACK 0 - -/*-------------------------------------------------------------------------*/ -/* HC private part of a device descriptor - * */ - -#define NUM_EDS 32 - -typedef struct epd { - struct urb *pipe_head; - struct list_head urb_queue; -// int urb_state; - struct timer_list timeout; - int last_iso; /* timestamp of last queued ISOC transfer */ - -} epd_t; - -struct hci_device { - epd_t ed[NUM_EDS]; -}; - -/*-------------------------------------------------------------------------*/ -/* Virtual Root HUB - */ - -#define usb_to_hci(usb) ((struct hci_device *)(usb)->hcpriv) - -struct virt_root_hub { - int devnum; /* Address of Root Hub endpoint */ - void *urb; /* interrupt URB of root hub */ - int send; /* active flag */ - int interval; /* interval of roothub interrupt transfers */ - struct timer_list rh_int_timer; /* interval timer for rh interrupt EP */ -}; - -#if 1 -/* USB HUB CONSTANTS (not OHCI-specific; see hub.h and USB spec) */ - -/* destination of request */ -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 - -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 - -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -#endif - -/*-------------------------------------------------------------------------*/ -/* struct for each HC - */ - -#define MAX_TRANS 32 - -typedef struct td { - struct urb *urb; - __u16 len; - __u16 iso_index; -} td_t; - -typedef struct td_array { - int len; - td_t td[MAX_TRANS]; -} td_array_t; - -typedef struct hci { - struct virt_root_hub rh; /* roothub */ - wait_queue_head_t waitq; /* deletion of URBs and devices needs a waitqueue */ - int active; /* HC is operating */ - - struct list_head ctrl_list; /* set of ctrl endpoints */ - struct list_head bulk_list; /* set of bulk endpoints */ - struct list_head iso_list; /* set of isoc endpoints */ - struct list_head intr_list; /* ordered (tree) set of int endpoints */ - struct list_head del_list; /* set of entpoints to be deleted */ - - td_array_t *td_array; - td_array_t a_td_array; - td_array_t i_td_array[2]; - - struct list_head hci_hcd_list; /* list of all hci_hcd */ - struct usb_bus *bus; /* our bus */ - -// int trans; /* number of transactions pending */ - int active_urbs; - int active_trans; - int frame_number; /* frame number */ - hcipriv_t hp; /* individual part of hc type */ - int nakCnt; - int last_packet_nak; - -} hci_t; - -/*-------------------------------------------------------------------------*/ -/* condition (error) CC codes and mapping OHCI like - */ - -#define TD_CC_NOERROR 0x00 -#define TD_CC_CRC 0x01 -#define TD_CC_BITSTUFFING 0x02 -#define TD_CC_DATATOGGLEM 0x03 -#define TD_CC_STALL 0x04 -#define TD_DEVNOTRESP 0x05 -#define TD_PIDCHECKFAIL 0x06 -#define TD_UNEXPECTEDPID 0x07 -#define TD_DATAOVERRUN 0x08 -#define TD_DATAUNDERRUN 0x09 -#define TD_BUFFEROVERRUN 0x0C -#define TD_BUFFERUNDERRUN 0x0D -#define TD_NOTACCESSED 0x0F - - -/* urb interface functions */ -static int hci_get_current_frame_number (struct usb_device *usb_dev); -static int hci_unlink_urb (struct urb * urb); - -static int qu_queue_urb (hci_t * hci, struct urb * urb); - -/* root hub */ -static int rh_init_int_timer (struct urb * urb); -static int rh_submit_urb (struct urb * urb); -static int rh_unlink_urb (struct urb * urb); - -/* schedule functions */ -static int sh_add_packet (hci_t * hci, struct urb * urb); - -/* hc specific functions */ -static inline void hc_flush_data_cache (hci_t * hci, void *data, int len); -static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data, - int *cc, int *toggle, int length, int pid, - int urb_state); -static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle, - int maxps, int slow, int endpoint, int address, - int pid, int format, int urb_state); - -static void hc_start_int (hci_t * hci); -static void hc_stop_int (hci_t * hci); -static void SL811Write (hci_t * hci, char offset, char data); - -/* debug| print the main components of an URB - * small: 0) header + data packets 1) just header */ - -static void urb_print (struct urb * urb, char *str, int small) -{ - unsigned int pipe = urb->pipe; - int i, len; - - if (!urb->dev || !urb->dev->bus) { - dbg ("%s URB: no dev", str); - return; - } - - printk ("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,flags:%4x,len:%d/%d,stat:%d(%x)\n", - str, hci_get_current_frame_number (urb->dev), - usb_pipedevice (pipe), usb_pipeendpoint (pipe), - usb_pipeout (pipe) ? 'O' : 'I', - usb_pipetype (pipe) < 2 ? (usb_pipeint (pipe) ? "INTR" : "ISOC") - : (usb_pipecontrol (pipe) ? "CTRL" : "BULK"), urb->transfer_flags, - urb->actual_length, urb->transfer_buffer_length, urb->status, - urb->status); - if (!small) { - if (usb_pipecontrol (pipe)) { - printk (__FILE__ ": cmd(8):"); - for (i = 0; i < 8; i++) - printk (" %02x", ((__u8 *) urb->setup_packet)[i]); - printk ("\n"); - } - if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) { - printk (__FILE__ ": data(%d/%d):", urb->actual_length, - urb->transfer_buffer_length); - len = usb_pipeout (pipe) ? urb-> transfer_buffer_length : urb->actual_length; - for (i = 0; i < 2096 && i < len; i++) - printk (" %02x", ((__u8 *) urb->transfer_buffer)[i]); - printk ("%s stat:%d\n", i < len ? "..." : "", - urb->status); - } - } -} diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c --- a/drivers/usb/host/hc_sl811.c 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,1357 +0,0 @@ -/*-------------------------------------------------------------------------*/ -/*-------------------------------------------------------------------------* - * SL811HS USB HCD for Linux Version 0.1 (10/28/2001) - * - * requires (includes) hc_simple.[hc] simple generic HCD frontend - * - * COPYRIGHT(C) 2001 by CYPRESS SEMICONDUCTOR INC. - * - *-------------------------------------------------------------------------* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - *-------------------------------------------------------------------------*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "../core/hcd.h" - -#undef HC_URB_TIMEOUT -#undef HC_SWITCH_INT -#undef HC_ENABLE_ISOC - -#define SL811_DEBUG_ERR - -#ifdef SL811_DEBUG_ERR -#define DBGERR(fmt, args...) printk(fmt,## args) -#else -#define DBGERR(fmt, args...) -#endif - -#ifdef SL811_DEBUG -#define DBG(fmt, args...) printk(fmt,## args) -#else -#define DBG(fmt, args...) -#endif - -#ifdef SL811_DEBUG_FUNC -#define DBGFUNC(fmt, args...) printk(fmt,## args) -#else -#define DBGFUNC(fmt, args...) -#endif - -#ifdef SL811_DEBUG_DATA -#define DBGDATAR(fmt, args...) printk(fmt,## args) -#define DBGDATAW(fmt, args...) printk(fmt,## args) -#else -#define DBGDATAR(fmt, args...) -#define DBGDATAW(fmt, args...) -#endif - -#ifdef SL811_DEBUG_VERBOSE -#define DBGVERBOSE(fmt, args...) printk(fmt,## args) -#else -#define DBGVERBOSE(fmt, args...) -#endif - -#define TRUE 1 -#define FALSE 0 - -#define HC_SWITCH_INT -#include "hc_sl811.h" -#include "hc_simple.h" - -static int urb_debug = 0; - -#include "hc_simple.c" -#include "hc_sl811_rh.c" - -/* The base_addr, data_reg_addr, and irq number are board specific. - * The current values are design to run on the Accelent SA1110 IDP - * NOTE: values need to modify for different development boards - */ - -static int base_addr = 0xd3800000; -static int data_reg_addr = 0xd3810000; -static int irq = 34; - -/* forware declaration */ - -int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len, - int toggle, int slow, int urb_state); - -static int sofWaitCnt = 0; - -module_param(urb_debug, int, 0); -MODULE_PARM_DESC (urb_debug, "debug urb messages, default is 0 (no)"); - -module_param(base_addr, int, 0); -MODULE_PARM_DESC (base_addr, "sl811 base address 0xd3800000"); -module_param(data_reg_addr, int, 0); -MODULE_PARM_DESC (data_reg_addr, "sl811 data register address 0xd3810000"); -module_param(irq, int, 0); -MODULE_PARM_DESC (irq, "IRQ 34 (default)"); - -static int hc_reset (hci_t * hci); - -/*************************************************************************** - * Function Name : SL811Read - * - * Read a byte of data from the SL811H/SL11H - * - * Input: hci = data structure for the host controller - * offset = address of SL811/SL11H register or memory - * - * Return: data - **************************************************************************/ -char SL811Read (hci_t * hci, char offset) -{ - hcipriv_t *hp = &hci->hp; - char data; - writeb (offset, hp->hcport); - wmb (); - data = readb (hp->hcport2); - rmb (); - return (data); -} - -/*************************************************************************** - * Function Name : SL811Write - * - * Write a byte of data to the SL811H/SL11H - * - * Input: hci = data structure for the host controller - * offset = address of SL811/SL11H register or memory - * data = the data going to write to SL811H - * - * Return: none - **************************************************************************/ -void SL811Write (hci_t * hci, char offset, char data) -{ - hcipriv_t *hp = &hci->hp; - writeb (offset, hp->hcport); - writeb (data, hp->hcport2); - wmb (); -} - -/*************************************************************************** - * Function Name : SL811BufRead - * - * Read consecutive bytes of data from the SL811H/SL11H buffer - * - * Input: hci = data structure for the host controller - * offset = SL811/SL11H register offset - * buf = the buffer where the data will store - * size = number of bytes to read - * - * Return: none - **************************************************************************/ -void SL811BufRead (hci_t * hci, short offset, char *buf, short size) -{ - hcipriv_t *hp = &hci->hp; - if (size <= 0) - return; - writeb ((char) offset, hp->hcport); - wmb (); - DBGDATAR ("SL811BufRead: offset = 0x%x, data = ", offset); - while (size--) { - *buf++ = (char) readb (hp->hcport2); - DBGDATAR ("0x%x ", *(buf - 1)); - rmb (); - } - DBGDATAR ("\n"); -} - -/*************************************************************************** - * Function Name : SL811BufWrite - * - * Write consecutive bytes of data to the SL811H/SL11H buffer - * - * Input: hci = data structure for the host controller - * offset = SL811/SL11H register offset - * buf = the data buffer - * size = number of bytes to write - * - * Return: none - **************************************************************************/ -void SL811BufWrite (hci_t * hci, short offset, char *buf, short size) -{ - hcipriv_t *hp = &hci->hp; - if (size <= 0) - return; - writeb ((char) offset, hp->hcport); - wmb (); - DBGDATAW ("SL811BufWrite: offset = 0x%x, data = ", offset); - while (size--) { - DBGDATAW ("0x%x ", *buf); - writeb (*buf, hp->hcport2); - wmb (); - buf++; - } - DBGDATAW ("\n"); -} - -/*************************************************************************** - * Function Name : regTest - * - * This routine test the Read/Write functionality of SL811HS registers - * - * 1) Store original register value into a buffer - * 2) Write to registers with a RAMP pattern. (10, 11, 12, ..., 255) - * 3) Read from register - * 4) Compare the written value with the read value and make sure they are - * equivalent - * 5) Restore the original register value - * - * Input: hci = data structure for the host controller - * - * - * Return: TRUE = passed; FALSE = failed - **************************************************************************/ -int regTest (hci_t * hci) -{ - int i, data, result = TRUE; - char buf[256]; - - DBGFUNC ("Enter regTest\n"); - for (i = 0x10; i < 256; i++) { - /* save the original buffer */ - buf[i] = (char) SL811Read (hci, i); - - /* Write the new data to the buffer */ - SL811Write (hci, i, i); - } - - /* compare the written data */ - for (i = 0x10; i < 256; i++) { - data = SL811Read (hci, i); - if (data != i) { - DBGERR ("Pattern test failed!! value = 0x%x, s/b 0x%x\n", - data, i); - result = FALSE; - } - } - - /* restore the data */ - for (i = 0x10; i < 256; i++) { - SL811Write (hci, i, buf[i]); - } - - return (result); -} - -/*************************************************************************** - * Function Name : regShow - * - * Display all SL811HS register values - * - * Input: hci = data structure for the host controller - * - * Return: none - **************************************************************************/ -void regShow (hci_t * hci) -{ - int i; - for (i = 0; i < 256; i++) { - printk ("offset %d: 0x%x\n", i, SL811Read (hci, i)); - } -} - -/************************************************************************ - * Function Name : USBReset - * - * This function resets SL811HS controller and detects the speed of - * the connecting device - * - * Input: hci = data structure for the host controller - * - * Return: 0 = no device attached; 1 = USB device attached - * - ***********************************************************************/ -static int USBReset (hci_t * hci) -{ - int status; - hcipriv_t *hp = &hci->hp; - - DBGFUNC ("enter USBReset\n"); - - SL811Write (hci, SL11H_CTLREG2, 0xae); - - // setup master and full speed - - SL811Write (hci, SL11H_CTLREG1, 0x08); // reset USB - mdelay (20); // 20ms - SL811Write (hci, SL11H_CTLREG1, 0); // remove SE0 - - for (status = 0; status < 100; status++) - SL811Write (hci, SL11H_INTSTATREG, 0xff); // clear all interrupt bits - - status = SL811Read (hci, SL11H_INTSTATREG); - - if (status & 0x40) // Check if device is removed - { - DBG ("USBReset: Device removed\n"); - SL811Write (hci, SL11H_INTENBLREG, - SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR | - SL11H_INTMASK_INSRMV); - hp->RHportStatus->portStatus &= - ~(PORT_CONNECT_STAT | PORT_ENABLE_STAT); - - return 0; - } - - SL811Write (hci, SL11H_BUFLNTHREG_B, 0); //zero lenth - SL811Write (hci, SL11H_PIDEPREG_B, 0x50); //send SOF to EP0 - SL811Write (hci, SL11H_DEVADDRREG_B, 0x01); //address0 - SL811Write (hci, SL11H_SOFLOWREG, 0xe0); - - if (!(status & 0x80)) { - /* slow speed device connect directly to root-hub */ - - DBG ("USBReset: low speed Device attached\n"); - SL811Write (hci, SL11H_CTLREG1, 0x8); - mdelay (20); - SL811Write (hci, SL11H_SOFTMRREG, 0xee); - SL811Write (hci, SL11H_CTLREG1, 0x21); - - /* start the SOF or EOP */ - - SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01); - hp->RHportStatus->portStatus |= - (PORT_CONNECT_STAT | PORT_LOW_SPEED_DEV_ATTACH_STAT); - - /* clear all interrupt bits */ - - for (status = 0; status < 20; status++) - SL811Write (hci, SL11H_INTSTATREG, 0xff); - } else { - /* full speed device connect directly to root hub */ - - DBG ("USBReset: full speed Device attached\n"); - SL811Write (hci, SL11H_CTLREG1, 0x8); - mdelay (20); - SL811Write (hci, SL11H_SOFTMRREG, 0xae); - SL811Write (hci, SL11H_CTLREG1, 0x01); - - /* start the SOF or EOP */ - - SL811Write (hci, SL11H_HOSTCTLREG_B, 0x01); - hp->RHportStatus->portStatus |= (PORT_CONNECT_STAT); - hp->RHportStatus->portStatus &= ~PORT_LOW_SPEED_DEV_ATTACH_STAT; - - /* clear all interrupt bits */ - - SL811Write (hci, SL11H_INTSTATREG, 0xff); - - } - - /* enable all interrupts */ - SL811Write (hci, SL11H_INTENBLREG, - SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR | - SL11H_INTMASK_INSRMV); - - return 1; -} - -/*-------------------------------------------------------------------------*/ -/* tl functions */ -static inline void hc_mark_last_trans (hci_t * hci) -{ - hcipriv_t *hp = &hci->hp; - __u8 *ptd = hp->tl; - - dbg ("enter hc_mark_last_trans\n"); - if (ptd == NULL) { - printk ("hc_mark_last_trans: ptd = null\n"); - return; - } - if (hp->xferPktLen > 0) - *(ptd + hp->tl_last) |= (1 << 3); -} - -static inline void hc_flush_data_cache (hci_t * hci, void *data, int len) -{ -} - -/************************************************************************ - * Function Name : hc_add_trans - * - * This function sets up the SL811HS register and transmit the USB packets. - * - * 1) Determine if enough time within the current frame to send the packet - * 2) Load the data into the SL811HS register - * 3) Set the appropriate command to the register and trigger the transmit - * - * Input: hci = data structure for the host controller - * len = data length - * data = transmitting data - * toggle = USB toggle bit, either 0 or 1 - * maxps = maximum packet size for this endpoint - * slow = speed of the device - * endpoint = endpoint number - * address = USB address of the device - * pid = packet ID - * format = - * urb_state = the current stage of USB transaction - * - * Return: 0 = no time left to schedule the transfer - * 1 = success - * - ***********************************************************************/ -static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle, - int maxps, int slow, int endpoint, int address, - int pid, int format, int urb_state) -{ - hcipriv_t *hp = &hci->hp; - __u16 speed; - int ii, jj, kk; - - DBGFUNC ("enter hc_addr_trans: len =0x%x, toggle:0x%x, endpoing:0x%x," - " addr:0x%x, pid:0x%x,format:0x%x\n", len, toggle, endpoint, - i address, pid, format); - - if (len > maxps) { - len = maxps; - } - - speed = hp->RHportStatus->portStatus; - if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) { -// ii = (8*7*8 + 6*3) * len + 800; - ii = 8 * 8 * len + 1024; - } else { - if (slow) { -// ii = (8*7*8 + 6*3) * len + 800; - ii = 8 * 8 * len + 2048; - } else -// ii = (8*7 + 6*3)*len + 110; - ii = 8 * len + 256; - } - - ii += 2 * 10 * len; - - jj = SL811Read (hci, SL11H_SOFTMRREG); - kk = (jj & 0xFF) * 64 - ii; - - if (kk < 0) { - DBGVERBOSE - ("hc_add_trans: no bandwidth for schedule, ii = 0x%x," - "jj = 0x%x, len =0x%x, active_trans = 0x%x\n", ii, jj, len, - hci->active_trans); - return (-1); - } - - if (pid != PID_IN) { - /* Load data into hc */ - - SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len); - } - - /* transmit */ - - SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len, - toggle, slow, urb_state); - - return len; -} - -/************************************************************************ - * Function Name : hc_parse_trans - * - * This function checks the status of the transmitted or received packet - * and copy the data from the SL811HS register into a buffer. - * - * 1) Check the status of the packet - * 2) If successful, and IN packet then copy the data from the SL811HS register - * into a buffer - * - * Input: hci = data structure for the host controller - * actbytes = pointer to actual number of bytes - * data = data buffer - * cc = packet status - * length = the urb transmit length - * pid = packet ID - * urb_state = the current stage of USB transaction - * - * Return: 0 - ***********************************************************************/ -static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data, - int *cc, int *toggle, int length, int pid, - int urb_state) -{ - __u8 addr; - __u8 len; - - DBGFUNC ("enter hc_parse_trans\n"); - - /* get packet status; convert ack rcvd to ack-not-rcvd */ - - *cc = (int) SL811Read (hci, SL11H_PKTSTATREG); - - if (*cc & - (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF | - SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) { - if (*cc & SL11H_STATMASK_OVF) - DBGERR ("parse trans: error recv ack, cc = 0x%x, TX_BASE_Len = " - "0x%x, TX_count=0x%x\n", *cc, - SL811Read (hci, SL11H_BUFLNTHREG), - SL811Read (hci, SL11H_XFERCNTREG)); - - } else { - DBGVERBOSE ("parse trans: recv ack, cc = 0x%x, len = 0x%x, \n", - *cc, length); - - /* Successful data */ - if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) { - - /* Find the base address */ - addr = SL811Read (hci, SL11H_BUFADDRREG); - - /* Find the Transmit Length */ - len = SL811Read (hci, SL11H_BUFLNTHREG); - - /* The actual data length = xmit length reg - xfer count reg */ - *actbytes = len - SL811Read (hci, SL11H_XFERCNTREG); - - if ((data != NULL) && (*actbytes > 0)) { - SL811BufRead (hci, addr, data, *actbytes); - - } else if ((data == NULL) && (*actbytes <= 0)) { - DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n", - *actbytes); - return 0; - } - } else if (pid == PID_OUT) { - *actbytes = length; - } else { - // printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid); - } - *toggle = !*toggle; - } - - return 0; -} - -/************************************************************************ - * Function Name : hc_start_int - * - * This function enables SL811HS interrupts - * - * Input: hci = data structure for the host controller - * - * Return: none - ***********************************************************************/ -static void hc_start_int (hci_t * hci) -{ -#ifdef HC_SWITCH_INT - int mask = - SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR | - SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET; - SL811Write (hci, IntEna, mask); -#endif -} - -/************************************************************************ - * Function Name : hc_stop_int - * - * This function disables SL811HS interrupts - * - * Input: hci = data structure for the host controller - * - * Return: none - ***********************************************************************/ -static void hc_stop_int (hci_t * hci) -{ -#ifdef HC_SWITCH_INT - SL811Write (hci, SL11H_INTSTATREG, 0xff); -// SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV); - -#endif -} - -/************************************************************************ - * Function Name : handleInsRmvIntr - * - * This function handles the insertion or removal of device on SL811HS. - * It resets the controller and updates the port status - * - * Input: hci = data structure for the host controller - * - * Return: none - ***********************************************************************/ -void handleInsRmvIntr (hci_t * hci) -{ - hcipriv_t *hp = &hci->hp; - - USBReset (hci); - - /* Changes in connection status */ - - hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE; - - /* Port Enable or Disable */ - - if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) { - /* device is connected to the port: - * 1) Enable port - * 2) Resume ?? - */ -// hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE; - - /* Over Current is not supported by the SL811 HW ?? */ - - /* How about the Port Power ?? */ - - } else { - /* Device has disconnect: - * 1) Disable port - */ - - hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT); - hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE; - - } -} - -/***************************************************************** - * - * Function Name: SL11StartXaction - * - * This functions load the registers with appropriate value and - * transmit the packet. - * - * Input: hci = data structure for the host controller - * addr = USB address of the device - * epaddr = endpoint number - * pid = packet ID - * len = data length - * toggle = USB toggle bit, either 0 or 1 - * slow = speed of the device - * urb_state = the current stage of USB transaction - * - * Return: 0 = error; 1 = successful - * - *****************************************************************/ -int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len, - int toggle, int slow, int urb_state) -{ - - hcipriv_t *hp = &hci->hp; - __u8 cmd = 0; - __u8 setup_data[4]; - __u16 speed; - - speed = hp->RHportStatus->portStatus; - if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) { - cmd |= SL11H_HCTLMASK_PREAMBLE; - } - switch (pid) { - case PID_SETUP: - cmd &= SL11H_HCTLMASK_PREAMBLE; - cmd |= - (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP | - SL11H_HCTLMASK_WRITE); - break; - - case PID_OUT: - cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE); - cmd |= - (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP | - SL11H_HCTLMASK_WRITE); - if (toggle) { - cmd |= SL11H_HCTLMASK_SEQ; - } - break; - - case PID_IN: - cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE); - cmd |= (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP); - break; - - default: - DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid); - return 0; - } - setup_data[0] = SL11H_DATA_START; - setup_data[1] = len; - setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF)); - setup_data[3] = addr & 0x7F; - - SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4); - - SL811Write (hci, SL11H_HOSTCTLREG, cmd); - -#if 0 - /* The SL811 has a hardware flaw when hub devices sends out - * SE0 between packets. It has been found in a TI chipset and - * cypress hub chipset. It causes the SL811 to hang - * The workaround is to re-issue the preample again. - */ - - if ((cmd & SL11H_HCTLMASK_PREAMBLE)) { - SL811Write (hci, SL11H_PIDEPREG_B, 0xc0); - SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1); // send the premable - } -#endif - return 1; -} - -/***************************************************************** - * - * Function Name: hc_interrupt - * - * Interrupt service routine. - * - * 1) determine the causes of interrupt - * 2) clears all interrupts - * 3) calls appropriate function to service the interrupt - * - * Input: irq = interrupt line associated with the controller - * hci = data structure for the host controller - * r = holds the snapshot of the processor's context before - * the processor entered interrupt code. (not used here) - * - * Return value : None. - * - *****************************************************************/ -static void hc_interrupt (int irq, void *__hci, struct pt_regs *r) -{ - char ii; - hci_t *hci = __hci; - int isExcessNak = 0; - int urb_state = 0; - char tmpIrq = 0; - - /* Get value from interrupt status register */ - - ii = SL811Read (hci, SL11H_INTSTATREG); - - if (ii & SL11H_INTMASK_INSRMV) { - /* Device insertion or removal detected for the USB port */ - - SL811Write (hci, SL11H_INTENBLREG, 0); - SL811Write (hci, SL11H_CTLREG1, 0); - mdelay (100); // wait for device stable - handleInsRmvIntr (hci); - return; - } - - /* Clear all interrupts */ - - SL811Write (hci, SL11H_INTSTATREG, 0xff); - - if (ii & SL11H_INTMASK_XFERDONE) { - /* USB Done interrupt occurred */ - - urb_state = sh_done_list (hci, &isExcessNak); -#ifdef WARNING - if (hci->td_array->len > 0) - printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n", - hci->td_array->len); -#endif - if (hci->td_array->len == 0 && !isExcessNak - && !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) { - if (urb_state == 0) { - /* All urb_state has not been finished yet! - * continue with the current urb transaction - */ - - if (hci->last_packet_nak == 0) { - if (!usb_pipecontrol - (hci->td_array->td[0].urb->pipe)) - sh_add_packet (hci, hci->td_array-> td[0].urb); - } - } else { - /* The last transaction has completed: - * schedule the next transaction - */ - - sh_schedule_trans (hci, 0); - } - } - SL811Write (hci, SL11H_INTSTATREG, 0xff); - return; - } - - if (ii & SL11H_INTMASK_SOFINTR) { - hci->frame_number = (hci->frame_number + 1) % 2048; - if (hci->td_array->len == 0) - sh_schedule_trans (hci, 1); - else { - if (sofWaitCnt++ > 100) { - /* The last transaction has not completed. - * Need to retire the current td, and let - * it transmit again later on. - * (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER - * GET TO THIS POINT) - */ - - DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n", - hci->td_array->len); - urb_print (hci->td_array->td[hci->td_array->len - 1].urb, - "INTERRUPT", 0); - sh_done_list (hci, &isExcessNak); - SL811Write (hci, SL11H_INTSTATREG, 0xff); - hci->td_array->len = 0; - sofWaitCnt = 0; - } - } - tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG); - if (tmpIrq) { - DBG ("IRQ occurred while service SOF: irq = 0x%x\n", - tmpIrq); - - /* If we receive a DONE IRQ after schedule, need to - * handle DONE IRQ again - */ - - if (tmpIrq & SL11H_INTMASK_XFERDONE) { - DBGERR ("IRQ occurred while service SOF: irq = 0x%x\n", - tmpIrq); - urb_state = sh_done_list (hci, &isExcessNak); - } - SL811Write (hci, SL11H_INTSTATREG, 0xff); - } - } else { - DBG ("SL811 ISR: unknown, int = 0x%x \n", ii); - } - - SL811Write (hci, SL11H_INTSTATREG, 0xff); - return; -} - -/***************************************************************** - * - * Function Name: hc_reset - * - * This function does register test and resets the SL811HS - * controller. - * - * Input: hci = data structure for the host controller - * - * Return value : 0 - * - *****************************************************************/ -static int hc_reset (hci_t * hci) -{ - int attachFlag = 0; - - DBGFUNC ("Enter hc_reset\n"); - regTest (hci); - attachFlag = USBReset (hci); - if (attachFlag) { - setPortChange (hci, PORT_CONNECT_CHANGE); - } - return (0); -} - -/***************************************************************** - * - * Function Name: hc_alloc_trans_buffer - * - * This function allocates all transfer buffer - * - * Input: hci = data structure for the host controller - * - * Return value : 0 - * - *****************************************************************/ -static int hc_alloc_trans_buffer (hci_t * hci) -{ - hcipriv_t *hp = &hci->hp; - int maxlen; - - hp->itl0_len = 0; - hp->itl1_len = 0; - hp->atl_len = 0; - - hp->itl_buffer_len = 1024; - hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len; /* 2048 */ - - maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len; - - hp->tl = kmalloc (maxlen, GFP_KERNEL); - - if (!hp->tl) - return -ENOMEM; - - memset (hp->tl, 0, maxlen); - return 0; -} - -/***************************************************************** - * - * Function Name: getPortStatusAndChange - * - * This function gets the ports status from SL811 and format it - * to a USB request format - * - * Input: hci = data structure for the host controller - * - * Return value : port status and change - * - *****************************************************************/ -static __u32 getPortStatusAndChange (hci_t * hci) -{ - hcipriv_t *hp = &hci->hp; - __u32 portstatus; - - DBGFUNC ("enter getPorStatusAndChange\n"); - - portstatus = hp->RHportStatus->portChange << 16 | hp->RHportStatus->portStatus; - - return (portstatus); -} - -/***************************************************************** - * - * Function Name: setPortChange - * - * This function set the bit position of portChange. - * - * Input: hci = data structure for the host controller - * bitPos = the bit position - * - * Return value : none - * - *****************************************************************/ -static void setPortChange (hci_t * hci, __u16 bitPos) -{ - hcipriv_t *hp = &hci->hp; - - switch (bitPos) { - case PORT_CONNECT_STAT: - hp->RHportStatus->portChange |= bitPos; - break; - - case PORT_ENABLE_STAT: - hp->RHportStatus->portChange |= bitPos; - break; - - case PORT_RESET_STAT: - hp->RHportStatus->portChange |= bitPos; - break; - - case PORT_POWER_STAT: - hp->RHportStatus->portChange |= bitPos; - break; - - case PORT_SUSPEND_STAT: - hp->RHportStatus->portChange |= bitPos; - break; - - case PORT_OVER_CURRENT_STAT: - hp->RHportStatus->portChange |= bitPos; - break; - } -} - -/***************************************************************** - * - * Function Name: clrPortChange - * - * This function clear the bit position of portChange. - * - * Input: hci = data structure for the host controller - * bitPos = the bit position - * - * Return value : none - * - *****************************************************************/ -static void clrPortChange (hci_t * hci, __u16 bitPos) -{ - hcipriv_t *hp = &hci->hp; - switch (bitPos) { - case PORT_CONNECT_CHANGE: - hp->RHportStatus->portChange &= ~bitPos; - break; - - case PORT_ENABLE_CHANGE: - hp->RHportStatus->portChange &= ~bitPos; - break; - - case PORT_RESET_CHANGE: - hp->RHportStatus->portChange &= ~bitPos; - break; - - case PORT_SUSPEND_CHANGE: - hp->RHportStatus->portChange &= ~bitPos; - break; - - case PORT_OVER_CURRENT_CHANGE: - hp->RHportStatus->portChange &= ~bitPos; - break; - } -} - -/***************************************************************** - * - * Function Name: clrPortStatus - * - * This function clear the bit position of portStatus. - * - * Input: hci = data structure for the host controller - * bitPos = the bit position - * - * Return value : none - * - *****************************************************************/ -static void clrPortStatus (hci_t * hci, __u16 bitPos) -{ - hcipriv_t *hp = &hci->hp; - switch (bitPos) { - case PORT_ENABLE_STAT: - hp->RHportStatus->portStatus &= ~bitPos; - break; - - case PORT_RESET_STAT: - hp->RHportStatus->portStatus &= ~bitPos; - break; - - case PORT_POWER_STAT: - hp->RHportStatus->portStatus &= ~bitPos; - break; - - case PORT_SUSPEND_STAT: - hp->RHportStatus->portStatus &= ~bitPos; - break; - } -} - -/***************************************************************** - * - * Function Name: setPortStatus - * - * This function set the bit position of portStatus. - * - * Input: hci = data structure for the host controller - * bitPos = the bit position - * - * Return value : none - * - *****************************************************************/ -static void setPortStatus (hci_t * hci, __u16 bitPos) -{ - hcipriv_t *hp = &hci->hp; - switch (bitPos) { - case PORT_ENABLE_STAT: - hp->RHportStatus->portStatus |= bitPos; - break; - - case PORT_RESET_STAT: - hp->RHportStatus->portStatus |= bitPos; - break; - - case PORT_POWER_STAT: - hp->RHportStatus->portStatus |= bitPos; - break; - - case PORT_SUSPEND_STAT: - hp->RHportStatus->portStatus |= bitPos; - break; - } -} - -/***************************************************************** - * - * Function Name: hc_start - * - * This function starts the root hub functionality. - * - * Input: hci = data structure for the host controller - * - * Return value : 0 - * - *****************************************************************/ -static int hc_start (hci_t * hci) -{ - DBGFUNC ("Enter hc_start\n"); - - rh_connect_rh (hci); - - return 0; -} - -/***************************************************************** - * - * Function Name: hc_alloc_hci - * - * This function allocates all data structure and store in the - * private data structure. - * - * Input: hci = data structure for the host controller - * - * Return value : 0 - * - *****************************************************************/ -static hci_t *__devinit hc_alloc_hci (void) -{ - hci_t *hci; - hcipriv_t *hp; - portstat_t *ps; - struct usb_bus *bus; - - DBGFUNC ("Enter hc_alloc_hci\n"); - hci = (hci_t *) kmalloc (sizeof (hci_t), GFP_KERNEL); - if (!hci) - return NULL; - - memset (hci, 0, sizeof (hci_t)); - - hp = &hci->hp; - - hp->irq = -1; - hp->hcport = -1; - - /* setup root hub port status */ - - ps = (portstat_t *) kmalloc (sizeof (portstat_t), GFP_KERNEL); - - if (!ps) - return NULL; - ps->portStatus = PORT_STAT_DEFAULT; - ps->portChange = PORT_CHANGE_DEFAULT; - hp->RHportStatus = ps; - - hci->nakCnt = 0; - hci->last_packet_nak = 0; - - hci->a_td_array.len = 0; - hci->i_td_array[0].len = 0; - hci->i_td_array[1].len = 0; - hci->td_array = &hci->a_td_array; - hci->active_urbs = 0; - hci->active_trans = 0; - INIT_LIST_HEAD (&hci->hci_hcd_list); - list_add (&hci->hci_hcd_list, &hci_hcd_list); - init_waitqueue_head (&hci->waitq); - - INIT_LIST_HEAD (&hci->ctrl_list); - INIT_LIST_HEAD (&hci->bulk_list); - INIT_LIST_HEAD (&hci->iso_list); - INIT_LIST_HEAD (&hci->intr_list); - INIT_LIST_HEAD (&hci->del_list); - - bus = usb_alloc_bus (&hci_device_operations); - if (!bus) { - kfree (hci); - kfree (ps); - return NULL; - } - - hci->bus = bus; - bus->hcpriv = (void *) hci; - - return hci; -} - -/***************************************************************** - * - * Function Name: hc_release_hci - * - * This function De-allocate all resources - * - * Input: hci = data structure for the host controller - * - * Return value : 0 - * - *****************************************************************/ -static void hc_release_hci (hci_t * hci) -{ - hcipriv_t *hp = &hci->hp; - - DBGFUNC ("Enter hc_release_hci\n"); - - /* disconnect all devices */ - if (hci->bus->root_hub) - usb_disconnect (&hci->bus->root_hub); - - hc_reset (hci); - - if (hp->tl) - kfree (hp->tl); - - if (hp->hcport > 0) { - release_region (hp->hcport, 2); - hp->hcport = 0; - } - - if (hp->irq >= 0) { - free_irq (hp->irq, hci); - hp->irq = -1; - } - - usb_deregister_bus (hci->bus); - usb_put_bus (hci->bus); - - list_del_init (&hci->hci_hcd_list); - - kfree (hci); -} - -/***************************************************************** - * - * Function Name: init_irq - * - * This function is board specific. It sets up the interrupt to - * be an edge trigger and trigger on the rising edge - * - * Input: none - * - * Return value : none - * - *****************************************************************/ -void init_irq (void) -{ - GPDR &= ~(1 << 13); - set_GPIO_IRQ_edge (1 << 13, GPIO_RISING_EDGE); -} - -/***************************************************************** - * - * Function Name: hc_found_hci - * - * This function request IO memory regions, request IRQ, and - * allocate all other resources. - * - * Input: addr = first IO address - * addr2 = second IO address - * irq = interrupt number - * - * Return: 0 = success or error condition - * - *****************************************************************/ -static int __devinit hc_found_hci (int addr, int addr2, int irq) -{ - hci_t *hci; - hcipriv_t *hp; - - DBGFUNC ("Enter hc_found_hci\n"); - hci = hc_alloc_hci (); - if (!hci) { - return -ENOMEM; - } - - init_irq (); - hp = &hci->hp; - - if (!request_region (addr, 256, "SL811 USB HOST")) { - DBGERR ("request address %d failed", addr); - hc_release_hci (hci); - return -EBUSY; - } - hp->hcport = addr; - if (!hp->hcport) { - DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport); - } - - if (!request_region (addr2, 256, "SL811 USB HOST")) { - DBGERR ("request address %d failed", addr2); - hc_release_hci (hci); - return -EBUSY; - } - hp->hcport2 = addr2; - if (!hp->hcport2) { - DBGERR ("Error mapping SL811 Memory 0x%x", hp->hcport2); - } - - if (hc_alloc_trans_buffer (hci)) { - hc_release_hci (hci); - return -ENOMEM; - } - - usb_register_bus (hci->bus); - - if (request_irq (irq, hc_interrupt, 0, "SL811", hci) != 0) { - DBGERR ("request interrupt %d failed", irq); - hc_release_hci (hci); - return -EBUSY; - } - hp->irq = irq; - - printk (KERN_INFO __FILE__ ": USB SL811 at %x, addr2 = %x, IRQ %d\n", - addr, addr2, irq); - hc_reset (hci); - - if (hc_start (hci) < 0) { - DBGERR ("can't start usb-%x", addr); - hc_release_hci (hci); - return -EBUSY; - } - - return 0; -} - -/***************************************************************** - * - * Function Name: hci_hcd_init - * - * This is an init function, and it is the first function being called - * - * Input: none - * - * Return: 0 = success or error condition - * - *****************************************************************/ -static int __init hci_hcd_init (void) -{ - int ret; - - DBGFUNC ("Enter hci_hcd_init\n"); - if (usb_disabled()) - return -ENODEV; - - ret = hc_found_hci (base_addr, data_reg_addr, irq); - - return ret; -} - -/***************************************************************** - * - * Function Name: hci_hcd_cleanup - * - * This is a cleanup function, and it is called when module is - * unloaded. - * - * Input: none - * - * Return: none - * - *****************************************************************/ -static void __exit hci_hcd_cleanup (void) -{ - hci_t *hci, *tmp; - - DBGFUNC ("Enter hci_hcd_cleanup\n"); - list_for_each_entry_safe(hci, tmp, &hci_hcd_list, hci_hcd_list) - hc_release_hci (hci); -} - -module_init (hci_hcd_init); -module_exit (hci_hcd_cleanup); - -MODULE_AUTHOR ("Pei Liu "); -MODULE_DESCRIPTION ("USB SL811HS Host Controller Driver"); diff -Nru a/drivers/usb/host/hc_sl811.h b/drivers/usb/host/hc_sl811.h --- a/drivers/usb/host/hc_sl811.h 2004-12-12 17:40:52 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,385 +0,0 @@ -/* - * SL811HS HCD (Host Controller Driver) for USB. - * - * COPYRIGHT (C) by CYPRESS SEMICONDUCTOR INC - * - * - */ - -#define GET_FRAME_NUMBER(hci) READ_REG32 (hci, HcFmNumber) - -/* - * Maximum number of root hub ports - */ -#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ - -/* control and status registers */ -#define HcRevision 0x00 -#define HcControl 0x01 -#define HcCommandStatus 0x02 -#define HcInterruptStatus 0x03 -#define HcInterruptEnable 0x04 -#define HcInterruptDisable 0x05 -#define HcFmInterval 0x0D -#define HcFmRemaining 0x0E -#define HcFmNumber 0x0F -#define HcLSThreshold 0x11 -#define HcRhDescriptorA 0x12 -#define HcRhDescriptorB 0x13 -#define HcRhStatus 0x14 -#define HcRhPortStatus 0x15 - -#define HcHardwareConfiguration 0x20 -#define HcDMAConfiguration 0x21 -#define HcTransferCounter 0x22 -#define HcuPInterrupt 0x24 -#define HcuPInterruptEnable 0x25 -#define HcChipID 0x27 -#define HcScratch 0x28 -#define HcSoftwareReset 0x29 -#define HcITLBufferLength 0x2A -#define HcATLBufferLength 0x2B -#define HcBufferStatus 0x2C -#define HcReadBackITL0Length 0x2D -#define HcReadBackITL1Length 0x2E -#define HcITLBufferPort 0x40 -#define HcATLBufferPort 0x41 - -/* OHCI CONTROL AND STATUS REGISTER MASKS */ - -/* - * HcControl (control) register masks - */ -#define OHCI_CTRL_HCFS (3 << 6) /* BUS state mask */ -#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ -#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ - -/* pre-shifted values for HCFS */ -#define OHCI_USB_RESET (0 << 6) -#define OHCI_USB_RESUME (1 << 6) -#define OHCI_USB_OPER (2 << 6) -#define OHCI_USB_SUSPEND (3 << 6) - -/* - * HcCommandStatus (cmdstatus) register masks - */ -#define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_SO (3 << 16) /* scheduling overrun count */ - -/* - * masks used with interrupt registers: - * HcInterruptStatus (intrstatus) - * HcInterruptEnable (intrenable) - * HcInterruptDisable (intrdisable) - */ -#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ - -#define OHCI_INTR_SF (1 << 2) /* start frame */ -#define OHCI_INTR_RD (1 << 3) /* resume detect */ -#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ -#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ -#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ -#define OHCI_INTR_ATD (1 << 7) /* scheduling overrun */ - -#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ - -/* - * HcHardwareConfiguration - */ -#define InterruptPinEnable (1 << 0) -#define InterruptPinTrigger (1 << 1) -#define InterruptOutputPolarity (1 << 2) -#define DataBusWidth16 (1 << 3) -#define DREQOutputPolarity (1 << 5) -#define DACKInputPolarity (1 << 6) -#define EOTInputPolarity (1 << 7) -#define DACKMode (1 << 8) -#define AnalogOCEnable (1 << 10) -#define SuspendClkNotStop (1 << 11) -#define DownstreamPort15KRSel (1 << 12) - -/* - * HcDMAConfiguration - */ -#define DMAReadWriteSelect (1 << 0) -#define ITL_ATL_DataSelect (1 << 1) -#define DMACounterSelect (1 << 2) -#define DMAEnable (1 << 4) -#define BurstLen_1 0 -#define BurstLen_4 (1 << 5) -#define BurstLen_8 (2 << 5) - -/* - * HcuPInterrupt - */ -#define SOFITLInt (1 << 0) -#define ATLInt (1 << 1) -#define AllEOTInterrupt (1 << 2) -#define OPR_Reg (1 << 4) -#define HCSuspended (1 << 5) -#define ClkReady (1 << 6) - -/* - * HcBufferStatus - */ -#define ITL0BufferFull (1 << 0) -#define ITL1BufferFull (1 << 1) -#define ATLBufferFull (1 << 2) -#define ITL0BufferDone (1 << 3) -#define ITL1BufferDone (1 << 4) -#define ATLBufferDone (1 << 5) - -/* OHCI ROOT HUB REGISTER MASKS */ - -/* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status */ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ - -/* roothub.status bits */ -#define RH_HS_LPS 0x00000001 /* local power status */ -#define RH_HS_OCI 0x00000002 /* over current indicator */ -#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ -#define RH_HS_LPSC 0x00010000 /* local power status change */ -#define RH_HS_OCIC 0x00020000 /* over current indicator change */ -#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ - -/* roothub.b masks */ -#define RH_B_DR 0x0000ffff /* device removable flags */ -#define RH_B_PPCM 0xffff0000 /* port power control mask */ - -/* roothub.a masks */ -#define RH_A_NDP (0xff << 0) /* number of downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* over current protection mode */ -#define RH_A_NOCP (1 << 12) /* no over current protection */ -#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ - -#define URB_DEL 1 - -#define PORT_STAT_DEFAULT 0x0100 -#define PORT_CONNECT_STAT 0x1 -#define PORT_ENABLE_STAT 0x2 -#define PORT_SUSPEND_STAT 0x4 -#define PORT_OVER_CURRENT_STAT 0x8 -#define PORT_RESET_STAT 0x10 -#define PORT_POWER_STAT 0x100 -#define PORT_LOW_SPEED_DEV_ATTACH_STAT 0x200 - -#define PORT_CHANGE_DEFAULT 0x0 -#define PORT_CONNECT_CHANGE 0x1 -#define PORT_ENABLE_CHANGE 0x2 -#define PORT_SUSPEND_CHANGE 0x4 -#define PORT_OVER_CURRENT_CHANGE 0x8 -#define PORT_RESET_CHANGE 0x10 - -/* Port Status Request info */ - -typedef struct portstat { - __u16 portChange; - __u16 portStatus; -} portstat_t; - -typedef struct hcipriv { - int irq; - int disabled; /* e.g. got a UE, we're hung */ - atomic_t resume_count; /* defending against multiple resumes */ - struct ohci_regs *regs; /* OHCI controller's memory */ - int hcport; /* I/O base address */ - int hcport2; /* I/O data reg addr */ - - struct portstat *RHportStatus; /* root hub port status */ - - int intrstatus; - __u32 hc_control; /* copy of the hc control reg */ - - int frame; - - __u8 *tl; - int xferPktLen; - int atl_len; - int atl_buffer_len; - int itl0_len; - int itl1_len; - int itl_buffer_len; - int itl_index; - int tl_last; - int units_left; - -} hcipriv_t; -struct hci; - -#define cClt 0 // Control -#define cISO 1 // ISO -#define cBULK 2 // BULK -#define cInt 3 // Interrupt -#define ISO_BIT 0x10 - -/*------------------------------------------------------------------------- - * EP0 use for configuration and Vendor Specific command interface - *------------------------------------------------------------------------*/ -#define cMemStart 0x10 -#define EP0Buf 0x40 /* SL11H/SL811H memory start at 0x40 */ -#define EP0Len 0x40 /* Length of config buffer EP0Buf */ -#define EP1Buf 0x60 -#define EP1Len 0x40 - -/*------------------------------------------------------------------------- - * SL11H/SL811H memory from 80h-ffh use as ping-pong buffer. - *------------------------------------------------------------------------*/ -#define uBufA 0x80 /* buffer A address for DATA0 */ -#define uBufB 0xc0 /* buffer B address for DATA1 */ -#define uXferLen 0x40 /* xfer length */ -#define sMemSize 0xc0 /* Total SL11 memory size */ -#define cMemEnd 256 - -/*------------------------------------------------------------------------- - * SL811H Register Control memory map - * --Note: - * --SL11H only has one control register set from 0x00-0x04 - * --SL811H has two control register set from 0x00-0x04 and 0x08-0x0c - *------------------------------------------------------------------------*/ - -#define EP0Control 0x00 -#define EP0Address 0x01 -#define EP0XferLen 0x02 -#define EP0Status 0x03 -#define EP0Counter 0x04 - -#define EP1Control 0x08 -#define EP1Address 0x09 -#define EP1XferLen 0x0a -#define EP1Status 0x0b -#define EP1Counter 0x0c - -#define CtrlReg 0x05 -#define IntEna 0x06 - // 0x07 is reserved -#define IntStatus 0x0d -#define cDATASet 0x0e -#define cSOFcnt 0x0f -#define IntMask 0x57 /* Reset|DMA|EP0|EP2|EP1 for IntEna */ -#define HostMask 0x47 /* Host request command for IntStatus */ -#define ReadMask 0xd7 /* Read mask interrupt for IntStatus */ - -/*------------------------------------------------------------------------- - * Standard Chapter 9 definition - *------------------------------------------------------------------------- - */ -#define GET_STATUS 0x00 -#define CLEAR_FEATURE 0x01 -#define SET_FEATURE 0x03 -#define SET_ADDRESS 0x05 -#define GET_DESCRIPTOR 0x06 -#define SET_DESCRIPTOR 0x07 -#define GET_CONFIG 0x08 -#define SET_CONFIG 0x09 -#define GET_INTERFACE 0x0a -#define SET_INTERFACE 0x0b -#define SYNCH_FRAME 0x0c - -#define DEVICE 0x01 -#define CONFIGURATION 0x02 -#define STRING 0x03 -#define INTERFACE 0x04 -#define ENDPOINT 0x05 - -/*------------------------------------------------------------------------- - * SL11H/SL811H definition - *------------------------------------------------------------------------- - */ -#define DATA0_WR 0x07 // (Arm+Enable+tranmist to Host+DATA0) -#define DATA1_WR 0x47 // (Arm+Enable+tranmist to Host on DATA1) -#define ZDATA0_WR 0x05 // (Arm+Transaction Ignored+tranmist to Host+DATA0) -#define ZDATA1_WR 0x45 // (Arm+Transaction Ignored+tranmist to Host+DATA1) -#define DATA0_RD 0x03 // (Arm+Enable+received from Host+DATA0) -#define DATA1_RD 0x43 // (Arm+Enable+received from Host+DATA1) - -#define PID_SETUP 0x2d // USB Specification 1.1 Standard Definition -#define PID_SOF 0xA5 -#define PID_IN 0x69 -#define PID_OUT 0xe1 - -#define MAX_RETRY 0xffff -#define TIMEOUT 5 /* 2 mseconds */ - -#define SL11H_HOSTCTLREG 0 -#define SL11H_BUFADDRREG 1 -#define SL11H_BUFLNTHREG 2 -#define SL11H_PKTSTATREG 3 /* read */ -#define SL11H_PIDEPREG 3 /* write */ -#define SL11H_XFERCNTREG 4 /* read */ -#define SL11H_DEVADDRREG 4 /* write */ -#define SL11H_CTLREG1 5 -#define SL11H_INTENBLREG 6 - -#define SL11H_HOSTCTLREG_B 8 -#define SL11H_BUFADDRREG_B 9 -#define SL11H_BUFLNTHREG_B 0x0A -#define SL11H_PKTSTATREG_B 0x0B /* read */ -#define SL11H_PIDEPREG_B 0x0B /* write */ -#define SL11H_XFERCNTREG_B 0x0C /* read */ -#define SL11H_DEVADDRREG_B 0x0C /* write */ - -#define SL11H_INTSTATREG 0x0D /* write clears bitwise */ -#define SL11H_HWREVREG 0x0E /* read */ -#define SL11H_SOFLOWREG 0x0E /* write */ -#define SL11H_SOFTMRREG 0x0F /* read */ -#define SL11H_CTLREG2 0x0F /* write */ -#define SL11H_DATA_START 0x10 - -/* Host control register bits (addr 0) */ -#define SL11H_HCTLMASK_ARM 1 -#define SL11H_HCTLMASK_ENBLEP 2 -#define SL11H_HCTLMASK_WRITE 4 -#define SL11H_HCTLMASK_ISOCH 0x10 -#define SL11H_HCTLMASK_AFTERSOF 0x20 -#define SL11H_HCTLMASK_SEQ 0x40 -#define SL11H_HCTLMASK_PREAMBLE 0x80 - -/* Packet status register bits (addr 3) */ -#define SL11H_STATMASK_ACK 1 -#define SL11H_STATMASK_ERROR 2 -#define SL11H_STATMASK_TMOUT 4 -#define SL11H_STATMASK_SEQ 8 -#define SL11H_STATMASK_SETUP 0x10 -#define SL11H_STATMASK_OVF 0x20 -#define SL11H_STATMASK_NAK 0x40 -#define SL11H_STATMASK_STALL 0x80 - -/* Control register 1 bits (addr 5) */ -#define SL11H_CTL1MASK_DSBLSOF 1 -#define SL11H_CTL1MASK_NOTXEOF2 4 -#define SL11H_CTL1MASK_DSTATE 0x18 -#define SL11H_CTL1MASK_NSPD 0x20 -#define SL11H_CTL1MASK_SUSPEND 0x40 -#define SL11H_CTL1MASK_CLK12 0x80 - -#define SL11H_CTL1VAL_RESET 8 - -/* Interrupt enable (addr 6) and interrupt status register bits (addr 0xD) */ -#define SL11H_INTMASK_XFERDONE 1 -#define SL11H_INTMASK_SOFINTR 0x10 -#define SL11H_INTMASK_INSRMV 0x20 -#define SL11H_INTMASK_USBRESET 0x40 -#define SL11H_INTMASK_DSTATE 0x80 /* only in status reg */ - -/* HW rev and SOF lo register bits (addr 0xE) */ -#define SL11H_HWRMASK_HWREV 0xF0 - -/* SOF counter and control reg 2 (addr 0xF) */ -#define SL11H_CTL2MASK_SOFHI 0x3F -#define SL11H_CTL2MASK_DSWAP 0x40 -#define SL11H_CTL2MASK_HOSTMODE 0xae - diff -Nru a/drivers/usb/host/hc_sl811_rh.c b/drivers/usb/host/hc_sl811_rh.c --- a/drivers/usb/host/hc_sl811_rh.c 2004-12-12 17:40:53 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,583 +0,0 @@ - -/*-------------------------------------------------------------------------*/ -/*-------------------------------------------------------------------------* - * SL811HS virtual root hub - * - * based on usb-ohci.c by R. Weissgaerber et al. - *-------------------------------------------------------------------------* - * 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 - * - *-------------------------------------------------------------------------*/ - -/* FIXME: reuse the root hub framework in usbcore, shrinking this code. */ - -#ifdef DEBUG -#undef DEBUG -#endif -static __u32 getPortStatusAndChange (hci_t * hci); -static void setPortStatus (hci_t * hci, __u16 bitPos); -static void setPortChange (hci_t * hci, __u16 bitPos); -static void clrPortStatus (hci_t * hci, __u16 bitPos); -static void clrPortChange (hci_t * hci, __u16 bitPos); -static int USBReset (hci_t * hci); -static int cc_to_error (int cc); - -/*-------------------------------------------------------------------------* - * Virtual Root Hub - *-------------------------------------------------------------------------*/ - -/* Device descriptor */ -static __u8 root_hub_dev_des[] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, /* __u16 bcdUSB; v1.1 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = { - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, - 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -/* Hub class-specific descriptor is constructed dynamically */ - -/*************************************************************************** - * Function Name : rh_send_irq - * - * This function examine the port change in the virtual root hub. - * - * Note: This function assumes only one port exist in the root hub. - * - * Input: hci = data structure for the host controller - * rh_data = The pointer to port change data - * rh_len = length of the data in bytes - * - * Return: length of data - **************************************************************************/ -static int rh_send_irq (hci_t * hci, void *rh_data, int rh_len) -{ - int num_ports; - int i; - int ret; - int len; - __u8 data[8]; - - DBGFUNC ("enter rh_send_irq: \n"); - - /* Assuming the root hub has one port. This value need to change if - * there are more than one port for the root hub - */ - - num_ports = 1; - - /* The root hub status is not implemented, it basically has two fields: - * -- Local Power Status - * -- Over Current Indicator - * -- Local Power Change - * -- Over Current Indicator - * - * Right now, It is assume the power is good and no changes - */ - - *(__u8 *) data = 0; - - ret = *(__u8 *) data; - - /* Has the port status change within the root hub: It checks for - * -- Port Connect Status change - * -- Port Enable Change - */ - - for (i = 0; i < num_ports; i++) { - *(__u8 *) (data + (i + 1) / 8) |= - (((getPortStatusAndChange (hci) >> 16) & (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1 : 0) << ((i + 1) % 8); - ret += *(__u8 *) (data + (i + 1) / 8); - - /* After the port change is read, it should be reset so the next time - * is it doesn't trigger a change again */ - - } - len = i / 8 + 1; - - if (ret > 0) { - memcpy (rh_data, data, min (len, min (rh_len, (int)sizeof (data)))); - return len; - } - return 0; -} - -/*************************************************************************** - * Function Name : rh_int_timer_do - * - * This function is called when the timer expires. It gets the the port - * change data and pass along to the upper protocol. - * - * Note: The virtual root hub interrupt pipe are polled by the timer - * every "interval" ms - * - * Input: ptr = ptr to the urb - * - * Return: none - **************************************************************************/ -static void rh_int_timer_do (unsigned long ptr) -{ - int len; - struct urb *urb = (struct urb *) ptr; - hci_t *hci = urb->dev->bus->hcpriv; - - DBGFUNC ("enter rh_int_timer_do\n"); - - if (hci->rh.send) { - len = rh_send_irq (hci, urb->transfer_buffer, - urb->transfer_buffer_length); - if (len > 0) { - urb->actual_length = len; - if (urb_debug == 2) - urb_print (urb, "RET-t(rh)", - usb_pipeout (urb->pipe)); - - if (urb->complete) { - urb->complete (urb, NULL); - } - } - } - - /* re-activate the timer */ - rh_init_int_timer (urb); -} - -/*************************************************************************** - * Function Name : rh_init_int_timer - * - * This function creates a timer that act as interrupt pipe in the - * virtual hub. - * - * Note: The virtual root hub's interrupt pipe are polled by the timer - * every "interval" ms - * - * Input: urb = USB request block - * - * Return: 0 - **************************************************************************/ -static int rh_init_int_timer (struct urb * urb) -{ - hci_t *hci = urb->dev->bus->hcpriv; - hci->rh.interval = urb->interval; - - init_timer (&hci->rh.rh_int_timer); - hci->rh.rh_int_timer.function = rh_int_timer_do; - hci->rh.rh_int_timer.data = (unsigned long) urb; - hci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000; - add_timer (&hci->rh.rh_int_timer); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* for returning string descriptors in UTF-16LE */ -static int ascii2utf (char *ascii, __u8 *utf, int utfmax) -{ - int retval; - - for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) { - *utf++ = *ascii++ & 0x7f; - *utf++ = 0; - } - return retval; -} - -static int root_hub_string (int id, int serial, char *type, __u8 *data, int len) -{ - char buf [30]; - - // assert (len > (2 * (sizeof (buf) + 1))); - // assert (strlen (type) <= 8); - - // language ids - if (id == 0) { - *data++ = 4; *data++ = 3; /* 4 bytes data */ - *data++ = 0; *data++ = 0; /* some language id */ - return 4; - - // serial number - } else if (id == 1) { - sprintf (buf, "%x", serial); - - // product description - } else if (id == 2) { - sprintf (buf, "USB %s Root Hub", type); - - // id 3 == vendor description - - // unsupported IDs --> "stall" - } else - return 0; - - data [0] = 2 + ascii2utf (buf, data + 2, len - 2); - data [1] = 3; - return data [0]; -} - -/*-------------------------------------------------------------------------*/ - -/* helper macro */ -#define OK(x) len = (x); break - -/*************************************************************************** - * Function Name : rh_submit_urb - * - * This function handles all USB request to the the virtual root hub - * - * Input: urb = USB request block - * - * Return: 0 - **************************************************************************/ -static int rh_submit_urb (struct urb * urb) -{ - struct usb_device *usb_dev = urb->dev; - hci_t *hci = usb_dev->bus->hcpriv; - unsigned int pipe = urb->pipe; - struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; - void *data = urb->transfer_buffer; - int leni = urb->transfer_buffer_length; - int len = 0; - int status = TD_CC_NOERROR; - __u32 datab[4]; - __u8 *data_buf = (__u8 *) datab; - - __u16 bmRType_bReq; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - - DBGFUNC ("enter rh_submit_urb\n"); - if (usb_pipeint (pipe)) { - hci->rh.urb = urb; - hci->rh.send = 1; - hci->rh.interval = urb->interval; - rh_init_int_timer (urb); - urb->status = cc_to_error (TD_CC_NOERROR); - - return 0; - } - - bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8); - wValue = le16_to_cpu (cmd->wValue); - wIndex = le16_to_cpu (cmd->wIndex); - wLength = le16_to_cpu (cmd->wLength); - - DBG ("rh_submit_urb, req = %d(%x) len=%d", - bmRType_bReq, bmRType_bReq, wLength); - - switch (bmRType_bReq) { - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ - - case RH_GET_STATUS: - *(__u16 *) data_buf = cpu_to_le16 (1); - OK (2); - - case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *) data_buf = cpu_to_le16 (0); - OK (2); - - case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *) data_buf = cpu_to_le16 (0); - OK (2); - - case RH_GET_STATUS | RH_CLASS: - *(__u32 *) data_buf = cpu_to_le32 (0); - OK (4); - - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - *(__u32 *) data_buf = - cpu_to_le32 (getPortStatusAndChange (hci)); - OK (4); - - case RH_CLEAR_FEATURE | RH_ENDPOINT: - switch (wValue) { - case (RH_ENDPOINT_STALL): - OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_CLASS: - switch (wValue) { - case RH_C_HUB_LOCAL_POWER: - OK (0); - - case (RH_C_HUB_OVER_CURRENT): - /* Over Current Not Implemented */ - OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_ENABLE): - clrPortStatus (hci, PORT_ENABLE_STAT); - OK (0); - - case (RH_PORT_SUSPEND): - clrPortStatus (hci, PORT_SUSPEND_STAT); - OK (0); - - case (RH_PORT_POWER): - clrPortStatus (hci, PORT_POWER_STAT); - OK (0); - - case (RH_C_PORT_CONNECTION): - clrPortChange (hci, PORT_CONNECT_STAT); - OK (0); - - case (RH_C_PORT_ENABLE): - clrPortChange (hci, PORT_ENABLE_STAT); - OK (0); - - case (RH_C_PORT_SUSPEND): - clrPortChange (hci, PORT_SUSPEND_STAT); - OK (0); - - case (RH_C_PORT_OVER_CURRENT): - clrPortChange (hci, PORT_OVER_CURRENT_STAT); - OK (0); - - case (RH_C_PORT_RESET): - clrPortChange (hci, PORT_RESET_STAT); - OK (0); - } - break; - - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_SUSPEND): - setPortStatus (hci, PORT_SUSPEND_STAT); - OK (0); - - case (RH_PORT_RESET): - setPortStatus (hci, PORT_RESET_STAT); - // USBReset(hci); - clrPortChange (hci, - PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE - | PORT_SUSPEND_CHANGE | - PORT_OVER_CURRENT_CHANGE); - setPortChange (hci, PORT_RESET_CHANGE); - clrPortStatus (hci, PORT_RESET_STAT); - setPortStatus (hci, PORT_ENABLE_STAT); - - OK (0); - - case (RH_PORT_POWER): - setPortStatus (hci, PORT_POWER_STAT); - OK (0); - - case (RH_PORT_ENABLE): - setPortStatus (hci, PORT_ENABLE_STAT); - OK (0); - } - break; - - case RH_SET_ADDRESS: - hci->rh.devnum = wValue; - OK (0); - - case RH_GET_DESCRIPTOR: - DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue); - switch ((wValue & 0xff00) >> 8) { - case (0x01): /* device descriptor */ - len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength)); - data_buf = root_hub_dev_des; - OK (len); - - case (0x02): /* configuration descriptor */ - len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength)); - data_buf = root_hub_config_des; - OK (len); - - case (0x03): /* string descriptors */ - len = root_hub_string (wValue & 0xff, (int) (long) 0, - "SL811HS", data, wLength); - if (len > 0) { - data_buf = data; - OK (min (leni, len)); - } - - default: - status = SL11H_STATMASK_STALL; - } - break; - - case RH_GET_DESCRIPTOR | RH_CLASS: - data_buf[0] = 9; // min length; - data_buf[1] = 0x29; - data_buf[2] = 1; // # of downstream port - data_buf[3] = 0; - datab[1] = 0; - data_buf[5] = 50; // 100 ms for port reset - data_buf[7] = 0xfc; // which port is attachable - if (data_buf[2] < 7) { - data_buf[8] = 0xff; - } else { - } - - len = min (leni, min ((__u16)data_buf[0], wLength)); - OK (len); - - case RH_GET_CONFIGURATION: - *(__u8 *) data_buf = 0x01; - OK (1); - - case RH_SET_CONFIGURATION: - OK (0); - - default: - DBGERR ("unsupported root hub command"); - status = SL11H_STATMASK_STALL; - } - - len = min (len, leni); - if (data != data_buf) - memcpy (data, data_buf, len); - urb->actual_length = len; - urb->status = cc_to_error (status); - - urb->hcpriv = NULL; - urb->dev = NULL; - if (urb->complete) { - urb->complete (urb, NULL); - } - - return 0; -} - -/*************************************************************************** - * Function Name : rh_unlink_urb - * - * This function unlinks the URB - * - * Input: urb = USB request block - * - * Return: 0 - **************************************************************************/ -static int rh_unlink_urb (struct urb * urb) -{ - hci_t *hci = urb->dev->bus->hcpriv; - - DBGFUNC ("enter rh_unlink_urb\n"); - if (hci->rh.urb == urb) { - hci->rh.send = 0; - del_timer (&hci->rh.rh_int_timer); - hci->rh.urb = NULL; - - urb->hcpriv = NULL; - usb_put_dev (urb->dev); - urb->dev = NULL; - if (urb->transfer_flags & URB_ASYNC_UNLINK) { - urb->status = -ECONNRESET; - if (urb->complete) { - urb->complete (urb, NULL); - } - } else - urb->status = -ENOENT; - } - return 0; -} - -/*************************************************************************** - * Function Name : rh_connect_rh - * - * This function connect the virtual root hub to the USB stack - * - * Input: urb = USB request block - * - * Return: 0 - **************************************************************************/ -static int rh_connect_rh (hci_t * hci) -{ - struct usb_device *usb_dev; - int retval; - - hci->rh.devnum = 0; - usb_dev = usb_alloc_dev (NULL, hci->bus, 0); - if (!usb_dev) - return -ENOMEM; - - usb_dev->devnum = 1; - usb_dev->bus->devnum_next = usb_dev->devnum + 1; - set_bit (usb_dev->devnum, usb_dev->bus->devmap.devicemap); - - down (&usb_bus_list_lock); - hci->bus->root_hub = usb_dev; - retval = usb_new_device (usb_dev); - if (retval != 0) - hci->bus->root_hub = NULL; - up (&usb_bus_list_lock); - if (retval != 0) { - usb_put_dev (usb_dev); - return -ENODEV; - } - - return 0; -} diff -Nru a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c --- a/drivers/usb/host/ohci-hub.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/usb/host/ohci-hub.c 2004-12-12 17:40:52 -08:00 @@ -306,17 +306,25 @@ struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ports, i, changed = 0, length = 1; int can_suspend = 1; + unsigned long flags; - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ - if (!HCD_IS_RUNNING(ohci->hcd.state)) - return 0; + spin_lock_irqsave (&ohci->lock, flags); + + /* handle autosuspended root: finish resuming before + * letting khubd or root hub timer see state changes. + */ + if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER + || !HCD_IS_RUNNING(ohci->hcd.state)) { + can_suspend = 0; + goto done; + } ports = roothub_a (ohci) & RH_A_NDP; if (ports > MAX_ROOT_PORTS) { ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n", ports, ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); /* retry later; "should not happen" */ - return 0; + goto done; } /* init status */ @@ -352,6 +360,8 @@ continue; can_suspend = 0; } +done: + spin_unlock_irqrestore (&ohci->lock, flags); #ifdef CONFIG_PM /* save power by suspending idle root hubs; diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c --- a/drivers/usb/host/ohci-pci.c 2004-12-12 17:40:53 -08:00 +++ b/drivers/usb/host/ohci-pci.c 2004-12-12 17:40:53 -08:00 @@ -121,10 +121,7 @@ msleep (100); #ifdef CONFIG_PMAC_PBOOK - if (_machine == _MACH_Pmac) - disable_irq ((to_pci_dev(hcd->self.controller))->irq); - - { + if (_machine == _MACH_Pmac) { struct device_node *of_node; /* Disable USB PAD & cell clock */ @@ -132,7 +129,7 @@ if (of_node) pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0); } -#endif +#endif /* CONFIG_PMAC_PBOOK */ return 0; } @@ -143,7 +140,7 @@ int retval = 0; #ifdef CONFIG_PMAC_PBOOK - { + if (_machine == _MACH_Pmac) { struct device_node *of_node; /* Re-enable USB PAD & cell clock */ @@ -151,7 +148,7 @@ if (of_node) pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1); } -#endif +#endif /* CONFIG_PMAC_PBOOK */ /* resume root hub */ if (time_before (jiffies, ohci->next_statechange)) @@ -165,12 +162,6 @@ usb_unlock_device (hcd->self.root_hub); #endif - if (retval == 0) { -#ifdef CONFIG_PMAC_PBOOK - if (_machine == _MACH_Pmac) - enable_irq (to_pci_dev(hcd->self.controller)->irq); -#endif - } return retval; } diff -Nru a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/host/sl811-hcd.c 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,1905 @@ +/* + * SL811HS HCD (Host Controller Driver) for USB. + * + * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) + * Copyright (C) 2004 David Brownell + * + * Periodic scheduling is based on Roman's OHCI code + * Copyright (C) 1999 Roman Weissgaerber + * + * The SL811HS controller handles host side USB (like the SL11H, but with + * another register set and SOF generation) as well as peripheral side USB + * (like the SL811S). This driver version doesn't implement the Gadget API + * for the peripheral role; or OTG (that'd need much external circuitry). + * + * For documentation, see the SL811HS spec and the "SL811HS Embedded Host" + * document (providing significant pieces missing from that spec); plus + * the SL811S spec if you want peripheral side info. + */ + +/* + * Status: Passed basic stress testing, works with hubs, mice, keyboards, + * and usb-storage. + * + * TODO: + * - usb suspend/resume triggered by sl811 (with USB_SUSPEND) + * - various issues noted in the code + * - performance work; use both register banks; ... + * - use urb->iso_frame_desc[] with ISO transfers + */ + +#undef VERBOSE +#undef PACKET_TRACE + +#include + +#ifdef CONFIG_USB_DEBUG +# define DEBUG +#else +# undef DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../core/hcd.h" +#include "sl811.h" + + +MODULE_DESCRIPTION("SL811HS USB Host Controller Driver"); +MODULE_LICENSE("GPL"); + +#define DRIVER_VERSION "06 Dec 2004" + + +#ifndef DEBUG +# define STUB_DEBUG_FILE +#endif + +/* for now, use only one transfer register bank */ +#undef USE_B + +/* this doesn't understand urb->iso_frame_desc[], but if you had a driver + * that just queued one ISO frame per URB then iso transfers "should" work + * using the normal urb status fields. + */ +#define DISABLE_ISO + +// #define QUIRK2 +#define QUIRK3 + +static const char hcd_name[] = "sl811-hcd"; + +/*-------------------------------------------------------------------------*/ + +static irqreturn_t sl811h_irq(int irq, void *_sl811, struct pt_regs *regs); + +static void port_power(struct sl811 *sl811, int is_on) +{ + /* hub is inactive unless the port is powered */ + if (is_on) { + if (sl811->port1 & (1 << USB_PORT_FEAT_POWER)) + return; + + sl811->port1 = (1 << USB_PORT_FEAT_POWER); + sl811->irq_enable = SL11H_INTMASK_INSRMV; + sl811->hcd.self.controller->power.power_state = PM_SUSPEND_ON; + } else { + sl811->port1 = 0; + sl811->irq_enable = 0; + sl811->hcd.state = USB_STATE_HALT; + sl811->hcd.self.controller->power.power_state = PM_SUSPEND_DISK; + } + sl811->ctrl1 = 0; + sl811_write(sl811, SL11H_IRQ_ENABLE, 0); + sl811_write(sl811, SL11H_IRQ_STATUS, ~0); + + if (sl811->board && sl811->board->port_power) { + /* switch VBUS, at 500mA unless hub power budget gets set */ + DBG("power %s\n", is_on ? "on" : "off"); + sl811->board->port_power(sl811->hcd.self.controller, is_on); + } + + /* reset as thoroughly as we can */ + if (sl811->board && sl811->board->reset) + sl811->board->reset(sl811->hcd.self.controller); + + sl811_write(sl811, SL11H_IRQ_ENABLE, 0); + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + sl811_write(sl811, SL811HS_CTLREG2, SL811HS_CTL2_INIT); + sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); + + // if !is_on, put into lowpower mode now +} + +/*-------------------------------------------------------------------------*/ + +/* This is a PIO-only HCD. Queueing appends URBs to the endpoint's queue, + * and may start I/O. Endpoint queues are scanned during completion irq + * handlers (one per packet: ACK, NAK, faults, etc) and urb cancelation. + * + * Using an external DMA engine to copy a packet at a time could work, + * though setup/teardown costs may be too big to make it worthwhile. + */ + +/* SETUP starts a new control request. Devices are not allowed to + * STALL or NAK these; they must cancel any pending control requests. + */ +static void setup_packet( + struct sl811 *sl811, + struct sl811h_ep *ep, + struct urb *urb, + u8 bank, + u8 control +) +{ + u8 addr; + u8 len; + void __iomem *data_reg; + + addr = SL811HS_PACKET_BUF(bank == 0); + len = sizeof(struct usb_ctrlrequest); + data_reg = sl811->data_reg; + sl811_write_buf(sl811, addr, urb->setup_packet, len); + + /* autoincrementing */ + sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); + writeb(len, data_reg); + writeb(SL_SETUP /* | ep->epnum */, data_reg); + writeb(usb_pipedevice(urb->pipe), data_reg); + + /* always OUT/data0 */ ; + sl811_write(sl811, bank + SL11H_HOSTCTLREG, + control | SL11H_HCTLMASK_OUT); + ep->length = 0; + PACKET("SETUP qh%p\n", ep); +} + +/* STATUS finishes control requests, often after IN or OUT data packets */ +static void status_packet( + struct sl811 *sl811, + struct sl811h_ep *ep, + struct urb *urb, + u8 bank, + u8 control +) +{ + int do_out; + void __iomem *data_reg; + + do_out = urb->transfer_buffer_length && usb_pipein(urb->pipe); + data_reg = sl811->data_reg; + + /* autoincrementing */ + sl811_write(sl811, bank + SL11H_BUFADDRREG, 0); + writeb(0, data_reg); + writeb((do_out ? SL_OUT : SL_IN) /* | ep->epnum */, data_reg); + writeb(usb_pipedevice(urb->pipe), data_reg); + + /* always data1; sometimes IN */ + control |= SL11H_HCTLMASK_TOGGLE; + if (do_out) + control |= SL11H_HCTLMASK_OUT; + sl811_write(sl811, bank + SL11H_HOSTCTLREG, control); + ep->length = 0; + PACKET("STATUS%s/%s qh%p\n", ep->nak_count ? "/retry" : "", + do_out ? "out" : "in", ep); +} + +/* IN packets can be used with any type of endpoint. here we just + * start the transfer, data from the peripheral may arrive later. + * urb->iso_frame_desc is currently ignored here... + */ +static void in_packet( + struct sl811 *sl811, + struct sl811h_ep *ep, + struct urb *urb, + u8 bank, + u8 control +) +{ + u8 addr; + u8 len; + void __iomem *data_reg; + + /* avoid losing data on overflow */ + len = ep->maxpacket; + addr = SL811HS_PACKET_BUF(bank == 0); + if (!(control & SL11H_HCTLMASK_ISOCH) + && usb_gettoggle(urb->dev, ep->epnum, 0)) + control |= SL11H_HCTLMASK_TOGGLE; + data_reg = sl811->data_reg; + + /* autoincrementing */ + sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); + writeb(len, data_reg); + writeb(SL_IN | ep->epnum, data_reg); + writeb(usb_pipedevice(urb->pipe), data_reg); + + sl811_write(sl811, bank + SL11H_HOSTCTLREG, control); + ep->length = min((int)len, + urb->transfer_buffer_length - urb->actual_length); + PACKET("IN%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "", + !!usb_gettoggle(urb->dev, ep->epnum, 0), ep, len); +} + +/* OUT packets can be used with any type of endpoint. + * urb->iso_frame_desc is currently ignored here... + */ +static void out_packet( + struct sl811 *sl811, + struct sl811h_ep *ep, + struct urb *urb, + u8 bank, + u8 control +) +{ + void *buf; + u8 addr; + u8 len; + void __iomem *data_reg; + + buf = urb->transfer_buffer + urb->actual_length; + prefetch(buf); + + len = min((int)ep->maxpacket, + urb->transfer_buffer_length - urb->actual_length); + + if (!(control & SL11H_HCTLMASK_ISOCH) + && usb_gettoggle(urb->dev, ep->epnum, 1)) + control |= SL11H_HCTLMASK_TOGGLE; + addr = SL811HS_PACKET_BUF(bank == 0); + data_reg = sl811->data_reg; + + sl811_write_buf(sl811, addr, buf, len); + + /* autoincrementing */ + sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); + writeb(len, data_reg); + writeb(SL_OUT | ep->epnum, data_reg); + writeb(usb_pipedevice(urb->pipe), data_reg); + + sl811_write(sl811, bank + SL11H_HOSTCTLREG, + control | SL11H_HCTLMASK_OUT); + ep->length = len; + PACKET("OUT%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "", + !!usb_gettoggle(urb->dev, ep->epnum, 1), ep, len); +} + +/*-------------------------------------------------------------------------*/ + +/* caller updates on-chip enables later */ + +static inline void sofirq_on(struct sl811 *sl811) +{ + if (sl811->irq_enable & SL11H_INTMASK_SOFINTR) + return; + VDBG("sof irq on\n"); + sl811->irq_enable |= SL11H_INTMASK_SOFINTR; +} + +static inline void sofirq_off(struct sl811 *sl811) +{ + if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR)) + return; + VDBG("sof irq off\n"); + sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR; +} + +/*-------------------------------------------------------------------------*/ + +/* pick the next endpoint for a transaction, and issue it. + * frames start with periodic transfers (after whatever is pending + * from the previous frame), and the rest of the time is async + * transfers, scheduled round-robin. + */ +static struct sl811h_ep *start(struct sl811 *sl811, u8 bank) +{ + struct sl811h_ep *ep; + struct sl811h_req *req; + struct urb *urb; + int fclock; + u8 control; + + /* use endpoint at schedule head */ + if (sl811->next_periodic) { + ep = sl811->next_periodic; + sl811->next_periodic = ep->next; + } else { + if (sl811->next_async) + ep = sl811->next_async; + else if (!list_empty(&sl811->async)) + ep = container_of(sl811->async.next, + struct sl811h_ep, schedule); + else { + /* could set up the first fullspeed periodic + * transfer for the next frame ... + */ + return NULL; + } + +#ifdef USE_B + if ((bank && sl811->active_b == ep) || sl811->active_a == ep) + return NULL; +#endif + + if (ep->schedule.next == &sl811->async) + sl811->next_async = NULL; + else + sl811->next_async = container_of(ep->schedule.next, + struct sl811h_ep, schedule); + } + + if (unlikely(list_empty(&ep->queue))) { + DBG("empty %p queue?\n", ep); + return NULL; + } + + req = container_of(ep->queue.next, struct sl811h_req, queue); + urb = req->urb; + control = ep->defctrl; + + /* if this frame doesn't have enough time left to transfer this + * packet, wait till the next frame. too-simple algorithm... + */ + fclock = sl811_read(sl811, SL11H_SOFTMRREG) << 6; + fclock -= 100; /* setup takes not much time */ + if (urb->dev->speed == USB_SPEED_LOW) { + if (control & SL11H_HCTLMASK_PREAMBLE) { + /* also note erratum 1: some hubs won't work */ + fclock -= 800; + } + fclock -= ep->maxpacket << 8; + + /* erratum 2: AFTERSOF only works for fullspeed */ + if (fclock < 0) { + if (ep->period) + sl811->stat_overrun++; + sofirq_on(sl811); + return NULL; + } + } else { + fclock -= 12000 / 19; /* 19 64byte packets/msec */ + if (fclock < 0) { + if (ep->period) + sl811->stat_overrun++; + control |= SL11H_HCTLMASK_AFTERSOF; + + /* throttle bulk/control irq noise */ + } else if (ep->nak_count) + control |= SL11H_HCTLMASK_AFTERSOF; + } + + + switch (ep->nextpid) { + case USB_PID_IN: + in_packet(sl811, ep, urb, bank, control); + break; + case USB_PID_OUT: + out_packet(sl811, ep, urb, bank, control); + break; + case USB_PID_SETUP: + setup_packet(sl811, ep, urb, bank, control); + break; + case USB_PID_ACK: /* for control status */ + status_packet(sl811, ep, urb, bank, control); + break; + default: + DBG("bad ep%p pid %02x\n", ep, ep->nextpid); + ep = NULL; + } + return ep; +} + +#define MIN_JIFFIES ((msecs_to_jiffies(2) > 1) ? msecs_to_jiffies(2) : 2) + +static inline void start_transfer(struct sl811 *sl811) +{ + if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) + return; + if (sl811->active_a == NULL) { + sl811->active_a = start(sl811, SL811_EP_A(SL811_HOST_BUF)); + if (sl811->active_a != NULL) + sl811->jiffies_a = jiffies + MIN_JIFFIES; + } +#ifdef USE_B + if (sl811->active_b == NULL) { + sl811->active_b = start(sl811, SL811_EP_B(SL811_HOST_BUF)); + if (sl811->active_b != NULL) + sl811->jiffies_b = jiffies + MIN_JIFFIES; + } +#endif +} + +static void finish_request( + struct sl811 *sl811, + struct sl811h_ep *ep, + struct sl811h_req *req, + struct pt_regs *regs, + int status +) __releases(sl811->lock) __acquires(sl811->lock) +{ + unsigned i; + struct urb *urb = req->urb; + + list_del(&req->queue); + kfree(req); + urb->hcpriv = NULL; + + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_SETUP; + + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = status; + spin_unlock(&urb->lock); + + spin_unlock(&sl811->lock); + usb_hcd_giveback_urb(&sl811->hcd, urb, regs); + spin_lock(&sl811->lock); + + /* leave active endpoints in the schedule */ + if (!list_empty(&ep->queue)) + return; + + /* async deschedule? */ + if (!list_empty(&ep->schedule)) { + list_del_init(&ep->schedule); + if (ep == sl811->next_async) + sl811->next_async = NULL; + return; + } + + /* periodic deschedule */ + DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { + struct sl811h_ep *temp; + struct sl811h_ep **prev = &sl811->periodic[i]; + + while (*prev && ((temp = *prev) != ep)) + prev = &temp->next; + if (*prev) + *prev = ep->next; + sl811->load[i] -= ep->load; + } + ep->branch = PERIODIC_SIZE; + sl811->periodic_count--; + hcd_to_bus(&sl811->hcd)->bandwidth_allocated + -= ep->load / ep->period; + if (ep == sl811->next_periodic) + sl811->next_periodic = ep->next; + + /* we might turn SOFs back on again for the async schedule */ + if (sl811->periodic_count == 0) + sofirq_off(sl811); +} + +static void +done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs) +{ + u8 status; + struct sl811h_req *req; + struct urb *urb; + int urbstat = -EINPROGRESS; + + if (unlikely(!ep)) + return; + + status = sl811_read(sl811, bank + SL11H_PKTSTATREG); + + req = container_of(ep->queue.next, struct sl811h_req, queue); + urb = req->urb; + + /* we can safely ignore NAKs */ + if (status & SL11H_STATMASK_NAK) { + // PACKET("...NAK_%02x qh%p\n", bank, ep); + if (!ep->period) + ep->nak_count++; + ep->error_count = 0; + + /* ACK advances transfer, toggle, and maybe queue */ + } else if (status & SL11H_STATMASK_ACK) { + struct usb_device *udev = urb->dev; + int len; + unsigned char *buf; + + /* urb->iso_frame_desc is currently ignored here... */ + + ep->nak_count = ep->error_count = 0; + switch (ep->nextpid) { + case USB_PID_OUT: + // PACKET("...ACK/out_%02x qh%p\n", bank, ep); + urb->actual_length += ep->length; + usb_dotoggle(udev, ep->epnum, 1); + if (urb->actual_length + == urb->transfer_buffer_length) { + if (usb_pipecontrol(urb->pipe)) + ep->nextpid = USB_PID_ACK; + + /* some bulk protocols terminate OUT transfers + * by a short packet, using ZLPs not padding. + */ + else if (ep->length < ep->maxpacket + || !(urb->transfer_flags + & URB_ZERO_PACKET)) + urbstat = 0; + } + break; + case USB_PID_IN: + // PACKET("...ACK/in_%02x qh%p\n", bank, ep); + buf = urb->transfer_buffer + urb->actual_length; + prefetchw(buf); + len = ep->maxpacket - sl811_read(sl811, + bank + SL11H_XFERCNTREG); + if (len > ep->length) { + len = ep->length; + urb->status = -EOVERFLOW; + } + urb->actual_length += len; + sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), + buf, len); + usb_dotoggle(udev, ep->epnum, 0); + if (urb->actual_length == urb->transfer_buffer_length) + urbstat = 0; + else if (len < ep->maxpacket) { + if (urb->transfer_flags & URB_SHORT_NOT_OK) + urbstat = -EREMOTEIO; + else + urbstat = 0; + } + if (usb_pipecontrol(urb->pipe) + && (urbstat == -EREMOTEIO + || urbstat == 0)) { + + /* NOTE if the status stage STALLs (why?), + * this reports the wrong urb status. + */ + spin_lock(&urb->lock); + if (urb->status == -EINPROGRESS) + urb->status = urbstat; + spin_unlock(&urb->lock); + + req = NULL; + ep->nextpid = USB_PID_ACK; + } + break; + case USB_PID_SETUP: + // PACKET("...ACK/setup_%02x qh%p\n", bank, ep); + if (urb->transfer_buffer_length == urb->actual_length) + ep->nextpid = USB_PID_ACK; + else if (usb_pipeout(urb->pipe)) { + usb_settoggle(udev, 0, 1, 1); + ep->nextpid = USB_PID_OUT; + } else { + usb_settoggle(udev, 0, 0, 1); + ep->nextpid = USB_PID_IN; + } + break; + case USB_PID_ACK: + // PACKET("...ACK/status_%02x qh%p\n", bank, ep); + urbstat = 0; + break; + } + + /* STALL stops all transfers */ + } else if (status & SL11H_STATMASK_STALL) { + PACKET("...STALL_%02x qh%p\n", bank, ep); + ep->nak_count = ep->error_count = 0; + urbstat = -EPIPE; + + /* error? retry, until "3 strikes" */ + } else if (++ep->error_count >= 3) { + if (status & SL11H_STATMASK_TMOUT) + urbstat = -ETIMEDOUT; + else if (status & SL11H_STATMASK_OVF) + urbstat = -EOVERFLOW; + else + urbstat = -EPROTO; + ep->error_count = 0; + PACKET("...3STRIKES_%02x %02x qh%p stat %d\n", + bank, status, ep, urbstat); + } + + if ((urbstat != -EINPROGRESS || urb->status != -EINPROGRESS) + && req) + finish_request(sl811, ep, req, regs, urbstat); +} + +static inline u8 checkdone(struct sl811 *sl811) +{ + u8 ctl; + u8 irqstat = 0; + + if (sl811->active_a && time_before_eq(sl811->jiffies_a, jiffies)) { + ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)); + if (ctl & SL11H_HCTLMASK_ARM) + sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); + DBG("%s DONE_A: ctrl %02x sts %02x\n", + (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", + ctl, + sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG))); + irqstat |= SL11H_INTMASK_DONE_A; + } +#ifdef USE_B + if (sl811->active_b && time_before_eq(sl811->jiffies_b, jiffies)) { + ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)); + if (ctl & SL11H_HCTLMASK_ARM) + sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); + DBG("%s DONE_B: ctrl %02x sts %02x\n", ctl, + (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", + ctl, + sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG))); + irqstat |= SL11H_INTMASK_DONE_A; + } +#endif + return irqstat; +} + +static irqreturn_t sl811h_irq(int irq, void *_sl811, struct pt_regs *regs) +{ + struct sl811 *sl811 = _sl811; + u8 irqstat; + irqreturn_t ret = IRQ_NONE; + unsigned retries = 5; + + spin_lock(&sl811->lock); + +retry: + irqstat = sl811_read(sl811, SL11H_IRQ_STATUS) & ~SL11H_INTMASK_DP; + if (irqstat) { + sl811_write(sl811, SL11H_IRQ_STATUS, irqstat); + irqstat &= sl811->irq_enable; + } + +#ifdef QUIRK2 + /* this may no longer be necessary ... */ + if (irqstat == 0 && ret == IRQ_NONE) { + irqstat = checkdone(sl811); + if (irqstat && irq != ~0) + sl811->stat_lost++; + } +#endif + + /* USB packets, not necessarily handled in the order they're + * issued ... that's fine if they're different endpoints. + */ + if (irqstat & SL11H_INTMASK_DONE_A) { + done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF), regs); + sl811->active_a = NULL; + sl811->stat_a++; + } +#ifdef USE_B + if (irqstat & SL11H_INTMASK_DONE_B) { + done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF), regs); + sl811->active_b = NULL; + sl811->stat_b++; + } +#endif + if (irqstat & SL11H_INTMASK_SOFINTR) { + unsigned index; + + index = sl811->frame++ % (PERIODIC_SIZE - 1); + sl811->stat_sof++; + + /* be graceful about almost-inevitable periodic schedule + * overruns: continue the previous frame's transfers iff + * this one has nothing scheduled. + */ + if (sl811->next_periodic) { + // ERR("overrun to slot %d\n", index); + sl811->stat_overrun++; + } + if (sl811->periodic[index]) + sl811->next_periodic = sl811->periodic[index]; + } + + /* khubd manages debouncing and wakeup */ + if (irqstat & SL11H_INTMASK_INSRMV) { + sl811->stat_insrmv++; + + /* most stats are reset for each VBUS session */ + sl811->stat_wake = 0; + sl811->stat_sof = 0; + sl811->stat_a = 0; + sl811->stat_b = 0; + sl811->stat_lost = 0; + + sl811->ctrl1 = 0; + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + + sl811->irq_enable = SL11H_INTMASK_INSRMV; + sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); + + /* usbcore nukes other pending transactions on disconnect */ + if (sl811->active_a) { + sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); + finish_request(sl811, sl811->active_a, + container_of(sl811->active_a->queue.next, + struct sl811h_req, queue), + NULL, -ESHUTDOWN); + sl811->active_a = NULL; + } +#ifdef USE_B + if (sl811->active_b) { + sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); + finish_request(sl811, sl811->active_b, + container_of(sl811->active_b->queue.next, + struct sl811h_req, queue), + NULL, -ESHUTDOWN); + sl811->active_b = NULL; + } +#endif + + /* port status seems wierd until after reset, so + * force the reset and make khubd clean up later. + */ + sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION) + | (1 << USB_PORT_FEAT_CONNECTION); + + } else if (irqstat & SL11H_INTMASK_RD) { + if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) { + DBG("wakeup\n"); + sl811->port1 |= 1 << USB_PORT_FEAT_C_SUSPEND; + sl811->stat_wake++; + } else + irqstat &= ~SL11H_INTMASK_RD; + } + + if (irqstat) { + if (sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)) + start_transfer(sl811); + ret = IRQ_HANDLED; + sl811->hcd.saw_irq = 1; + if (retries--) + goto retry; + } + + if (sl811->periodic_count == 0 && list_empty(&sl811->async)) + sofirq_off(sl811); + sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); + + spin_unlock(&sl811->lock); + + return ret; +} + +/*-------------------------------------------------------------------------*/ + +/* usb 1.1 says max 90% of a frame is available for periodic transfers. + * this driver doesn't promise that much since it's got to handle an + * IRQ per packet; irq handling latencies also use up that time. + */ +#define MAX_PERIODIC_LOAD 500 /* out of 1000 usec */ + +static int balance(struct sl811 *sl811, u16 period, u16 load) +{ + int i, branch = -ENOSPC; + + /* search for the least loaded schedule branch of that period + * which has enough bandwidth left unreserved. + */ + for (i = 0; i < period ; i++) { + if (branch < 0 || sl811->load[branch] > sl811->load[i]) { + int j; + + for (j = i; j < PERIODIC_SIZE; j += period) { + if ((sl811->load[j] + load) + > MAX_PERIODIC_LOAD) + break; + } + if (j < PERIODIC_SIZE) + continue; + branch = i; + } + } + return branch; +} + +/*-------------------------------------------------------------------------*/ + +static int sl811h_urb_enqueue( + struct usb_hcd *hcd, + struct urb *urb, + int mem_flags +) { + struct sl811 *sl811 = hcd_to_sl811(hcd); + struct usb_device *udev = urb->dev; + struct hcd_dev *hdev = (struct hcd_dev *) udev->hcpriv; + unsigned int pipe = urb->pipe; + int is_out = !usb_pipein(pipe); + int type = usb_pipetype(pipe); + int epnum = usb_pipeendpoint(pipe); + struct sl811h_ep *ep = NULL; + struct sl811h_req *req; + unsigned long flags; + int i; + int retval = 0; + +#ifdef DISABLE_ISO + if (type == PIPE_ISOCHRONOUS) + return -ENOSPC; +#endif + + /* avoid all allocations within spinlocks: request or endpoint */ + urb->hcpriv = req = kmalloc(sizeof *req, mem_flags); + if (!req) + return -ENOMEM; + req->urb = urb; + + i = epnum << 1; + if (i && is_out) + i |= 1; + if (!hdev->ep[i]) + ep = kcalloc(1, sizeof *ep, mem_flags); + + spin_lock_irqsave(&sl811->lock, flags); + + /* don't submit to a dead or disabled port */ + if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)) + || !HCD_IS_RUNNING(sl811->hcd.state)) { + retval = -ENODEV; + goto fail; + } + + if (hdev->ep[i]) { + kfree(ep); + ep = hdev->ep[i]; + } else if (!ep) { + retval = -ENOMEM; + goto fail; + + } else { + INIT_LIST_HEAD(&ep->queue); + INIT_LIST_HEAD(&ep->schedule); + ep->udev = usb_get_dev(udev); + ep->epnum = epnum; + ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); + ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE; + usb_settoggle(udev, epnum, is_out, 0); + + if (type == PIPE_CONTROL) + ep->nextpid = USB_PID_SETUP; + else if (is_out) + ep->nextpid = USB_PID_OUT; + else + ep->nextpid = USB_PID_IN; + + if (ep->maxpacket > H_MAXPACKET) { + /* iso packets up to 240 bytes could work... */ + DBG("dev %d ep%d maxpacket %d\n", + udev->devnum, epnum, ep->maxpacket); + retval = -EINVAL; + goto fail; + } + + if (udev->speed == USB_SPEED_LOW) { + /* send preamble for external hub? */ + if (!(sl811->ctrl1 & SL11H_CTL1MASK_LSPD)) + ep->defctrl |= SL11H_HCTLMASK_PREAMBLE; + } + switch (type) { + case PIPE_ISOCHRONOUS: + case PIPE_INTERRUPT: + if (urb->interval > PERIODIC_SIZE) + urb->interval = PERIODIC_SIZE; + ep->period = urb->interval; + ep->branch = PERIODIC_SIZE; + if (type == PIPE_ISOCHRONOUS) + ep->defctrl |= SL11H_HCTLMASK_ISOCH; + ep->load = usb_calc_bus_time(udev->speed, !is_out, + (type == PIPE_ISOCHRONOUS), + usb_maxpacket(udev, pipe, is_out)) + / 1000; + break; + } + + hdev->ep[i] = ep; + } + + /* maybe put endpoint into schedule */ + switch (type) { + case PIPE_CONTROL: + case PIPE_BULK: + if (list_empty(&ep->schedule)) + list_add_tail(&ep->schedule, &sl811->async); + break; + case PIPE_ISOCHRONOUS: + case PIPE_INTERRUPT: + urb->interval = ep->period; + if (ep->branch < PERIODIC_SIZE) + break; + + retval = balance(sl811, ep->period, ep->load); + if (retval < 0) + goto fail; + ep->branch = retval; + retval = 0; + urb->start_frame = (sl811->frame & (PERIODIC_SIZE - 1)) + + ep->branch; + + /* sort each schedule branch by period (slow before fast) + * to share the faster parts of the tree without needing + * dummy/placeholder nodes + */ + DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); + for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { + struct sl811h_ep **prev = &sl811->periodic[i]; + struct sl811h_ep *here = *prev; + + while (here && ep != here) { + if (ep->period > here->period) + break; + prev = &here->next; + here = *prev; + } + if (ep != here) { + ep->next = here; + *prev = ep; + } + sl811->load[i] += ep->load; + } + sl811->periodic_count++; + hcd_to_bus(&sl811->hcd)->bandwidth_allocated + += ep->load / ep->period; + sofirq_on(sl811); + } + + /* in case of unlink-during-submit */ + spin_lock(&urb->lock); + if (urb->status != -EINPROGRESS) { + spin_unlock(&urb->lock); + finish_request(sl811, ep, req, NULL, 0); + req = NULL; + retval = 0; + goto fail; + } + list_add_tail(&req->queue, &ep->queue); + spin_unlock(&urb->lock); + + start_transfer(sl811); + sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); +fail: + spin_unlock_irqrestore(&sl811->lock, flags); + if (retval) + kfree(req); + return retval; +} + +static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) +{ + struct sl811 *sl811 = hcd_to_sl811(hcd); + struct usb_device *udev = urb->dev; + struct hcd_dev *hdev = (struct hcd_dev *) udev->hcpriv; + unsigned int pipe = urb->pipe; + int is_out = !usb_pipein(pipe); + unsigned long flags; + unsigned i; + struct sl811h_ep *ep; + struct sl811h_req *req = urb->hcpriv; + int retval = 0; + + i = usb_pipeendpoint(pipe) << 1; + if (i && is_out) + i |= 1; + + spin_lock_irqsave(&sl811->lock, flags); + ep = hdev->ep[i]; + if (ep) { + /* finish right away if this urb can't be active ... + * note that some drivers wrongly expect delays + */ + if (ep->queue.next != &req->queue) { + /* not front of queue? never active */ + + /* for active transfers, we expect an IRQ */ + } else if (sl811->active_a == ep) { + if (time_before_eq(sl811->jiffies_a, jiffies)) { + /* happens a lot with lowspeed?? */ + DBG("giveup on DONE_A: ctrl %02x sts %02x\n", + sl811_read(sl811, + SL811_EP_A(SL11H_HOSTCTLREG)), + sl811_read(sl811, + SL811_EP_A(SL11H_PKTSTATREG))); + sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), + 0); + sl811->active_a = NULL; + } else + req = NULL; +#ifdef USE_B + } else if (sl811->active_b == ep) { + if (time_before_eq(sl811->jiffies_a, jiffies)) { + /* happens a lot with lowspeed?? */ + DBG("giveup on DONE_B: ctrl %02x sts %02x\n", + sl811_read(sl811, + SL811_EP_B(SL11H_HOSTCTLREG)), + sl811_read(sl811, + SL811_EP_B(SL11H_PKTSTATREG))); + sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), + 0); + sl811->active_b = NULL; + } else + req = NULL; +#endif + } else { + /* front of queue for inactive endpoint */ + } + + if (req) + finish_request(sl811, ep, req, NULL, 0); + else + VDBG("dequeue, urb %p active %s; wait4irq\n", urb, + (sl811->active_a == ep) ? "A" : "B"); + } else + retval = -EINVAL; + spin_unlock_irqrestore(&sl811->lock, flags); + return retval; +} + +static void +sl811h_endpoint_disable(struct usb_hcd *hcd, struct hcd_dev *hdev, int epnum) +{ + struct sl811 *sl811 = hcd_to_sl811(hcd); + struct sl811h_ep *ep; + unsigned long flags; + int i; + + i = (epnum & 0xf) << 1; + if (epnum && !(epnum & USB_DIR_IN)) + i |= 1; + + spin_lock_irqsave(&sl811->lock, flags); + ep = hdev->ep[i]; + hdev->ep[i] = NULL; + spin_unlock_irqrestore(&sl811->lock, flags); + + if (ep) { + /* assume we'd just wait for the irq */ + if (!list_empty(&ep->queue)) + msleep(3); + if (!list_empty(&ep->queue)) + WARN("ep %p not empty?\n", ep); + + usb_put_dev(ep->udev); + kfree(ep); + } + return; +} + +static int +sl811h_get_frame(struct usb_hcd *hcd) +{ + struct sl811 *sl811 = hcd_to_sl811(hcd); + + /* wrong except while periodic transfers are scheduled; + * never matches the on-the-wire frame; + * subject to overruns. + */ + return sl811->frame; +} + + +/*-------------------------------------------------------------------------*/ + +/* the virtual root hub timer IRQ checks for hub status */ +static int +sl811h_hub_status_data(struct usb_hcd *hcd, char *buf) +{ + struct sl811 *sl811 = hcd_to_sl811(hcd); +#ifdef QUIRK3 + unsigned long flags; + + /* non-SMP HACK: use root hub timer as i/o watchdog + * this seems essential when SOF IRQs aren't in use... + */ + local_irq_save(flags); + if (!timer_pending(&sl811->timer)) { + if (sl811h_irq(~0, sl811, NULL) != IRQ_NONE) + sl811->stat_lost++; + } + local_irq_restore(flags); +#endif + + if (!(sl811->port1 & (0xffff << 16))) + return 0; + + /* tell khubd port 1 changed */ + *buf = (1 << 1); + return 1; +} + +static void +sl811h_hub_descriptor ( + struct sl811 *sl811, + struct usb_hub_descriptor *desc +) { + u16 temp = 0; + + desc->bDescriptorType = 0x29; + desc->bHubContrCurrent = 0; + + desc->bNbrPorts = 1; + desc->bDescLength = 9; + + /* per-port power switching (gang of one!), or none */ + desc->bPwrOn2PwrGood = 0; + if (sl811->board && sl811->board->port_power) { + desc->bPwrOn2PwrGood = sl811->board->potpg; + if (!desc->bPwrOn2PwrGood) + desc->bPwrOn2PwrGood = 10; + temp = 0x0001; + } else + temp = 0x0002; + + /* no overcurrent errors detection/handling */ + temp |= 0x0010; + + desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp); + + /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ + desc->bitmap[0] = 1 << 1; + desc->bitmap[1] = ~0; +} + +static void +sl811h_timer(unsigned long _sl811) +{ + struct sl811 *sl811 = (void *) _sl811; + unsigned long flags; + u8 irqstat; + u8 signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE; + const u32 mask = (1 << USB_PORT_FEAT_CONNECTION) + | (1 << USB_PORT_FEAT_ENABLE) + | (1 << USB_PORT_FEAT_LOWSPEED); + + spin_lock_irqsave(&sl811->lock, flags); + + /* stop special signaling */ + sl811->ctrl1 &= ~SL11H_CTL1MASK_FORCE; + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + udelay(3); + + irqstat = sl811_read(sl811, SL11H_IRQ_STATUS); + + switch (signaling) { + case SL11H_CTL1MASK_SE0: + DBG("end reset\n"); + sl811->port1 = (1 << USB_PORT_FEAT_C_RESET) + | (1 << USB_PORT_FEAT_POWER); + sl811->ctrl1 = 0; + /* don't wrongly ack RD */ + if (irqstat & SL11H_INTMASK_INSRMV) + irqstat &= ~SL11H_INTMASK_RD; + break; + case SL11H_CTL1MASK_K: + DBG("end resume\n"); + sl811->port1 &= ~(1 << USB_PORT_FEAT_SUSPEND); + break; + default: + DBG("odd timer signaling: %02x\n", signaling); + break; + } + sl811_write(sl811, SL11H_IRQ_STATUS, irqstat); + + if (irqstat & SL11H_INTMASK_RD) { + /* usbcore nukes all pending transactions on disconnect */ + if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION)) + sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION) + | (1 << USB_PORT_FEAT_C_ENABLE); + sl811->port1 &= ~mask; + sl811->irq_enable = SL11H_INTMASK_INSRMV; + } else { + sl811->port1 |= mask; + if (irqstat & SL11H_INTMASK_DP) + sl811->port1 &= ~(1 << USB_PORT_FEAT_LOWSPEED); + sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD; + } + + if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION)) { + u8 ctrl2 = SL811HS_CTL2_INIT; + + sl811->irq_enable |= SL11H_INTMASK_DONE_A; +#ifdef USE_B + sl811->irq_enable |= SL11H_INTMASK_DONE_B; +#endif + if (sl811->port1 & (1 << USB_PORT_FEAT_LOWSPEED)) { + sl811->ctrl1 |= SL11H_CTL1MASK_LSPD; + ctrl2 |= SL811HS_CTL2MASK_DSWAP; + } + + /* start SOFs flowing, kickstarting with A registers */ + sl811->ctrl1 |= SL11H_CTL1MASK_SOF_ENA; + sl811_write(sl811, SL11H_SOFLOWREG, 0xe0); + sl811_write(sl811, SL811HS_CTLREG2, ctrl2); + + /* autoincrementing */ + sl811_write(sl811, SL811_EP_A(SL11H_BUFLNTHREG), 0); + writeb(SL_SOF, sl811->data_reg); + writeb(0, sl811->data_reg); + sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), + SL11H_HCTLMASK_ARM); + + /* khubd provides debounce delay */ + } else { + sl811->ctrl1 = 0; + } + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + + /* reenable irqs */ + sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); + spin_unlock_irqrestore(&sl811->lock, flags); +} + +static int +sl811h_hub_control( + struct usb_hcd *hcd, + u16 typeReq, + u16 wValue, + u16 wIndex, + char *buf, + u16 wLength +) { + struct sl811 *sl811 = hcd_to_sl811(hcd); + int retval = 0; + unsigned long flags; + + spin_lock_irqsave(&sl811->lock, flags); + + switch (typeReq) { + case ClearHubFeature: + case SetHubFeature: + switch (wValue) { + case C_HUB_OVER_CURRENT: + case C_HUB_LOCAL_POWER: + break; + default: + goto error; + } + break; + case ClearPortFeature: + if (wIndex != 1 || wLength != 0) + goto error; + + switch (wValue) { + case USB_PORT_FEAT_ENABLE: + sl811->port1 &= (1 << USB_PORT_FEAT_POWER); + sl811->ctrl1 = 0; + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + sl811->irq_enable = SL11H_INTMASK_INSRMV; + sl811_write(sl811, SL11H_IRQ_ENABLE, + sl811->irq_enable); + break; + case USB_PORT_FEAT_SUSPEND: + if (!(sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))) + break; + + /* 20 msec of resume/K signaling, other irqs blocked */ + DBG("start resume...\n"); + sl811->irq_enable = 0; + sl811_write(sl811, SL11H_IRQ_ENABLE, + sl811->irq_enable); + sl811->ctrl1 |= SL11H_CTL1MASK_K; + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + + mod_timer(&sl811->timer, jiffies + + msecs_to_jiffies(20)); + break; + case USB_PORT_FEAT_POWER: + port_power(sl811, 0); + break; + case USB_PORT_FEAT_C_ENABLE: + case USB_PORT_FEAT_C_SUSPEND: + case USB_PORT_FEAT_C_CONNECTION: + case USB_PORT_FEAT_C_OVER_CURRENT: + case USB_PORT_FEAT_C_RESET: + break; + default: + goto error; + } + sl811->port1 &= ~(1 << wValue); + break; + case GetHubDescriptor: + sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf); + break; + case GetHubStatus: + *(__le32 *) buf = cpu_to_le32(0); + break; + case GetPortStatus: + if (wIndex != 1) + goto error; + *(__le32 *) buf = cpu_to_le32(sl811->port1); + +#ifndef VERBOSE + if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ +#endif + DBG("GetPortStatus %08x\n", sl811->port1); + break; + case SetPortFeature: + if (wIndex != 1 || wLength != 0) + goto error; + switch (wValue) { + case USB_PORT_FEAT_SUSPEND: + if (sl811->port1 & (1 << USB_PORT_FEAT_RESET)) + goto error; + if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))) + goto error; + + DBG("suspend...\n"); + sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA; + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + break; + case USB_PORT_FEAT_POWER: + port_power(sl811, 1); + break; + case USB_PORT_FEAT_RESET: + if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) + goto error; + if (!(sl811->port1 & (1 << USB_PORT_FEAT_POWER))) + break; + + /* 50 msec of reset/SE0 signaling, irqs blocked */ + sl811->irq_enable = 0; + sl811_write(sl811, SL11H_IRQ_ENABLE, + sl811->irq_enable); + sl811->ctrl1 = SL11H_CTL1MASK_SE0; + sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); + sl811->port1 |= (1 << USB_PORT_FEAT_RESET); + mod_timer(&sl811->timer, jiffies + + msecs_to_jiffies(50)); + break; + default: + goto error; + } + sl811->port1 |= 1 << wValue; + break; + + default: +error: + /* "protocol stall" on error */ + retval = -EPIPE; + } + + spin_unlock_irqrestore(&sl811->lock, flags); + return retval; +} + +#ifdef CONFIG_PM + +static int +sl811h_hub_suspend(struct usb_hcd *hcd) +{ + // SOFs off + DBG("%s\n", __FUNCTION__); + return 0; +} + +static int +sl811h_hub_resume(struct usb_hcd *hcd) +{ + // SOFs on + DBG("%s\n", __FUNCTION__); + return 0; +} + +#else + +#define sl811h_hub_suspend NULL +#define sl811h_hub_resume NULL + +#endif + + +/*-------------------------------------------------------------------------*/ + +#ifdef STUB_DEBUG_FILE + +static inline void create_debug_file(struct sl811 *sl811) { } +static inline void remove_debug_file(struct sl811 *sl811) { } + +#else + +#include +#include + +static void dump_irq(struct seq_file *s, char *label, u8 mask) +{ + seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask, + (mask & SL11H_INTMASK_DONE_A) ? " done_a" : "", + (mask & SL11H_INTMASK_DONE_B) ? " done_b" : "", + (mask & SL11H_INTMASK_SOFINTR) ? " sof" : "", + (mask & SL11H_INTMASK_INSRMV) ? " ins/rmv" : "", + (mask & SL11H_INTMASK_RD) ? " rd" : "", + (mask & SL11H_INTMASK_DP) ? " dp" : ""); +} + +static int proc_sl811h_show(struct seq_file *s, void *unused) +{ + struct sl811 *sl811 = s->private; + struct sl811h_ep *ep; + unsigned i; + + seq_printf(s, "%s\n%s version %s\nportstatus[1] = %08x\n", + sl811->hcd.product_desc, + hcd_name, DRIVER_VERSION, + sl811->port1); + + seq_printf(s, "insert/remove: %ld\n", sl811->stat_insrmv); + seq_printf(s, "current session: done_a %ld done_b %ld " + "wake %ld sof %ld overrun %ld lost %ld\n\n", + sl811->stat_a, sl811->stat_b, + sl811->stat_wake, sl811->stat_sof, + sl811->stat_overrun, sl811->stat_lost); + + spin_lock_irq(&sl811->lock); + + if (sl811->ctrl1 & SL11H_CTL1MASK_SUSPEND) + seq_printf(s, "(suspended)\n\n"); + else { + u8 t = sl811_read(sl811, SL11H_CTLREG1); + + seq_printf(s, "ctrl1 %02x%s%s%s%s\n", t, + (t & SL11H_CTL1MASK_SOF_ENA) ? " sofgen" : "", + ({char *s; switch (t & SL11H_CTL1MASK_FORCE) { + case SL11H_CTL1MASK_NORMAL: s = ""; break; + case SL11H_CTL1MASK_SE0: s = " se0/reset"; break; + case SL11H_CTL1MASK_K: s = " k/resume"; break; + default: s = "j"; break; + }; s; }), + (t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "", + (t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : ""); + + dump_irq(s, "irq_enable", + sl811_read(sl811, SL11H_IRQ_ENABLE)); + dump_irq(s, "irq_status", + sl811_read(sl811, SL11H_IRQ_STATUS)); + seq_printf(s, "frame clocks remaining: %d\n", + sl811_read(sl811, SL11H_SOFTMRREG) << 6); + } + + seq_printf(s, "A: qh%p ctl %02x sts %02x\n", sl811->active_a, + sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)), + sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG))); + seq_printf(s, "B: qh%p ctl %02x sts %02x\n", sl811->active_b, + sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)), + sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG))); + seq_printf(s, "\n"); + list_for_each_entry (ep, &sl811->async, schedule) { + struct sl811h_req *req; + + seq_printf(s, "%s%sqh%p, ep%d%s, maxpacket %d" + " nak %d err %d\n", + (ep == sl811->active_a) ? "(A) " : "", + (ep == sl811->active_b) ? "(B) " : "", + ep, ep->epnum, + ({ char *s; switch (ep->nextpid) { + case USB_PID_IN: s = "in"; break; + case USB_PID_OUT: s = "out"; break; + case USB_PID_SETUP: s = "setup"; break; + case USB_PID_ACK: s = "status"; break; + default: s = "?"; break; + }; s;}), + ep->maxpacket, + ep->nak_count, ep->error_count); + list_for_each_entry (req, &ep->queue, queue) { + seq_printf(s, " urb%p, %d/%d\n", req->urb, + req->urb->actual_length, + req->urb->transfer_buffer_length); + } + } + if (!list_empty(&sl811->async)) + seq_printf(s, "\n"); + + seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE); + + for (i = 0; i < PERIODIC_SIZE; i++) { + ep = sl811->periodic[i]; + if (!ep) + continue; + seq_printf(s, "%2d [%3d]:\n", i, sl811->load[i]); + + /* DUMB: prints shared entries multiple times */ + do { + seq_printf(s, + " %s%sqh%d/%p (%sdev%d ep%d%s max %d) " + "err %d\n", + (ep == sl811->active_a) ? "(A) " : "", + (ep == sl811->active_b) ? "(B) " : "", + ep->period, ep, + (ep->udev->speed == USB_SPEED_FULL) + ? "" : "ls ", + ep->udev->devnum, ep->epnum, + (ep->epnum == 0) ? "" + : ((ep->nextpid == USB_PID_IN) + ? "in" + : "out"), + ep->maxpacket, ep->error_count); + ep = ep->next; + } while (ep); + } + + spin_unlock_irq(&sl811->lock); + seq_printf(s, "\n"); + + return 0; +} + +static int proc_sl811h_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_sl811h_show, PDE(inode)->data); +} + +static struct file_operations proc_ops = { + .open = proc_sl811h_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* expect just one sl811 per system */ +static const char proc_filename[] = "driver/sl811h"; + +static void create_debug_file(struct sl811 *sl811) +{ + struct proc_dir_entry *pde; + + pde = create_proc_entry(proc_filename, 0, NULL); + if (pde == NULL) + return; + + pde->proc_fops = &proc_ops; + pde->data = sl811; + sl811->pde = pde; +} + +static void remove_debug_file(struct sl811 *sl811) +{ + if (sl811->pde) + remove_proc_entry(proc_filename, NULL); +} + +#endif + +/*-------------------------------------------------------------------------*/ + +static void +sl811h_stop(struct usb_hcd *hcd) +{ + struct sl811 *sl811 = hcd_to_sl811(hcd); + unsigned long flags; + + del_timer_sync(&sl811->hcd.rh_timer); + + spin_lock_irqsave(&sl811->lock, flags); + port_power(sl811, 0); + spin_unlock_irqrestore(&sl811->lock, flags); +} + +static int +sl811h_start(struct usb_hcd *hcd) +{ + struct sl811 *sl811 = hcd_to_sl811(hcd); + struct usb_device *udev; + + /* chip has been reset, VBUS power is off */ + + udev = usb_alloc_dev(NULL, &sl811->hcd.self, 0); + if (!udev) + return -ENOMEM; + + udev->speed = USB_SPEED_FULL; + hcd->state = USB_STATE_RUNNING; + + if (sl811->board) + sl811->hcd.can_wakeup = sl811->board->can_wakeup; + + if (hcd_register_root(udev, &sl811->hcd) != 0) { + usb_put_dev(udev); + sl811h_stop(hcd); + return -ENODEV; + } + + if (sl811->board && sl811->board->power) + hub_set_power_budget(udev, sl811->board->power * 2); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct hc_driver sl811h_hc_driver = { + .description = hcd_name, + + /* + * generic hardware linkage + */ + .flags = HCD_USB11, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = sl811h_urb_enqueue, + .urb_dequeue = sl811h_urb_dequeue, + .endpoint_disable = sl811h_endpoint_disable, + + /* + * periodic schedule support + */ + .get_frame_number = sl811h_get_frame, + + /* + * root hub support + */ + .hub_status_data = sl811h_hub_status_data, + .hub_control = sl811h_hub_control, + .hub_suspend = sl811h_hub_suspend, + .hub_resume = sl811h_hub_resume, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init_or_module +sl811h_remove(struct device *dev) +{ + struct sl811 *sl811 = dev_get_drvdata(dev); + struct platform_device *pdev; + struct resource *res; + + pdev = container_of(dev, struct platform_device, dev); + + if (HCD_IS_RUNNING(sl811->hcd.state)) + sl811->hcd.state = USB_STATE_QUIESCING; + + usb_disconnect(&sl811->hcd.self.root_hub); + remove_debug_file(sl811); + sl811h_stop(&sl811->hcd); + + if (!list_empty(&sl811->hcd.self.bus_list)) + usb_deregister_bus(&sl811->hcd.self); + + if (sl811->hcd.irq >= 0) + free_irq(sl811->hcd.irq, sl811); + + if (sl811->data_reg) + iounmap(sl811->data_reg); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + release_mem_region(res->start, 1); + + if (sl811->addr_reg) + iounmap(sl811->addr_reg); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, 1); + + kfree(sl811); + return 0; +} + +#define resource_len(r) (((r)->end - (r)->start) + 1) + +static int __init +sl811h_probe(struct device *dev) +{ + struct sl811 *sl811; + struct platform_device *pdev; + struct resource *addr, *data; + int irq; + int status; + u8 tmp; + unsigned long flags; + + /* basic sanity checks first. board-specific init logic should + * have initialized these three resources and probably board + * specific platform_data. we don't probe for IRQs, and do only + * minimal sanity checking. + */ + pdev = container_of(dev, struct platform_device, dev); + if (pdev->num_resources < 3) + return -ENODEV; + + addr = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data = platform_get_resource(pdev, IORESOURCE_MEM, 1); + irq = platform_get_irq(pdev, 0); + if (!addr || !data || irq < 0) + return -ENODEV; + + /* refuse to confuse usbcore */ + if (dev->dma_mask) { + DBG("no we won't dma\n"); + return -EINVAL; + } + + if (!request_mem_region(addr->start, 1, hcd_name)) + return -EBUSY; + if (!request_mem_region(data->start, 1, hcd_name)) { + release_mem_region(addr->start, 1); + return -EBUSY; + } + + /* allocate and initialize hcd */ + sl811 = kcalloc(1, sizeof *sl811, GFP_KERNEL); + if (!sl811) + return 0; + dev_set_drvdata(dev, sl811); + + usb_bus_init(&sl811->hcd.self); + sl811->hcd.self.controller = dev; + sl811->hcd.self.bus_name = dev->bus_id; + sl811->hcd.self.op = &usb_hcd_operations; + sl811->hcd.self.hcpriv = sl811; + + // NOTE: 2.6.11 starts to change the hcd glue layer some more, + // eventually letting us eliminate struct sl811h_req and a + // lot of the boilerplate code here + + INIT_LIST_HEAD(&sl811->hcd.dev_list); + sl811->hcd.self.release = &usb_hcd_release; + + sl811->hcd.description = sl811h_hc_driver.description; + init_timer(&sl811->hcd.rh_timer); + sl811->hcd.driver = &sl811h_hc_driver; + sl811->hcd.irq = -1; + sl811->hcd.state = USB_STATE_HALT; + + spin_lock_init(&sl811->lock); + INIT_LIST_HEAD(&sl811->async); + sl811->board = dev->platform_data; + init_timer(&sl811->timer); + sl811->timer.function = sl811h_timer; + sl811->timer.data = (unsigned long) sl811; + + sl811->addr_reg = ioremap(addr->start, resource_len(addr)); + if (sl811->addr_reg == NULL) { + status = -ENOMEM; + goto fail; + } + sl811->data_reg = ioremap(data->start, resource_len(addr)); + if (sl811->data_reg == NULL) { + status = -ENOMEM; + goto fail; + } + + spin_lock_irqsave(&sl811->lock, flags); + port_power(sl811, 0); + spin_unlock_irqrestore(&sl811->lock, flags); + msleep(200); + + tmp = sl811_read(sl811, SL11H_HWREVREG); + switch (tmp >> 4) { + case 1: + sl811->hcd.product_desc = "SL811HS v1.2"; + break; + case 2: + sl811->hcd.product_desc = "SL811HS v1.5"; + break; + default: + /* reject case 0, SL11S is less functional */ + DBG("chiprev %02x\n", tmp); + status = -ENXIO; + goto fail; + } + + /* sl811s would need a different handler for this irq */ +#ifdef CONFIG_ARM + /* Cypress docs say the IRQ is IRQT_HIGH ... */ + set_irq_type(irq, IRQT_RISING); +#endif + status = request_irq(irq, sl811h_irq, SA_INTERRUPT, hcd_name, sl811); + if (status < 0) + goto fail; + sl811->hcd.irq = irq; + + INFO("%s, irq %d\n", sl811->hcd.product_desc, irq); + + status = usb_register_bus(&sl811->hcd.self); + if (status < 0) + goto fail; + status = sl811h_start(&sl811->hcd); + if (status == 0) { + create_debug_file(sl811); + return 0; + } +fail: + sl811h_remove(dev); + DBG("init error, %d\n", status); + return status; +} + +#ifdef CONFIG_PM + +/* for this device there's no useful distinction between the controller + * and its root hub, except that the root hub only gets direct PM calls + * when CONFIG_USB_SUSPEND is enabled. + */ + +static int +sl811h_suspend(struct device *dev, u32 state, u32 phase) +{ + struct sl811 *sl811 = dev_get_drvdata(dev); + int retval = 0; + + if (phase != SUSPEND_POWER_DOWN) + return retval; + + if (state <= PM_SUSPEND_MEM) + retval = sl811h_hub_suspend(&sl811->hcd); + else + port_power(sl811, 0); + if (retval == 0) + dev->power.power_state = state; + return retval; +} + +static int +sl811h_resume(struct device *dev, u32 phase) +{ + struct sl811 *sl811 = dev_get_drvdata(dev); + + if (phase != RESUME_POWER_ON) + return 0; + + /* with no "check to see if VBUS is still powered" board hook, + * let's assume it'd only be powered to enable remote wakeup. + */ + if (dev->power.power_state > PM_SUSPEND_MEM + || !sl811->hcd.can_wakeup) { + sl811->port1 = 0; + port_power(sl811, 1); + return 0; + } + + dev->power.power_state = PM_SUSPEND_ON; + return sl811h_hub_resume(&sl811->hcd); +} + +#else + +#define sl811h_suspend NULL +#define sl811h_resume NULL + +#endif + + +static struct device_driver sl811h_driver = { + .name = (char *) hcd_name, + .bus = &platform_bus_type, + + .probe = sl811h_probe, + .remove = sl811h_remove, + + .suspend = sl811h_suspend, + .resume = sl811h_resume, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init sl811h_init(void) +{ + if (usb_disabled()) + return -ENODEV; + + INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION); + return driver_register(&sl811h_driver); +} +module_init(sl811h_init); + +static void __exit sl811h_cleanup(void) +{ + driver_unregister(&sl811h_driver); +} +module_exit(sl811h_cleanup); diff -Nru a/drivers/usb/host/sl811.h b/drivers/usb/host/sl811.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/host/sl811.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,270 @@ +/* + * SL811HS register declarations and HCD data structures + * + * Copyright (C) 2004 Psion Teklogix + * Copyright (C) 2004 David Brownell + * Copyright (C) 2001 Cypress Semiconductor Inc. + */ + +/* + * SL811HS has transfer registers, and control registers. In host/master + * mode one set of registers is used; in peripheral/slave mode, another. + * - SL11H only has some "A" transfer registers from 0x00-0x04 + * - SL811HS also has "B" registers from 0x08-0x0c + * - SL811S (or HS in slave mode) has four A+B sets, at 00, 10, 20, 30 + */ + +#define SL811_EP_A(base) ((base) + 0) +#define SL811_EP_B(base) ((base) + 8) + +#define SL811_HOST_BUF 0x00 +#define SL811_PERIPH_EP0 0x00 +#define SL811_PERIPH_EP1 0x10 +#define SL811_PERIPH_EP2 0x20 +#define SL811_PERIPH_EP3 0x30 + + +/* TRANSFER REGISTERS: host and peripheral sides are similar + * except for the control models (master vs slave). + */ +#define SL11H_HOSTCTLREG 0 +# define SL11H_HCTLMASK_ARM 0x01 +# define SL11H_HCTLMASK_ENABLE 0x02 +# define SL11H_HCTLMASK_IN 0x00 +# define SL11H_HCTLMASK_OUT 0x04 +# define SL11H_HCTLMASK_ISOCH 0x10 +# define SL11H_HCTLMASK_AFTERSOF 0x20 +# define SL11H_HCTLMASK_TOGGLE 0x40 +# define SL11H_HCTLMASK_PREAMBLE 0x80 +#define SL11H_BUFADDRREG 1 +#define SL11H_BUFLNTHREG 2 +#define SL11H_PKTSTATREG 3 /* read */ +# define SL11H_STATMASK_ACK 0x01 +# define SL11H_STATMASK_ERROR 0x02 +# define SL11H_STATMASK_TMOUT 0x04 +# define SL11H_STATMASK_SEQ 0x08 +# define SL11H_STATMASK_SETUP 0x10 +# define SL11H_STATMASK_OVF 0x20 +# define SL11H_STATMASK_NAK 0x40 +# define SL11H_STATMASK_STALL 0x80 +#define SL11H_PIDEPREG 3 /* write */ +# define SL_SETUP 0xd0 +# define SL_IN 0x90 +# define SL_OUT 0x10 +# define SL_SOF 0x50 +# define SL_PREAMBLE 0xc0 +# define SL_NAK 0xa0 +# define SL_STALL 0xe0 +# define SL_DATA0 0x30 +# define SL_DATA1 0xb0 +#define SL11H_XFERCNTREG 4 /* read */ +#define SL11H_DEVADDRREG 4 /* write */ + + +/* CONTROL REGISTERS: host and peripheral are very different. + */ +#define SL11H_CTLREG1 5 +# define SL11H_CTL1MASK_SOF_ENA 0x01 +# define SL11H_CTL1MASK_FORCE 0x18 +# define SL11H_CTL1MASK_NORMAL 0x00 +# define SL11H_CTL1MASK_SE0 0x08 /* reset */ +# define SL11H_CTL1MASK_J 0x10 +# define SL11H_CTL1MASK_K 0x18 /* resume */ +# define SL11H_CTL1MASK_LSPD 0x20 +# define SL11H_CTL1MASK_SUSPEND 0x40 +#define SL11H_IRQ_ENABLE 6 +# define SL11H_INTMASK_DONE_A 0x01 +# define SL11H_INTMASK_DONE_B 0x02 +# define SL11H_INTMASK_SOFINTR 0x10 +# define SL11H_INTMASK_INSRMV 0x20 /* to/from SE0 */ +# define SL11H_INTMASK_RD 0x40 +# define SL11H_INTMASK_DP 0x80 /* only in INTSTATREG */ +#define SL11S_ADDRESS 7 + +/* 0x08-0x0c are for the B buffer (not in SL11) */ + +#define SL11H_IRQ_STATUS 0x0D /* write to ack */ +#define SL11H_HWREVREG 0x0E /* read */ +# define SL11H_HWRMASK_HWREV 0xF0 +#define SL11H_SOFLOWREG 0x0E /* write */ +#define SL11H_SOFTMRREG 0x0F /* read */ + +/* a write to this register enables SL811HS features. + * HOST flag presumably overrides the chip input signal? + */ +#define SL811HS_CTLREG2 0x0F +# define SL811HS_CTL2MASK_SOF_MASK 0x3F +# define SL811HS_CTL2MASK_DSWAP 0x40 +# define SL811HS_CTL2MASK_HOST 0x80 + +#define SL811HS_CTL2_INIT (SL811HS_CTL2MASK_HOST | 0x2e) + + +/* DATA BUFFERS: registers from 0x10..0xff are for data buffers; + * that's 240 bytes, which we'll split evenly between A and B sides. + * Only ISO can use more than 64 bytes per packet. + * (The SL11S has 0x40..0xff for buffers.) + */ +#define H_MAXPACKET 120 /* bytes in A or B fifos */ + +#define SL11H_DATA_START 0x10 +#define SL811HS_PACKET_BUF(is_a) ((is_a) \ + ? SL11H_DATA_START \ + : (SL11H_DATA_START + H_MAXPACKET)) + +/*-------------------------------------------------------------------------*/ + +#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */ +#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE) + +struct sl811 { + struct usb_hcd hcd; + spinlock_t lock; + void __iomem *addr_reg; + void __iomem *data_reg; + struct sl811_platform_data *board; + struct proc_dir_entry *pde; + + unsigned long stat_insrmv; + unsigned long stat_wake; + unsigned long stat_sof; + unsigned long stat_a; + unsigned long stat_b; + unsigned long stat_lost; + unsigned long stat_overrun; + + /* sw model */ + struct timer_list timer; + struct sl811h_ep *next_periodic; + struct sl811h_ep *next_async; + + struct sl811h_ep *active_a; + unsigned long jiffies_a; + struct sl811h_ep *active_b; + unsigned long jiffies_b; + + u32 port1; + u8 ctrl1, ctrl2, irq_enable; + u16 frame; + + /* async schedule: control, bulk */ + struct list_head async; + + /* periodic schedule: interrupt, iso */ + u16 load[PERIODIC_SIZE]; + struct sl811h_ep *periodic[PERIODIC_SIZE]; + unsigned periodic_count; +}; + +static inline struct sl811 *hcd_to_sl811(struct usb_hcd *hcd) +{ + return container_of(hcd, struct sl811, hcd); +} + +struct sl811h_ep { + struct list_head queue; + struct usb_device *udev; + + u8 defctrl; + u8 maxpacket; + u8 epnum; + u8 nextpid; + + u16 error_count; + u16 nak_count; + u16 length; /* of current packet */ + + /* periodic schedule */ + u16 period; + u16 branch; + u16 load; + struct sl811h_ep *next; + + /* async schedule */ + struct list_head schedule; +}; + +struct sl811h_req { + /* FIXME usbcore should maintain endpoints' urb queues + * directly in 'struct usb_host_endpoint' + */ + struct urb *urb; + struct list_head queue; +}; + +/*-------------------------------------------------------------------------*/ + +/* These register utilities should work for the SL811S register API too + * NOTE: caller must hold sl811->lock. + */ + +static inline u8 sl811_read(struct sl811 *sl811, int reg) +{ + writeb(reg, sl811->addr_reg); + return readb(sl811->data_reg); +} + +static inline void sl811_write(struct sl811 *sl811, int reg, u8 val) +{ + writeb(reg, sl811->addr_reg); + writeb(val, sl811->data_reg); +} + +static inline void +sl811_write_buf(struct sl811 *sl811, int addr, const void *buf, size_t count) +{ + const u8 *data; + void __iomem *data_reg; + + if (!count) + return; + writeb(addr, sl811->addr_reg); + + data = buf; + data_reg = sl811->data_reg; + do { + writeb(*data++, data_reg); + } while (--count); +} + +static inline void +sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count) +{ + u8 *data; + void __iomem *data_reg; + + if (!count) + return; + writeb(addr, sl811->addr_reg); + + data = buf; + data_reg = sl811->data_reg; + do { + *data++ = readb(data_reg); + } while (--count); +} + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +#define DBG(stuff...) printk(KERN_DEBUG "sl811: " stuff) +#else +#define DBG(stuff...) do{}while(0) +#endif + +#ifdef VERBOSE +# define VDBG DBG +#else +# define VDBG(stuff...) do{}while(0) +#endif + +#ifdef PACKET_TRACE +# define PACKET VDBG +#else +# define PACKET(stuff...) do{}while(0) +#endif + +#define ERR(stuff...) printk(KERN_ERR "sl811: " stuff) +#define WARN(stuff...) printk(KERN_WARNING "sl811: " stuff) +#define INFO(stuff...) printk(KERN_INFO "sl811: " stuff) + diff -Nru a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c --- a/drivers/usb/host/uhci-debug.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/usb/host/uhci-debug.c 2004-12-12 17:40:52 -08:00 @@ -34,17 +34,6 @@ } } -static inline int uhci_is_skeleton_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - int i; - - for (i = 0; i < UHCI_NUM_SKELQH; i++) - if (qh == uhci->skelqh[i]) - return 1; - - return 0; -} - static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space) { char *out = buf; diff -Nru a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c --- a/drivers/usb/host/uhci-hub.c 2004-12-12 17:40:52 -08:00 +++ b/drivers/usb/host/uhci-hub.c 2004-12-12 17:40:52 -08:00 @@ -69,7 +69,7 @@ * FIXME: Synchronize access to these fields by a spinlock. */ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, - unsigned int port_addr) + unsigned long port_addr) { int status; @@ -78,13 +78,19 @@ clear_bit(port, &uhci->suspended_ports); clear_bit(port, &uhci->resuming_ports); set_bit(port, &uhci->port_c_suspend); + + /* The controller won't actually turn off the RD bit until + * it has had a chance to send a low-speed EOP sequence, + * which takes 3 bit times (= 2 microseconds). We'll delay + * slightly longer for good luck. */ + udelay(4); } } static void uhci_check_resume(struct uhci_hcd *uhci) { unsigned int port; - unsigned int port_addr; + unsigned long port_addr; for (port = 0; port < uhci->rh_numports; ++port) { port_addr = uhci->io_addr + USBPORTSC1 + 2 * port; diff -Nru a/fs/compat.c b/fs/compat.c --- a/fs/compat.c 2004-12-12 17:40:52 -08:00 +++ b/fs/compat.c 2004-12-12 17:40:52 -08:00 @@ -1387,25 +1387,25 @@ int retval; int i; - file = open_exec(filename); - - retval = PTR_ERR(file); - if (IS_ERR(file)) - return retval; - - sched_exec(); - retval = -ENOMEM; bprm = kmalloc(sizeof(*bprm), GFP_KERNEL); if (!bprm) goto out_ret; memset(bprm, 0, sizeof(*bprm)); + file = open_exec(filename); + retval = PTR_ERR(file); + if (IS_ERR(file)) + goto out_kfree; + + sched_exec(); + bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); bprm->file = file; bprm->filename = filename; bprm->interp = filename; bprm->mm = mm_alloc(); + retval = -ENOMEM; if (!bprm->mm) goto out_file; @@ -1472,6 +1472,8 @@ allow_write_access(bprm->file); fput(bprm->file); } + +out_kfree: kfree(bprm); out_ret: diff -Nru a/fs/exec.c b/fs/exec.c --- a/fs/exec.c 2004-12-12 17:40:52 -08:00 +++ b/fs/exec.c 2004-12-12 17:40:52 -08:00 @@ -1094,26 +1094,26 @@ int retval; int i; - file = open_exec(filename); - - retval = PTR_ERR(file); - if (IS_ERR(file)) - return retval; - - sched_exec(); - retval = -ENOMEM; bprm = kmalloc(sizeof(*bprm), GFP_KERNEL); if (!bprm) goto out_ret; memset(bprm, 0, sizeof(*bprm)); + file = open_exec(filename); + retval = PTR_ERR(file); + if (IS_ERR(file)) + goto out_kfree; + + sched_exec(); + bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); bprm->file = file; bprm->filename = filename; bprm->interp = filename; bprm->mm = mm_alloc(); + retval = -ENOMEM; if (!bprm->mm) goto out_file; @@ -1180,6 +1180,8 @@ allow_write_access(bprm->file); fput(bprm->file); } + +out_kfree: kfree(bprm); out_ret: diff -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c --- a/fs/ext3/dir.c 2004-12-12 17:40:52 -08:00 +++ b/fs/ext3/dir.c 2004-12-12 17:40:52 -08:00 @@ -418,7 +418,7 @@ get_dtype(sb, fname->file_type)); if (error) { filp->f_pos = curr_pos; - info->extra_fname = fname; + info->extra_fname = fname->next; return error; } fname = fname->next; @@ -457,12 +457,9 @@ * If there are any leftover names on the hash collision * chain, return them first. */ - if (info->extra_fname) { - if(call_filldir(filp, dirent, filldir, info->extra_fname)) - goto finished; - else - goto next_entry; - } + if (info->extra_fname && + call_filldir(filp, dirent, filldir, info->extra_fname)) + goto finished; if (!info->curr_node) info->curr_node = rb_first(&info->root); @@ -495,7 +492,7 @@ info->curr_minor_hash = fname->minor_hash; if (call_filldir(filp, dirent, filldir, fname)) break; -next_entry: + info->curr_node = rb_next(info->curr_node); if (!info->curr_node) { if (info->next_hash == ~0) { diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c --- a/fs/partitions/check.c 2004-12-12 17:40:53 -08:00 +++ b/fs/partitions/check.c 2004-12-12 17:40:53 -08:00 @@ -378,7 +378,7 @@ if (disk->fops->revalidate_disk) disk->fops->revalidate_disk(disk); if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) - return -EIO; + return 0; for (p = 1; p < state->limit; p++) { sector_t size = state->parts[p].size; sector_t from = state->parts[p].from; diff -Nru a/include/asm-arm/arch-sa1100/ide.h b/include/asm-arm/arch-sa1100/ide.h --- a/include/asm-arm/arch-sa1100/ide.h 2004-12-12 17:40:52 -08:00 +++ b/include/asm-arm/arch-sa1100/ide.h 2004-12-12 17:40:52 -08:00 @@ -14,6 +14,8 @@ #include #include +#error "This code is broken and needs update to match with current ide support" + /* * Set up a hw structure for a specified data port, control port and IRQ. diff -Nru a/include/asm-arm/ide.h b/include/asm-arm/ide.h --- a/include/asm-arm/ide.h 2004-12-12 17:40:52 -08:00 +++ b/include/asm-arm/ide.h 2004-12-12 17:40:52 -08:00 @@ -17,10 +17,6 @@ #define MAX_HWIFS 4 #endif -#if defined(CONFIG_ARCH_SA1100) -# include /* obsolete + broken */ -#endif - #if !defined(CONFIG_ARCH_L7200) # define IDE_ARCH_OBSOLETE_INIT # ifdef CONFIG_ARCH_CLPS7500 diff -Nru a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h --- a/include/asm-arm/uaccess.h 2004-12-12 17:40:53 -08:00 +++ b/include/asm-arm/uaccess.h 2004-12-12 17:40:53 -08:00 @@ -108,35 +108,35 @@ extern int __get_user_8(void *); extern int __get_user_bad(void); -#define __get_user_x(__r1,__p,__e,__s,__i...) \ +#define __get_user_x(__r2,__p,__e,__s,__i...) \ __asm__ __volatile__ ( \ - __asmeq("%0", "r0") __asmeq("%1", "r1") \ + __asmeq("%0", "r0") __asmeq("%1", "r2") \ "bl __get_user_" #__s \ - : "=&r" (__e), "=r" (__r1) \ + : "=&r" (__e), "=r" (__r2) \ : "0" (__p) \ : __i, "cc") #define get_user(x,p) \ ({ \ const register typeof(*(p)) __user *__p asm("r0") = (p);\ - register typeof(*(p)) __r1 asm("r1"); \ + register typeof(*(p)) __r2 asm("r2"); \ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __get_user_x(__r1, __p, __e, 1, "lr"); \ + __get_user_x(__r2, __p, __e, 1, "lr"); \ break; \ case 2: \ - __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \ + __get_user_x(__r2, __p, __e, 2, "r3", "lr"); \ break; \ case 4: \ - __get_user_x(__r1, __p, __e, 4, "lr"); \ + __get_user_x(__r2, __p, __e, 4, "lr"); \ break; \ case 8: \ - __get_user_x(__r1, __p, __e, 8, "lr"); \ + __get_user_x(__r2, __p, __e, 8, "lr"); \ break; \ default: __e = __get_user_bad(); break; \ } \ - x = __r1; \ + x = __r2; \ __e; \ }) @@ -227,31 +227,31 @@ extern int __put_user_8(void *, unsigned long long); extern int __put_user_bad(void); -#define __put_user_x(__r1,__p,__e,__s) \ +#define __put_user_x(__r2,__p,__e,__s) \ __asm__ __volatile__ ( \ - __asmeq("%0", "r0") __asmeq("%2", "r1") \ + __asmeq("%0", "r0") __asmeq("%2", "r2") \ "bl __put_user_" #__s \ : "=&r" (__e) \ - : "0" (__p), "r" (__r1) \ + : "0" (__p), "r" (__r2) \ : "ip", "lr", "cc") #define put_user(x,p) \ ({ \ - const register typeof(*(p)) __r1 asm("r1") = (x); \ + const register typeof(*(p)) __r2 asm("r2") = (x); \ const register typeof(*(p)) __user *__p asm("r0") = (p);\ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __put_user_x(__r1, __p, __e, 1); \ + __put_user_x(__r2, __p, __e, 1); \ break; \ case 2: \ - __put_user_x(__r1, __p, __e, 2); \ + __put_user_x(__r2, __p, __e, 2); \ break; \ case 4: \ - __put_user_x(__r1, __p, __e, 4); \ + __put_user_x(__r2, __p, __e, 4); \ break; \ case 8: \ - __put_user_x(__r1, __p, __e, 8); \ + __put_user_x(__r2, __p, __e, 8); \ break; \ default: __e = __put_user_bad(); break; \ } \ diff -Nru a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h --- a/include/asm-sparc/elf.h 2004-12-12 17:40:53 -08:00 +++ b/include/asm-sparc/elf.h 2004-12-12 17:40:53 -08:00 @@ -143,7 +143,7 @@ the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (0x08000000) +#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE) /* This yields a mask that user programs can use to figure out what instruction set this cpu supports. This can NOT be done in userspace diff -Nru a/include/asm-sparc/mostek.h b/include/asm-sparc/mostek.h --- a/include/asm-sparc/mostek.h 2004-12-12 17:40:53 -08:00 +++ b/include/asm-sparc/mostek.h 2004-12-12 17:40:53 -08:00 @@ -11,6 +11,7 @@ #include #include +#include /* M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ) * diff -Nru a/include/asm-sparc/processor.h b/include/asm-sparc/processor.h --- a/include/asm-sparc/processor.h 2004-12-12 17:40:53 -08:00 +++ b/include/asm-sparc/processor.h 2004-12-12 17:40:53 -08:00 @@ -43,10 +43,12 @@ struct task_struct; +#ifdef __KERNEL__ struct fpq { unsigned long *insn_addr; unsigned long insn; }; +#endif typedef struct { int seg; diff -Nru a/include/asm-sparc/sigcontext.h b/include/asm-sparc/sigcontext.h --- a/include/asm-sparc/sigcontext.h 2004-12-12 17:40:52 -08:00 +++ b/include/asm-sparc/sigcontext.h 2004-12-12 17:40:52 -08:00 @@ -4,7 +4,6 @@ #ifdef __KERNEL__ #include -#endif #ifndef __ASSEMBLY__ @@ -58,5 +57,7 @@ } __siginfo_fpu_t; #endif /* !(__ASSEMBLY__) */ + +#endif /* (__KERNEL__) */ #endif /* !(__SPARC_SIGCONTEXT_H) */ diff -Nru a/include/asm-sparc/signal.h b/include/asm-sparc/signal.h --- a/include/asm-sparc/signal.h 2004-12-12 17:40:52 -08:00 +++ b/include/asm-sparc/signal.h 2004-12-12 17:40:52 -08:00 @@ -3,6 +3,7 @@ #define _ASMSPARC_SIGNAL_H #include +#include #ifdef __KERNEL__ #ifndef __ASSEMBLY__ @@ -111,11 +112,14 @@ unsigned long sig[_NSIG_WORDS]; } __new_sigset_t; + +#ifdef __KERNEL__ /* A SunOS sigstack */ struct sigstack { char *the_stack; int cur_status; }; +#endif /* Sigvec flags */ #define _SV_SSTACK 1u /* This signal handler should use sig-stack */ @@ -189,6 +193,7 @@ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */ #define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ +#ifdef __KERNEL__ struct __new_sigaction { __sighandler_t sa_handler; unsigned long sa_flags; @@ -196,12 +201,10 @@ __new_sigset_t sa_mask; }; -#ifdef __KERNEL__ struct k_sigaction { struct __new_sigaction sa; void __user *ka_restorer; }; -#endif struct __old_sigaction { __sighandler_t sa_handler; @@ -216,7 +219,6 @@ size_t ss_size; } stack_t; -#ifdef __KERNEL__ struct sparc_deliver_cookie { int restart_syscall; unsigned long orig_i0; diff -Nru a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h --- a/include/linux/dvb/frontend.h 2004-12-12 17:40:52 -08:00 +++ b/include/linux/dvb/frontend.h 2004-12-12 17:40:52 -08:00 @@ -78,7 +78,7 @@ __u32 symbol_rate_min; __u32 symbol_rate_max; __u32 symbol_rate_tolerance; /* ppm */ - __u32 notifier_delay; /* ms */ + __u32 notifier_delay; /* DEPRECATED */ fe_caps_t caps; }; diff -Nru a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h 2004-12-12 17:40:52 -08:00 +++ b/include/linux/libata.h 2004-12-12 17:40:52 -08:00 @@ -112,6 +112,7 @@ ATA_FLAG_SRST = (1 << 5), /* use ATA SRST, not E.D.D. */ ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ + ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ diff -Nru a/include/linux/serial_core.h b/include/linux/serial_core.h --- a/include/linux/serial_core.h 2004-12-12 17:40:52 -08:00 +++ b/include/linux/serial_core.h 2004-12-12 17:40:52 -08:00 @@ -91,12 +91,15 @@ /* MPC52xx type numbers */ #define PORT_MPC52xx 59 -/*IBM icom*/ -#define PORT_ICOM 60 +/* IBM icom */ +#define PORT_ICOM 60 /* Samsung S3C2440 SoC */ #define PORT_S3C2440 61 +/* Motorola i.MX SoC */ +#define PORT_IMX 62 + #ifdef __KERNEL__ #include @@ -241,11 +244,11 @@ * within. */ struct uart_state { - unsigned int close_delay; - unsigned int closing_wait; + unsigned int close_delay; /* msec */ + unsigned int closing_wait; /* msec */ #define USF_CLOSING_WAIT_INF (0) -#define USF_CLOSING_WAIT_NONE (65535) +#define USF_CLOSING_WAIT_NONE (~0U) int count; int pm_state; diff -Nru a/include/linux/socket.h b/include/linux/socket.h --- a/include/linux/socket.h 2004-12-12 17:40:53 -08:00 +++ b/include/linux/socket.h 2004-12-12 17:40:53 -08:00 @@ -90,6 +90,10 @@ (struct cmsghdr *)(ctl) : \ (struct cmsghdr *)NULL) #define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) +#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \ + (cmsg)->cmsg_len <= (unsigned long) \ + ((mhdr)->msg_controllen - \ + ((char *)(cmsg) - (char *)(mhdr)->msg_control))) /* * This mess will go away with glibc diff -Nru a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/linux/usb_sl811.h 2004-12-12 17:40:53 -08:00 @@ -0,0 +1,26 @@ + +/* + * board initialization should put one of these into dev->platform_data + * and place the sl811hs onto platform_bus named "sl811-hcd". + */ + +struct sl811_platform_data { + unsigned can_wakeup:1; + + /* given port_power, msec/2 after power on till power good */ + u8 potpg; + + /* mA/2 power supplied on this port (max = default = 250) */ + u8 power; + + /* sl811 relies on an external source of VBUS current */ + void (*port_power)(struct device *dev, int is_on); + + /* pulse sl811 nRST (probably with a GPIO) */ + void (*reset)(struct device *dev); + + // some boards need something like these: + // int (*check_overcurrent)(struct device *dev); + // void (*clock_enable)(struct device *dev, int is_on); +}; + diff -Nru a/include/media/saa7146.h b/include/media/saa7146.h --- a/include/media/saa7146.h 2004-12-12 17:40:52 -08:00 +++ b/include/media/saa7146.h 2004-12-12 17:40:52 -08:00 @@ -168,7 +168,7 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length ); char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt); void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data); -int saa7146_wait_for_debi_done(struct saa7146_dev *dev); +int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop); /* some memory sizes */ #define SAA7146_I2C_MEM ( 1*PAGE_SIZE) diff -Nru a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h --- a/include/media/saa7146_vv.h 2004-12-12 17:40:52 -08:00 +++ b/include/media/saa7146_vv.h 2004-12-12 17:40:52 -08:00 @@ -219,8 +219,6 @@ /* resource management functions */ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit); -int saa7146_res_check(struct saa7146_fh *fh, unsigned int bit); -int saa7146_res_locked(struct saa7146_dev *dev, unsigned int bit); void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits); #define RESOURCE_DMA1_HPS 0x1 diff -Nru a/include/net/act_api.h b/include/net/act_api.h --- a/include/net/act_api.h 2004-12-12 17:40:52 -08:00 +++ b/include/net/act_api.h 2004-12-12 17:40:52 -08:00 @@ -8,15 +8,23 @@ #include #include +#define tca_gen(name) \ +struct tcf_##name *next; \ + u32 index; \ + int refcnt; \ + int bindcnt; \ + u32 capab; \ + int action; \ + struct tcf_t tm; \ + struct gnet_stats_basic bstats; \ + struct gnet_stats_queue qstats; \ + struct gnet_stats_rate_est rate_est; \ + spinlock_t *stats_lock; \ + spinlock_t lock + struct tcf_police { - struct tcf_police *next; - int refcnt; -#ifdef CONFIG_NET_CLS_ACT - int bindcnt; -#endif - u32 index; - int action; + tca_gen(police); int result; u32 ewma_rate; u32 burst; @@ -24,33 +32,14 @@ u32 toks; u32 ptoks; psched_time_t t_c; - spinlock_t lock; struct qdisc_rate_table *R_tab; struct qdisc_rate_table *P_tab; - - struct gnet_stats_basic bstats; - struct gnet_stats_queue qstats; - struct gnet_stats_rate_est rate_est; - spinlock_t *stats_lock; }; #ifdef CONFIG_NET_CLS_ACT #define ACT_P_CREATED 1 #define ACT_P_DELETED 1 -#define tca_gen(name) \ -struct tcf_##name *next; \ - u32 index; \ - int refcnt; \ - int bindcnt; \ - u32 capab; \ - int action; \ - struct tcf_t tm; \ - struct gnet_stats_basic bstats; \ - struct gnet_stats_queue qstats; \ - struct gnet_stats_rate_est rate_est; \ - spinlock_t *stats_lock; \ - spinlock_t lock struct tcf_act_hdr { diff -Nru a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h --- a/include/net/bluetooth/hci_core.h 2004-12-12 17:40:52 -08:00 +++ b/include/net/bluetooth/hci_core.h 2004-12-12 17:40:52 -08:00 @@ -38,10 +38,20 @@ /* HCI Core structures */ +struct inquiry_data { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 pscan_mode; + __u8 dev_class[3]; + __u16 clock_offset; + __s8 rssi; +}; + struct inquiry_entry { struct inquiry_entry *next; __u32 timestamp; - struct inquiry_info info; + struct inquiry_data data; }; struct inquiry_cache { @@ -142,6 +152,7 @@ __u16 state; __u8 type; __u8 out; + __u8 dev_class[3]; __u32 link_mode; unsigned long pend; @@ -199,7 +210,7 @@ } struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info); +void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data); /* ----- HCI Connections ----- */ enum { diff -Nru a/include/net/ip_vs.h b/include/net/ip_vs.h --- a/include/net/ip_vs.h 2004-12-12 17:40:52 -08:00 +++ b/include/net/ip_vs.h 2004-12-12 17:40:52 -08:00 @@ -358,6 +358,7 @@ NET_IPV4_VS_EXPIRE_NODEST_CONN=23, NET_IPV4_VS_SYNC_THRESHOLD=24, NET_IPV4_VS_NAT_ICMP_SEND=25, + NET_IPV4_VS_EXPIRE_QUIESCENT_TEMPLATE=26, NET_IPV4_VS_LAST }; @@ -879,6 +880,7 @@ */ extern int sysctl_ip_vs_cache_bypass; extern int sysctl_ip_vs_expire_nodest_conn; +extern int sysctl_ip_vs_expire_quiescent_template; extern int sysctl_ip_vs_sync_threshold[2]; extern int sysctl_ip_vs_nat_icmp_send; extern struct ip_vs_stats ip_vs_stats; diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c 2004-12-12 17:40:53 -08:00 +++ b/kernel/sched.c 2004-12-12 17:40:53 -08:00 @@ -4446,6 +4446,7 @@ if (sd->parent) printk(" ERROR !SD_LOAD_BALANCE domain has parent"); printk("\n"); + break; } printk("span %s\n", str); @@ -4454,8 +4455,6 @@ printk(KERN_DEBUG "ERROR domain->span does not contain CPU%d\n", i); if (!cpu_isset(i, group->cpumask)) printk(KERN_DEBUG "ERROR domain->groups does not contain CPU%d\n", i); - if (!group->cpu_power) - printk(KERN_DEBUG "ERROR domain->cpu_power not set\n"); printk(KERN_DEBUG); for (j = 0; j < level + 2; j++) @@ -4466,6 +4465,9 @@ printk(" ERROR: NULL"); break; } + + if (!group->cpu_power) + printk(KERN_DEBUG "ERROR group->cpu_power not set\n"); if (!cpus_weight(group->cpumask)) printk(" ERROR empty group:"); diff -Nru a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c --- a/net/bluetooth/hci_conn.c 2004-12-12 17:40:53 -08:00 +++ b/net/bluetooth/hci_conn.c 2004-12-12 17:40:53 -08:00 @@ -71,9 +71,10 @@ if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)) && inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { - cp.pscan_rep_mode = ie->info.pscan_rep_mode; - cp.pscan_mode = ie->info.pscan_mode; - cp.clock_offset = ie->info.clock_offset | __cpu_to_le16(0x8000); + cp.pscan_rep_mode = ie->data.pscan_rep_mode; + cp.pscan_mode = ie->data.pscan_mode; + cp.clock_offset = ie->data.clock_offset | __cpu_to_le16(0x8000); + memcpy(conn->dev_class, ie->data.dev_class, 3); } cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK); diff -Nru a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c --- a/net/bluetooth/hci_core.c 2004-12-12 17:40:52 -08:00 +++ b/net/bluetooth/hci_core.c 2004-12-12 17:40:52 -08:00 @@ -313,19 +313,19 @@ BT_DBG("cache %p, %s", cache, batostr(bdaddr)); for (e = cache->list; e; e = e->next) - if (!bacmp(&e->info.bdaddr, bdaddr)) + if (!bacmp(&e->data.bdaddr, bdaddr)) break; return e; } -void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info) +void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data) { struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_entry *e; - BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr)); + BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); - if (!(e = hci_inquiry_cache_lookup(hdev, &info->bdaddr))) { + if (!(e = hci_inquiry_cache_lookup(hdev, &data->bdaddr))) { /* Entry not in the cache. Add new one. */ if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) return; @@ -334,7 +334,7 @@ cache->list = e; } - memcpy(&e->info, info, sizeof(*info)); + memcpy(&e->data, data, sizeof(*data)); e->timestamp = jiffies; cache->timestamp = jiffies; } @@ -346,8 +346,16 @@ struct inquiry_entry *e; int copied = 0; - for (e = cache->list; e && copied < num; e = e->next, copied++) - memcpy(info++, &e->info, sizeof(*info)); + for (e = cache->list; e && copied < num; e = e->next, copied++) { + struct inquiry_data *data = &e->data; + bacpy(&info->bdaddr, &data->bdaddr); + info->pscan_rep_mode = data->pscan_rep_mode; + info->pscan_period_mode = data->pscan_period_mode; + info->pscan_mode = data->pscan_mode; + memcpy(info->dev_class, data->dev_class, 3); + info->clock_offset = data->clock_offset; + info++; + } BT_DBG("cache %p, copied %d", cache, copied); return copied; diff -Nru a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c --- a/net/bluetooth/hci_event.c 2004-12-12 17:40:52 -08:00 +++ b/net/bluetooth/hci_event.c 2004-12-12 17:40:52 -08:00 @@ -491,8 +491,18 @@ BT_DBG("%s num_rsp %d", hdev->name, num_rsp); hci_dev_lock(hdev); - for (; num_rsp; num_rsp--) - hci_inquiry_cache_update(hdev, info++); + for (; num_rsp; num_rsp--) { + struct inquiry_data data; + bacpy(&data.bdaddr, &info->bdaddr); + data.pscan_rep_mode = info->pscan_rep_mode; + data.pscan_period_mode = info->pscan_period_mode; + data.pscan_mode = info->pscan_mode; + memcpy(data.dev_class, info->dev_class, 3); + data.clock_offset = info->clock_offset; + data.rssi = 0x00; + info++; + hci_inquiry_cache_update(hdev, &data); + } hci_dev_unlock(hdev); } @@ -506,15 +516,16 @@ hci_dev_lock(hdev); for (; num_rsp; num_rsp--) { - struct inquiry_info tmp; - bacpy(&tmp.bdaddr, &info->bdaddr); - tmp.pscan_rep_mode = info->pscan_rep_mode; - tmp.pscan_period_mode = info->pscan_period_mode; - tmp.pscan_mode = 0x00; - memcpy(tmp.dev_class, &info->dev_class, 3); - tmp.clock_offset = info->clock_offset; + struct inquiry_data data; + bacpy(&data.bdaddr, &info->bdaddr); + data.pscan_rep_mode = info->pscan_rep_mode; + data.pscan_period_mode = info->pscan_period_mode; + data.pscan_mode = 0x00; + memcpy(data.dev_class, info->dev_class, 3); + data.clock_offset = info->clock_offset; + data.rssi = info->rssi; info++; - hci_inquiry_cache_update(hdev, &tmp); + hci_inquiry_cache_update(hdev, &data); } hci_dev_unlock(hdev); } @@ -544,6 +555,7 @@ return; } } + memcpy(conn->dev_class, ev->dev_class, 3); conn->state = BT_CONNECT; hci_dev_unlock(hdev); diff -Nru a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c --- a/net/bluetooth/hci_sysfs.c 2004-12-12 17:40:53 -08:00 +++ b/net/bluetooth/hci_sysfs.c 2004-12-12 17:40:53 -08:00 @@ -48,14 +48,14 @@ hci_dev_lock_bh(hdev); for (e = cache->list; e; e = e->next) { - struct inquiry_info *info = &e->info; + struct inquiry_data *data = &e->data; bdaddr_t bdaddr; - baswap(&bdaddr, &info->bdaddr); - n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x 0x%.2x %u\n", + baswap(&bdaddr, &data->bdaddr); + n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %u\n", batostr(&bdaddr), - info->pscan_rep_mode, info->pscan_period_mode, info->pscan_mode, - info->dev_class[2], info->dev_class[1], info->dev_class[0], - info->clock_offset, 0, e->timestamp); + data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode, + data->dev_class[2], data->dev_class[1], data->dev_class[0], + data->clock_offset, data->rssi, e->timestamp); } hci_dev_unlock_bh(hdev); diff -Nru a/net/compat.c b/net/compat.c --- a/net/compat.c 2004-12-12 17:40:53 -08:00 +++ b/net/compat.c 2004-12-12 17:40:53 -08:00 @@ -124,6 +124,12 @@ (struct compat_cmsghdr __user *)((msg)->msg_control) : \ (struct compat_cmsghdr __user *)NULL) +#define CMSG_COMPAT_OK(ucmlen, ucmsg, mhdr) \ + ((ucmlen) >= sizeof(struct cmsghdr) && \ + (ucmlen) <= (unsigned long) \ + ((mhdr)->msg_controllen - \ + ((char *)(ucmsg) - (char *)(mhdr)->msg_control))) + static inline struct compat_cmsghdr __user *cmsg_compat_nxthdr(struct msghdr *msg, struct compat_cmsghdr __user *cmsg, int cmsg_len) { @@ -154,11 +160,7 @@ return -EFAULT; /* Catch bogons. */ - if(CMSG_COMPAT_ALIGN(ucmlen) < - CMSG_COMPAT_ALIGN(sizeof(struct compat_cmsghdr))) - return -EINVAL; - if((unsigned long)(((char __user *)ucmsg - (char __user *)kmsg->msg_control) - + ucmlen) > kmsg->msg_controllen) + if (!CMSG_COMPAT_OK(ucmlen, ucmsg, kmsg)) return -EINVAL; tmp = ((ucmlen - CMSG_COMPAT_ALIGN(sizeof(*ucmsg))) + diff -Nru a/net/core/scm.c b/net/core/scm.c --- a/net/core/scm.c 2004-12-12 17:40:52 -08:00 +++ b/net/core/scm.c 2004-12-12 17:40:52 -08:00 @@ -127,9 +127,7 @@ for too short ancillary data object at all! Oops. OK, let's add it... */ - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) + if (!CMSG_OK(msg, cmsg)) goto error; if (cmsg->cmsg_level != SOL_SOCKET) diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c --- a/net/ipv4/af_inet.c 2004-12-12 17:40:52 -08:00 +++ b/net/ipv4/af_inet.c 2004-12-12 17:40:52 -08:00 @@ -821,6 +821,31 @@ .sendpage = inet_sendpage, }; +/* + * For SOCK_RAW sockets; should be the same as inet_dgram_ops but without + * udp_poll + */ +static struct proto_ops inet_sockraw_ops = { + .family = PF_INET, + .owner = THIS_MODULE, + .release = inet_release, + .bind = inet_bind, + .connect = inet_dgram_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = inet_getname, + .poll = datagram_poll, + .ioctl = inet_ioctl, + .listen = sock_no_listen, + .shutdown = inet_shutdown, + .setsockopt = sock_common_setsockopt, + .getsockopt = sock_common_getsockopt, + .sendmsg = inet_sendmsg, + .recvmsg = sock_common_recvmsg, + .mmap = sock_no_mmap, + .sendpage = inet_sendpage, +}; + static struct net_proto_family inet_family_ops = { .family = PF_INET, .create = inet_create, @@ -861,7 +886,7 @@ .type = SOCK_RAW, .protocol = IPPROTO_IP, /* wild card */ .prot = &raw_prot, - .ops = &inet_dgram_ops, + .ops = &inet_sockraw_ops, .capability = CAP_NET_RAW, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_REUSE, diff -Nru a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c --- a/net/ipv4/ip_options.c 2004-12-12 17:40:53 -08:00 +++ b/net/ipv4/ip_options.c 2004-12-12 17:40:53 -08:00 @@ -515,6 +515,8 @@ kfree(opt); return -EINVAL; } + if (*optp) + kfree(*optp); *optp = opt; return 0; } diff -Nru a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c --- a/net/ipv4/ip_sockglue.c 2004-12-12 17:40:52 -08:00 +++ b/net/ipv4/ip_sockglue.c 2004-12-12 17:40:52 -08:00 @@ -146,11 +146,8 @@ struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) { + if (!CMSG_OK(msg, cmsg)) return -EINVAL; - } if (cmsg->cmsg_level != SOL_IP) continue; switch (cmsg->cmsg_type) { diff -Nru a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c --- a/net/ipv4/ipvs/ip_vs_conn.c 2004-12-12 17:40:53 -08:00 +++ b/net/ipv4/ipvs/ip_vs_conn.c 2004-12-12 17:40:53 -08:00 @@ -453,7 +453,9 @@ * Checking the dest server status. */ if ((dest == NULL) || - !(dest->flags & IP_VS_DEST_F_AVAILABLE)) { + !(dest->flags & IP_VS_DEST_F_AVAILABLE) || + (sysctl_ip_vs_expire_quiescent_template && + (atomic_read(&dest->weight) == 0))) { IP_VS_DBG(9, "check_template: dest not available for " "protocol %s s:%u.%u.%u.%u:%d v:%u.%u.%u.%u:%d " "-> d:%u.%u.%u.%u:%d\n", diff -Nru a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c --- a/net/ipv4/ipvs/ip_vs_ctl.c 2004-12-12 17:40:53 -08:00 +++ b/net/ipv4/ipvs/ip_vs_ctl.c 2004-12-12 17:40:53 -08:00 @@ -75,6 +75,7 @@ static int sysctl_ip_vs_am_droprate = 10; int sysctl_ip_vs_cache_bypass = 0; int sysctl_ip_vs_expire_nodest_conn = 0; +int sysctl_ip_vs_expire_quiescent_template = 0; int sysctl_ip_vs_sync_threshold[2] = { 3, 50 }; int sysctl_ip_vs_nat_icmp_send = 0; @@ -1447,9 +1448,9 @@ { .ctl_name = NET_IPV4_VS_TO_ES, .procname = "timeout_established", - .data = &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED], + .data = &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1457,7 +1458,7 @@ .procname = "timeout_synsent", .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1465,7 +1466,7 @@ .procname = "timeout_synrecv", .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1473,7 +1474,7 @@ .procname = "timeout_finwait", .data = &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1489,7 +1490,7 @@ .procname = "timeout_close", .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1497,7 +1498,7 @@ .procname = "timeout_closewait", .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1505,7 +1506,7 @@ .procname = "timeout_lastack", .data = &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1513,7 +1514,7 @@ .procname = "timeout_listen", .data = &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1521,7 +1522,7 @@ .procname = "timeout_synack", .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1529,7 +1530,7 @@ .procname = "timeout_udp", .data = &vs_timeout_table_dos.timeout[IP_VS_S_UDP], .maxlen = sizeof(int), - .mode = 0644, + .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { @@ -1553,6 +1554,14 @@ .ctl_name = NET_IPV4_VS_EXPIRE_NODEST_CONN, .procname = "expire_nodest_conn", .data = &sysctl_ip_vs_expire_nodest_conn, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = NET_IPV4_VS_EXPIRE_QUIESCENT_TEMPLATE, + .procname = "expire_quiescent_template", + .data = &sysctl_ip_vs_expire_quiescent_template, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, diff -Nru a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c --- a/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-12-12 17:40:53 -08:00 +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c 2004-12-12 17:40:53 -08:00 @@ -381,6 +381,7 @@ problem (DMZ machines opening holes to internal networks, or the packet filter itself). */ if (!loose) { + ip_conntrack_expect_put(exp); ret = NF_ACCEPT; goto out; } diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c --- a/net/ipv4/tcp_input.c 2004-12-12 17:40:53 -08:00 +++ b/net/ipv4/tcp_input.c 2004-12-12 17:40:53 -08:00 @@ -3028,7 +3028,7 @@ tp->snd_wscale = *(__u8 *)ptr; if(tp->snd_wscale > 14) { if(net_ratelimit()) - printk("tcp_parse_options: Illegal window " + printk(KERN_INFO "tcp_parse_options: Illegal window " "scaling value %d >14 received.", tp->snd_wscale); tp->snd_wscale = 14; diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c --- a/net/ipv6/af_inet6.c 2004-12-12 17:40:52 -08:00 +++ b/net/ipv6/af_inet6.c 2004-12-12 17:40:52 -08:00 @@ -524,11 +524,33 @@ extern void ipv6_sysctl_unregister(void); #endif +/* Same as inet6_dgram_ops, sans udp_poll. */ +static struct proto_ops inet6_sockraw_ops = { + .family = PF_INET6, + .owner = THIS_MODULE, + .release = inet6_release, + .bind = inet6_bind, + .connect = inet_dgram_connect, /* ok */ + .socketpair = sock_no_socketpair, /* a do nothing */ + .accept = sock_no_accept, /* a do nothing */ + .getname = inet6_getname, + .poll = datagram_poll, /* ok */ + .ioctl = inet6_ioctl, /* must change */ + .listen = sock_no_listen, /* ok */ + .shutdown = inet_shutdown, /* ok */ + .setsockopt = sock_common_setsockopt, /* ok */ + .getsockopt = sock_common_getsockopt, /* ok */ + .sendmsg = inet_sendmsg, /* ok */ + .recvmsg = sock_common_recvmsg, /* ok */ + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + static struct inet_protosw rawv6_protosw = { .type = SOCK_RAW, .protocol = IPPROTO_IP, /* wild card */ .prot = &rawv6_prot, - .ops = &inet6_dgram_ops, + .ops = &inet6_sockraw_ops, .capability = CAP_NET_RAW, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_REUSE, diff -Nru a/net/ipv6/datagram.c b/net/ipv6/datagram.c --- a/net/ipv6/datagram.c 2004-12-12 17:40:52 -08:00 +++ b/net/ipv6/datagram.c 2004-12-12 17:40:52 -08:00 @@ -427,9 +427,7 @@ int addr_type; struct net_device *dev = NULL; - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) { + if (!CMSG_OK(msg, cmsg)) { err = -EINVAL; goto exit_f; } diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c --- a/net/ipv6/ndisc.c 2004-12-12 17:40:52 -08:00 +++ b/net/ipv6/ndisc.c 2004-12-12 17:40:52 -08:00 @@ -943,7 +943,7 @@ } /* Don't accept RS if we're not in router mode */ - if (!idev->cnf.forwarding || idev->cnf.accept_ra) + if (!idev->cnf.forwarding) goto out; /* diff -Nru a/net/sched/ipt.c b/net/sched/ipt.c --- a/net/sched/ipt.c 2004-12-12 17:40:52 -08:00 +++ b/net/sched/ipt.c 2004-12-12 17:40:52 -08:00 @@ -63,8 +63,7 @@ target = __ipt_find_target_lock(t->u.user.name, &ret); if (!target) { - printk("init_targ: Failed to find %s\n", - t->u.kernel.target->name); + printk("init_targ: Failed to find %s\n", t->u.user.name); return -1; } diff -Nru a/net/sched/sch_netem.c b/net/sched/sch_netem.c --- a/net/sched/sch_netem.c 2004-12-12 17:40:53 -08:00 +++ b/net/sched/sch_netem.c 2004-12-12 17:40:53 -08:00 @@ -258,12 +258,13 @@ { struct Qdisc *sch = (struct Qdisc *)arg; struct netem_sched_data *q = qdisc_priv(sch); + struct net_device *dev = sch->dev; struct sk_buff *skb; psched_time_t now; pr_debug("netem_watchdog: fired @%lu\n", jiffies); - spin_lock_bh(&sch->dev->queue_lock); + spin_lock_bh(&dev->queue_lock); PSCHED_GET_TIME(now); while ((skb = skb_peek(&q->delayed)) != NULL) { @@ -286,7 +287,8 @@ else sch->q.qlen++; } - spin_unlock_bh(&sch->dev->queue_lock); + qdisc_restart(dev); + spin_unlock_bh(&dev->queue_lock); } static void netem_reset(struct Qdisc *sch) diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c --- a/net/sctp/socket.c 2004-12-12 17:40:53 -08:00 +++ b/net/sctp/socket.c 2004-12-12 17:40:53 -08:00 @@ -4098,12 +4098,8 @@ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR((struct msghdr*)msg, cmsg)) { - /* Check for minimum length. The SCM code has this check. */ - if (cmsg->cmsg_len < sizeof(struct cmsghdr) || - (unsigned long)(((char*)cmsg - (char*)msg->msg_control) - + cmsg->cmsg_len) > msg->msg_controllen) { + if (!CMSG_OK(msg, cmsg)) return -EINVAL; - } /* Should we parse this header or ignore? */ if (cmsg->cmsg_level != IPPROTO_SCTP) diff -Nru a/sound/core/init.c b/sound/core/init.c --- a/sound/core/init.c 2004-12-12 17:40:52 -08:00 +++ b/sound/core/init.c 2004-12-12 17:40:52 -08:00 @@ -785,12 +785,15 @@ int snd_card_pci_suspend(struct pci_dev *dev, u32 state) { snd_card_t *card = pci_get_drvdata(dev); + int err; if (! card || ! card->pm_suspend) return 0; if (card->power_state == SNDRV_CTL_POWER_D3hot) return 0; /* FIXME: correct state value? */ - return card->pm_suspend(card, 0); + err = card->pm_suspend(card, 0); + pci_save_state(dev); + return err; } int snd_card_pci_resume(struct pci_dev *dev) diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c --- a/sound/core/pcm_native.c 2004-12-12 17:40:52 -08:00 +++ b/sound/core/pcm_native.c 2004-12-12 17:40:52 -08:00 @@ -3099,6 +3099,7 @@ area->vm_page_prot = pgprot_noncached(area->vm_page_prot); #endif area->vm_ops = &snd_pcm_vm_ops_data_mmio; + area->vm_private_data = substream; area->vm_flags |= VM_IO; size = area->vm_end - area->vm_start; offset = area->vm_pgoff << PAGE_SHIFT; diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c --- a/sound/pci/ali5451/ali5451.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/ali5451/ali5451.c 2004-12-12 17:40:53 -08:00 @@ -1932,6 +1932,7 @@ outl(0xffffffff, ALI_REG(chip, ALI_STOP)); spin_unlock_irq(&chip->reg_lock); + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -1986,6 +1987,7 @@ } if (codec->port) pci_release_regions(codec->pci); + pci_disable_device(codec->pci); #ifdef CONFIG_PM if (codec->image) kfree(codec->image); @@ -2093,11 +2095,14 @@ if (pci_set_dma_mask(pci, 0x7fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x7fffffff) < 0) { snd_printk("architecture does not support 31bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } - if ((codec = kcalloc(1, sizeof(*codec), GFP_KERNEL)) == NULL) + if ((codec = kcalloc(1, sizeof(*codec), GFP_KERNEL)) == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&codec->reg_lock); spin_lock_init(&codec->voice_alloc); diff -Nru a/sound/pci/als4000.c b/sound/pci/als4000.c --- a/sound/pci/als4000.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/als4000.c 2004-12-12 17:40:53 -08:00 @@ -582,6 +582,7 @@ } #endif pci_release_regions(acard->pci); + pci_disable_device(acard->pci); } static int __devinit snd_card_als4000_probe(struct pci_dev *pci, @@ -612,11 +613,14 @@ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } - if ((err = pci_request_regions(pci, "ALS4000")) < 0) + if ((err = pci_request_regions(pci, "ALS4000")) < 0) { + pci_disable_device(pci); return err; + } gcr = pci_resource_start(pci, 0); pci_read_config_word(pci, PCI_COMMAND, &word); @@ -627,6 +631,7 @@ sizeof( snd_card_als4000_t ) ); if (card == NULL) { pci_release_regions(pci); + pci_disable_device(pci); return -ENOMEM; } diff -Nru a/sound/pci/atiixp.c b/sound/pci/atiixp.c --- a/sound/pci/atiixp.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/atiixp.c 2004-12-12 17:40:52 -08:00 @@ -1420,6 +1420,7 @@ pci_enable_device(chip->pci); pci_set_power_state(chip->pci, 0); + pci_set_master(chip->pci); snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); @@ -1473,6 +1474,7 @@ if (chip->remap_addr) iounmap(chip->remap_addr); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -1500,8 +1502,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->ac97_lock); @@ -1510,6 +1514,7 @@ chip->pci = pci; chip->irq = -1; if ((err = pci_request_regions(pci, "ATI IXP AC97")) < 0) { + pci_disable_device(pci); kfree(chip); return err; } diff -Nru a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c --- a/sound/pci/atiixp_modem.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/atiixp_modem.c 2004-12-12 17:40:53 -08:00 @@ -1142,6 +1142,7 @@ pci_enable_device(chip->pci); pci_set_power_state(chip->pci, 0); + pci_set_master(chip->pci); snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); @@ -1195,6 +1196,7 @@ if (chip->remap_addr) iounmap(chip->remap_addr); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -1222,8 +1224,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->ac97_lock); @@ -1233,6 +1237,7 @@ chip->irq = -1; if ((err = pci_request_regions(pci, "ATI IXP MC97")) < 0) { kfree(chip); + pci_disable_device(pci); return err; } chip->addr = pci_resource_start(pci, 0); diff -Nru a/sound/pci/azt3328.c b/sound/pci/azt3328.c --- a/sound/pci/azt3328.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/azt3328.c 2004-12-12 17:40:52 -08:00 @@ -1268,6 +1268,7 @@ if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; @@ -1317,8 +1318,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); chip->card = card; chip->pci = pci; @@ -1328,11 +1331,13 @@ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } if ((err = pci_request_regions(pci, "Aztech AZF3328")) < 0) { kfree(chip); + pci_disable_device(pci); return err; } diff -Nru a/sound/pci/bt87x.c b/sound/pci/bt87x.c --- a/sound/pci/bt87x.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/bt87x.c 2004-12-12 17:40:52 -08:00 @@ -648,6 +648,7 @@ if (chip->irq >= 0) free_irq(chip->irq, chip); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -693,8 +694,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (!chip) + if (!chip) { + pci_disable_device(pci); return -ENOMEM; + } chip->card = card; chip->pci = pci; chip->irq = -1; @@ -702,6 +705,7 @@ if ((err = pci_request_regions(pci, "Bt87x audio")) < 0) { kfree(chip); + pci_disable_device(pci); return err; } chip->mmio = ioremap_nocache(pci_resource_start(pci, 0), diff -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c --- a/sound/pci/cmipci.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/cmipci.c 2004-12-12 17:40:53 -08:00 @@ -2550,6 +2550,7 @@ } #endif pci_release_regions(cm->pci); + pci_disable_device(cm->pci); kfree(cm); return 0; } @@ -2583,8 +2584,10 @@ return err; cm = kcalloc(1, sizeof(*cm), GFP_KERNEL); - if (cm == NULL) + if (cm == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&cm->reg_lock); init_MUTEX(&cm->open_mutex); @@ -2598,6 +2601,7 @@ if ((err = pci_request_regions(pci, card->driver)) < 0) { kfree(cm); + pci_disable_device(pci); return err; } cm->iobase = pci_resource_start(pci, 0); diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c --- a/sound/pci/cs4281.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/cs4281.c 2004-12-12 17:40:53 -08:00 @@ -1362,6 +1362,7 @@ if (chip->ba1) iounmap(chip->ba1); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; @@ -1395,8 +1396,10 @@ if ((err = pci_enable_device(pci)) < 0) return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); chip->card = card; chip->pci = pci; @@ -1410,6 +1413,7 @@ if ((err = pci_request_regions(pci, "CS4281")) < 0) { kfree(chip); + pci_disable_device(pci); return err; } chip->ba0_addr = pci_resource_start(pci, 0); @@ -2074,6 +2078,7 @@ ulCLK &= ~CLKCR1_CKRA; snd_cs4281_pokeBA0(chip, BA0_CLKCR1, ulCLK); + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -2085,6 +2090,7 @@ u32 ulCLK; pci_enable_device(chip->pci); + pci_set_master(chip->pci); ulCLK = snd_cs4281_peekBA0(chip, BA0_CLKCR1); ulCLK |= CLKCR1_CKRA; diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c --- a/sound/pci/cs46xx/cs46xx_lib.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/cs46xx/cs46xx_lib.c 2004-12-12 17:40:52 -08:00 @@ -2885,6 +2885,7 @@ } #endif + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -3678,6 +3679,7 @@ /* disable CLKRUN */ chip->active_ctrl(chip, -chip->amplifier); chip->amplifier = amp_saved; /* restore the status */ + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -3688,6 +3690,7 @@ int amp_saved; pci_enable_device(chip->pci); + pci_set_master(chip->pci); amp_saved = chip->amplifier; chip->amplifier = 0; chip->active_ctrl(chip, 1); /* force to on */ @@ -3744,8 +3747,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); #ifdef CONFIG_SND_CS46XX_NEW_DSP init_MUTEX(&chip->spos_mutex); diff -Nru a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c --- a/sound/pci/emu10k1/emu10k1_main.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/emu10k1/emu10k1_main.c 2004-12-12 17:40:53 -08:00 @@ -561,6 +561,7 @@ free_irq(emu->irq, (void *)emu); if (emu->port) pci_release_regions(emu->pci); + pci_disable_device(emu->pci); kfree(emu); return 0; } @@ -596,14 +597,17 @@ return err; emu = kcalloc(1, sizeof(*emu), GFP_KERNEL); - if (emu == NULL) + if (emu == NULL) { + pci_disable_device(pci); return -ENOMEM; + } /* set the DMA transfer mask */ emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); kfree(emu); + pci_disable_device(pci); return -ENXIO; } emu->card = card; @@ -629,6 +633,7 @@ if ((err = pci_request_regions(pci, "EMU10K1")) < 0) { kfree(emu); + pci_disable_device(pci); return err; } emu->port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c --- a/sound/pci/ens1370.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/ens1370.c 2004-12-12 17:40:53 -08:00 @@ -1839,6 +1839,7 @@ if (ensoniq->irq >= 0) free_irq(ensoniq->irq, (void *)ensoniq); pci_release_regions(ensoniq->pci); + pci_disable_device(ensoniq->pci); kfree(ensoniq); return 0; } @@ -1893,8 +1894,10 @@ if ((err = pci_enable_device(pci)) < 0) return err; ensoniq = kcalloc(1, sizeof(*ensoniq), GFP_KERNEL); - if (ensoniq == NULL) + if (ensoniq == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&ensoniq->reg_lock); init_MUTEX(&ensoniq->src_mutex); ensoniq->card = card; @@ -1902,6 +1905,7 @@ ensoniq->irq = -1; if ((err = pci_request_regions(pci, "Ensoniq AudioPCI")) < 0) { kfree(ensoniq); + pci_disable_device(pci); return err; } ensoniq->port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/es1938.c b/sound/pci/es1938.c --- a/sound/pci/es1938.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/es1938.c 2004-12-12 17:40:53 -08:00 @@ -1394,6 +1394,7 @@ outb(0x00, SLIO_REG(chip, IRQCONTROL)); /* disable irqs */ + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -1432,6 +1433,7 @@ if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -1461,18 +1463,22 @@ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); chip->card = card; chip->pci = pci; if ((err = pci_request_regions(pci, "ESS Solo-1")) < 0) { kfree(chip); + pci_disable_device(pci); return err; } chip->io_port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c --- a/sound/pci/es1968.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/es1968.c 2004-12-12 17:40:53 -08:00 @@ -2411,6 +2411,7 @@ snd_ac97_suspend(chip->ac97); snd_es1968_bob_stop(chip); snd_es1968_set_acpi(chip, ACPI_D3); + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -2424,6 +2425,7 @@ /* restore all our config */ pci_enable_device(chip->pci); + pci_set_master(chip->pci); snd_es1968_chip_init(chip); /* need to restore the base pointers.. */ @@ -2467,6 +2469,7 @@ chip->master_switch = NULL; chip->master_volume = NULL; pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -2518,12 +2521,15 @@ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (! chip) + if (! chip) { + pci_disable_device(pci); return -ENOMEM; + } /* Set Vars */ chip->type = chip_type; @@ -2543,6 +2549,7 @@ if ((err = pci_request_regions(pci, "ESS Maestro")) < 0) { kfree(chip); + pci_disable_device(pci); return err; } chip->io_port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/fm801.c b/sound/pci/fm801.c --- a/sound/pci/fm801.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/fm801.c 2004-12-12 17:40:53 -08:00 @@ -1234,6 +1234,7 @@ if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; @@ -1263,14 +1264,17 @@ if ((err = pci_enable_device(pci)) < 0) return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); chip->card = card; chip->pci = pci; chip->irq = -1; if ((err = pci_request_regions(pci, "FM801")) < 0) { kfree(chip); + pci_disable_device(pci); return err; } chip->port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c --- a/sound/pci/ice1712/ice1712.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/ice1712/ice1712.c 2004-12-12 17:40:52 -08:00 @@ -2495,6 +2495,7 @@ if (ice->port) pci_release_regions(ice->pci); snd_ice1712_akm4xxx_free(ice); + pci_disable_device(ice->pci); kfree(ice); return 0; } @@ -2527,12 +2528,15 @@ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } ice = kcalloc(1, sizeof(*ice), GFP_KERNEL); - if (ice == NULL) + if (ice == NULL) { + pci_disable_device(pci); return -ENOMEM; + } ice->omni = omni ? 1 : 0; if (cs8427_timeout < 1) cs8427_timeout = 1; @@ -2562,6 +2566,7 @@ if ((err = pci_request_regions(pci, "ICE1712")) < 0) { kfree(ice); + pci_disable_device(pci); return err; } ice->port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c --- a/sound/pci/ice1712/ice1724.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/ice1712/ice1724.c 2004-12-12 17:40:52 -08:00 @@ -2076,6 +2076,7 @@ } pci_release_regions(ice->pci); snd_ice1712_akm4xxx_free(ice); + pci_disable_device(ice->pci); kfree(ice); return 0; } @@ -2105,8 +2106,10 @@ return err; ice = kcalloc(1, sizeof(*ice), GFP_KERNEL); - if (ice == NULL) + if (ice == NULL) { + pci_disable_device(pci); return -ENOMEM; + } ice->vt1724 = 1; spin_lock_init(&ice->reg_lock); init_MUTEX(&ice->gpio_mutex); @@ -2124,6 +2127,7 @@ if ((err = pci_request_regions(pci, "ICE1724")) < 0) { kfree(ice); + pci_disable_device(pci); return err; } ice->port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c --- a/sound/pci/intel8x0.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/intel8x0.c 2004-12-12 17:40:53 -08:00 @@ -1020,7 +1020,9 @@ */ if (cnt & ICH_PCM_246_MASK) { iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_PCM_246_MASK); + spin_unlock_irq(&chip->reg_lock); msleep(50); /* grrr... */ + spin_lock_irq(&chip->reg_lock); } } else if (chip->device_type == DEVICE_INTEL_ICH4) { if (runtime->sample_bits > 16) @@ -2261,6 +2263,7 @@ if (chip->remap_bmaddr) iounmap(chip->remap_bmaddr); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -2279,6 +2282,7 @@ for (i = 0; i < 3; i++) if (chip->ac97[i]) snd_ac97_suspend(chip->ac97[i]); + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -2496,8 +2500,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->ac97_lock); chip->device_type = device_type; @@ -2517,6 +2523,7 @@ if ((err = pci_request_regions(pci, card->shortname)) < 0) { kfree(chip); + pci_disable_device(pci); return err; } diff -Nru a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c --- a/sound/pci/intel8x0m.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/intel8x0m.c 2004-12-12 17:40:52 -08:00 @@ -1074,6 +1074,7 @@ if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -1091,6 +1092,7 @@ snd_pcm_suspend_all(chip->pcm[i]); if (chip->ac97) snd_ac97_suspend(chip->ac97); + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -1172,8 +1174,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->ac97_lock); chip->device_type = device_type; @@ -1183,6 +1187,7 @@ if ((err = pci_request_regions(pci, card->shortname)) < 0) { kfree(chip); + pci_disable_device(pci); return err; } diff -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c --- a/sound/pci/korg1212/korg1212.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/korg1212/korg1212.c 2004-12-12 17:40:52 -08:00 @@ -2179,6 +2179,7 @@ korg1212->dma_shared.area = NULL; } + pci_disable_device(korg1212->pci); kfree(korg1212); return 0; } @@ -2210,8 +2211,10 @@ return err; korg1212 = kcalloc(1, sizeof(*korg1212), GFP_KERNEL); - if (korg1212 == NULL) + if (korg1212 == NULL) { + pci_disable_device(pci); return -ENOMEM; + } korg1212->card = card; korg1212->pci = pci; @@ -2244,6 +2247,7 @@ if ((err = pci_request_regions(pci, "korg1212")) < 0) { kfree(korg1212); + pci_disable_device(pci); return err; } @@ -2270,6 +2274,7 @@ if ((korg1212->iobase = ioremap(korg1212->iomem, iomem_size)) == NULL) { snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", korg1212->iomem, korg1212->iomem + iomem_size - 1); + snd_korg1212_free(korg1212); return -EBUSY; } @@ -2279,6 +2284,7 @@ if (err) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + snd_korg1212_free(korg1212); return -EBUSY; } @@ -2326,6 +2332,7 @@ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), sizeof(KorgSharedBuffer), &korg1212->dma_shared) < 0) { snd_printk(KERN_ERR "can not allocate shared buffer memory (%Zd bytes)\n", sizeof(KorgSharedBuffer)); + snd_korg1212_free(korg1212); return -ENOMEM; } korg1212->sharedBufferPtr = (KorgSharedBuffer *)korg1212->dma_shared.area; @@ -2342,6 +2349,7 @@ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), korg1212->DataBufsSize, &korg1212->dma_play) < 0) { snd_printk(KERN_ERR "can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize); + snd_korg1212_free(korg1212); return -ENOMEM; } korg1212->playDataBufsPtr = (KorgAudioBuffer *)korg1212->dma_play.area; @@ -2355,6 +2363,7 @@ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), korg1212->DataBufsSize, &korg1212->dma_rec) < 0) { snd_printk(KERN_ERR "can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize); + snd_korg1212_free(korg1212); return -ENOMEM; } korg1212->recordDataBufsPtr = (KorgAudioBuffer *)korg1212->dma_rec.area; @@ -2386,6 +2395,7 @@ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) { snd_printk(KERN_ERR "can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize); + snd_korg1212_free(korg1212); return -ENOMEM; } @@ -2405,8 +2415,10 @@ mdelay(CARD_BOOT_DELAY_IN_MS); - if (snd_korg1212_downloadDSPCode(korg1212)) + if (snd_korg1212_downloadDSPCode(korg1212)) { + snd_korg1212_free(korg1212); return -EBUSY; + } printk(KERN_INFO "dspMemPhy = %08x U[%08x]\n" "PlayDataPhy = %08x L[%08x]\n" @@ -2421,8 +2433,10 @@ korg1212->RoutingTablePhy, LowerWordSwap(korg1212->RoutingTablePhy), korg1212->AdatTimeCodePhy, LowerWordSwap(korg1212->AdatTimeCodePhy)); - if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm)) < 0) + if ((err = snd_pcm_new(korg1212->card, "korg1212", 0, 1, 1, &korg1212->pcm)) < 0) { + snd_korg1212_free(korg1212); return err; + } korg1212->pcm->private_data = korg1212; korg1212->pcm->private_free = snd_korg1212_free_pcm; @@ -2439,8 +2453,10 @@ for (i = 0; i < ARRAY_SIZE(snd_korg1212_controls); i++) { err = snd_ctl_add(korg1212->card, snd_ctl_new1(&snd_korg1212_controls[i], korg1212)); - if (err < 0) + if (err < 0) { + snd_korg1212_free(korg1212); return err; + } } snd_korg1212_proc_init(korg1212); diff -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c --- a/sound/pci/maestro3.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/maestro3.c 2004-12-12 17:40:52 -08:00 @@ -2386,6 +2386,7 @@ if (chip->iobase) pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -2422,6 +2423,8 @@ /* power down apci registers */ snd_m3_outw(chip, 0xffff, 0x54); snd_m3_outw(chip, 0xffff, 0x56); + + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -2434,6 +2437,7 @@ if (chip->suspend_mem == NULL) return 0; + pci_enable_device(chip->pci); pci_set_master(chip->pci); /* first lets just bring everything back. .*/ @@ -2502,12 +2506,15 @@ if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); switch (pci->device) { @@ -2549,6 +2556,7 @@ chip->substreams = kmalloc(sizeof(m3_dma_t) * chip->num_substreams, GFP_KERNEL); if (chip->substreams == NULL) { kfree(chip); + pci_disable_device(pci); return -ENOMEM; } memset(chip->substreams, 0, sizeof(m3_dma_t) * chip->num_substreams); diff -Nru a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c --- a/sound/pci/mixart/mixart.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/mixart/mixart.c 2004-12-12 17:40:53 -08:00 @@ -1092,6 +1092,7 @@ mgr->bufferinfo.area = NULL; } + pci_disable_device(mgr->pci); kfree(mgr); return 0; } @@ -1292,14 +1293,17 @@ /* check if we can restrict PCI DMA transfers to 32 bits */ if (pci_set_dma_mask(pci, 0xffffffff) < 0) { snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } /* */ mgr = kcalloc(1, sizeof(*mgr), GFP_KERNEL); - if (! mgr) + if (! mgr) { + pci_disable_device(pci); return -ENOMEM; + } mgr->pci = pci; mgr->irq = -1; @@ -1307,6 +1311,7 @@ /* resource assignment */ if ((err = pci_request_regions(pci, CARD_NAME)) < 0) { kfree(mgr); + pci_disable_device(pci); return err; } for (i = 0; i < 2; i++) { diff -Nru a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c --- a/sound/pci/nm256/nm256.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/nm256/nm256.c 2004-12-12 17:40:53 -08:00 @@ -1274,6 +1274,7 @@ snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); chip->coeffs_current = 0; + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -1319,6 +1320,7 @@ if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -1346,9 +1348,14 @@ *chip_ret = NULL; + if ((err = pci_enable_device(pci)) < 0) + return err; + chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } chip->card = card; chip->pci = pci; @@ -1534,9 +1541,6 @@ unsigned int xbuffer_top; struct nm256_quirk *q; u16 subsystem_vendor, subsystem_device; - - if ((err = pci_enable_device(pci)) < 0) - return err; if (dev >= SNDRV_CARDS) return -ENODEV; diff -Nru a/sound/pci/rme32.c b/sound/pci/rme32.c --- a/sound/pci/rme32.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/rme32.c 2004-12-12 17:40:53 -08:00 @@ -1350,6 +1350,7 @@ pci_release_regions(rme32->pci); rme32->port = 0; } + pci_disable_device(rme32->pci); } static void snd_rme32_free_spdif_pcm(snd_pcm_t * pcm) diff -Nru a/sound/pci/rme96.c b/sound/pci/rme96.c --- a/sound/pci/rme96.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/rme96.c 2004-12-12 17:40:52 -08:00 @@ -1553,6 +1553,7 @@ pci_release_regions(rme96->pci); rme96->port = 0; } + pci_disable_device(rme96->pci); } static void diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c --- a/sound/pci/rme9652/hdsp.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/rme9652/hdsp.c 2004-12-12 17:40:52 -08:00 @@ -5060,6 +5060,7 @@ if (hdsp->port) pci_release_regions(hdsp->pci); + pci_disable_device(hdsp->pci); return 0; } diff -Nru a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c --- a/sound/pci/rme9652/rme9652.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/rme9652/rme9652.c 2004-12-12 17:40:52 -08:00 @@ -1812,6 +1812,7 @@ if (rme9652->port) pci_release_regions(rme9652->pci); + pci_disable_device(rme9652->pci); return 0; } diff -Nru a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c --- a/sound/pci/sonicvibes.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/sonicvibes.c 2004-12-12 17:40:53 -08:00 @@ -1185,6 +1185,7 @@ kfree_nocheck(sonic->res_dmac); } pci_release_regions(sonic->pci); + pci_disable_device(sonic->pci); kfree(sonic); return 0; } @@ -1216,12 +1217,15 @@ if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } sonic = kcalloc(1, sizeof(*sonic), GFP_KERNEL); - if (sonic == NULL) + if (sonic == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&sonic->reg_lock); sonic->card = card; sonic->pci = pci; @@ -1229,6 +1233,7 @@ if ((err = pci_request_regions(pci, "S3 SonicVibes")) < 0) { kfree(sonic); + pci_disable_device(pci); return err; } diff -Nru a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c --- a/sound/pci/trident/trident_main.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/trident/trident_main.c 2004-12-12 17:40:53 -08:00 @@ -3537,12 +3537,15 @@ if (pci_set_dma_mask(pci, 0x3fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x3fffffff) < 0) { snd_printk("architecture does not support 30bit PCI busmaster DMA\n"); + pci_disable_device(pci); return -ENXIO; } trident = kcalloc(1, sizeof(*trident), GFP_KERNEL); - if (trident == NULL) + if (trident == NULL) { + pci_disable_device(pci); return -ENOMEM; + } trident->device = (pci->vendor << 16) | pci->device; trident->card = card; trident->pci = pci; @@ -3564,6 +3567,7 @@ if ((err = pci_request_regions(pci, "Trident Audio")) < 0) { kfree(trident); + pci_disable_device(pci); return err; } trident->port = pci_resource_start(pci, 0); @@ -3682,6 +3686,7 @@ if (trident->irq >= 0) free_irq(trident->irq, (void *)trident); pci_release_regions(trident->pci); + pci_disable_device(trident->pci); kfree(trident); return 0; } @@ -3949,6 +3954,7 @@ case TRIDENT_DEVICE_ID_SI7018: break; } + pci_disable_device(trident->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c --- a/sound/pci/via82xx.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/via82xx.c 2004-12-12 17:40:53 -08:00 @@ -1980,6 +1980,7 @@ pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->old_legacy_cfg); } + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -2006,8 +2007,10 @@ if ((err = pci_enable_device(pci)) < 0) return err; - if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) + if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) { + pci_disable_device(pci); return -ENOMEM; + } chip->chip_type = chip_type; chip->revision = revision; @@ -2025,6 +2028,7 @@ if ((err = pci_request_regions(pci, card->driver)) < 0) { kfree(chip); + pci_disable_device(pci); return err; } chip->port = pci_resource_start(pci, 0); diff -Nru a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c --- a/sound/pci/vx222/vx222.c 2004-12-12 17:40:52 -08:00 +++ b/sound/pci/vx222/vx222.c 2004-12-12 17:40:52 -08:00 @@ -116,6 +116,7 @@ free_irq(chip->irq, (void*)chip); if (vx->port[0]) pci_release_regions(vx->pci); + pci_disable_device(vx->pci); kfree(chip); return 0; } @@ -147,8 +148,10 @@ vx_ops = hw->type == VX_TYPE_BOARD ? &vx222_old_ops : &vx222_ops; chip = snd_vx_create(card, hw, vx_ops, sizeof(struct snd_vx222) - sizeof(vx_core_t)); - if (! chip) + if (! chip) { + pci_disable_device(pci); return -ENOMEM; + } vx = (struct snd_vx222 *)chip; vx->pci = pci; diff -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c --- a/sound/pci/ymfpci/ymfpci_main.c 2004-12-12 17:40:53 -08:00 +++ b/sound/pci/ymfpci/ymfpci_main.c 2004-12-12 17:40:53 -08:00 @@ -2098,6 +2098,7 @@ pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -2153,6 +2154,7 @@ chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_disable_dsp(chip); + pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0; } @@ -2204,8 +2206,10 @@ return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } chip->old_legacy_ctrl = old_legacy_ctrl; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->voice_lock);