http://linux.bkbits.net/linux-2.5 torvalds@ppc970.osdl.org|ChangeSet|20050123190959|48791 torvalds # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/01/23 11:09:59-08:00 torvalds@ppc970.osdl.org # x86-64: don't crash and loop when the user passes an unknown earlyprintk= option. # # Signed-off-by: Andi Kleen # Signed-off-by: Linus Torvalds # # arch/x86_64/kernel/early_printk.c # 2005/01/23 11:09:52-08:00 torvalds@ppc970.osdl.org +0 -3 # x86-64: don't crash and loop when the user passes an unknown earlyprintk= option. # # ChangeSet # 2005/01/23 10:29:42-08:00 kaos@ocs.com.au # [PATCH] fix module kallsym lookup breakage # # Anton Blanchard wrote: # >Your recent patch looks to break module kallsyms lookups.... # >It looks like if CONFIG_KALLSYMS_ALL is set then we never look up module # >addresses. # # Separate lookups for kernel and modules when CONFIG_KALLSYMS_ALL=y. # # Signed-off-by: Keith Owens # Acked-by: Chris Wedgwood # Signed-off-by: Linus Torvalds # # kernel/kallsyms.c # 2005/01/10 05:42:42-08:00 kaos@ocs.com.au +9 -1 # fix module kallsym lookup breakage # # ChangeSet # 2005/01/23 10:29:27-08:00 ak@suse.de # [PATCH] x86-64: Fix UP build warning # # Fix warning: # # In file included from include/asm/numa.h:5, # from arch/x86_64/kernel/setup64.c:27: # include/asm/numnodes.h:6:1: warning: "NODES_SHIFT" redefined # In file included from include/linux/mmzone.h:13, # from include/linux/gfp.h:4, # from include/linux/slab.h:15, # from include/linux/percpu.h:4, # from include/linux/sched.h:33, # from arch/x86_64/kernel/setup64.c:11: # include/linux/numa.h:11:1: warning: this is the location of the previous definition # # in UP builds. # # Signed-off-by: Andi Kleen # Signed-off-by: Linus Torvalds # # include/asm-x86_64/numnodes.h # 2005/01/23 10:29:19-08:00 ak@suse.de +4 -0 # x86-64: Fix UP build warning # # ChangeSet # 2005/01/23 10:29:11-08:00 ak@suse.de # [PATCH] i386/x86-64: Fix ioremap off by one # # From Terence Ripperda # # When doing iounmap don't try to change_page_attr back the guard # page that ioremap added. # # Since the last round of change_page_attr changes this would # trigger an BUG because the reference count on the changed pages # wouldn't match up. # # The problem would be only visible on machines with >3GB of memory, # because only then the PCI memory hole is below end_pfn and # change_page_attr is used. # # Fixed for both i386 and x86-64. # # This was actually discovered&fixed by Andrea earlier, but I goofed up # while doing the last ioremap fixes merge and this change got lost. # Poor Terence had to debug it again. Sorry about that. # # cc: andrea@suse.de # Signed-off-by: Andi Kleen # Signed-off-by: Linus Torvalds # # arch/x86_64/mm/ioremap.c # 2005/01/23 10:29:03-08:00 ak@suse.de +2 -1 # i386/x86-64: Fix ioremap off by one # # arch/i386/mm/ioremap.c # 2005/01/23 10:29:03-08:00 ak@suse.de +2 -1 # i386/x86-64: Fix ioremap off by one # # ChangeSet # 2005/01/23 10:28:57-08:00 ak@suse.de # [PATCH] x86_64: Fix int3 trap # # Undo bogus change that was introduced with kprobes. It's not # really needed and it breaks some user applications because # it changes the signal for int 3 from SIGTRAP to SIGSEGV. # # Cc: # Signed-off-by: Andi Kleen # Signed-off-by: Linus Torvalds # # arch/x86_64/kernel/traps.c # 2005/01/23 10:28:47-08:00 ak@suse.de +1 -1 # x86_64: Fix int3 trap # # ChangeSet # 2005/01/22 19:46:13-08:00 davem@nuts.davemloft.net # [SPARC64]: Minor memmove refinements. # # - If dst/src are equal, memcpy can be used. # - Eliminate register writes which were unused # # Signed-off-by: David S. Miller # # arch/sparc64/lib/memmove.S # 2005/01/22 19:45:36-08:00 davem@nuts.davemloft.net +5 -7 # [SPARC64]: Minor memmove refinements. # # ChangeSet # 2005/01/22 19:42:06-08:00 davem@nuts.davemloft.net # [TG3]: Update driver version and reldate. # # Signed-off-by: David S. Miller # # drivers/net/tg3.c # 2005/01/22 19:41:32-08:00 davem@nuts.davemloft.net +2 -2 # [TG3]: Update driver version and reldate. # # ChangeSet # 2005/01/22 16:01:24-08:00 tony.luck@intel.com # [IA64] clean up loose ends from addition of efi_range_is_wc() # # Signed-off-by: Tony Luck # # drivers/char/drm/drm_vm.c # 2005/01/22 15:59:58-08:00 tony.luck@intel.com +3 -0 # need linux/efi.h to get efi_range_is_wc() # # arch/ia64/kernel/efi.c # 2005/01/22 15:59:24-08:00 tony.luck@intel.com +1 -0 # export efi_mem_attributes so users of efi_range_is_wc() can see it # # ChangeSet # 2005/01/22 15:56:39-08:00 tony.luck@intel.com # [IA64] irq handling cleanup # # Patch from Christoph Hellwig to: # - irq_desc and irq_to_vector machvecs. SN2 has it's own versions, # but they're the same as the generic ones # - kill do do_IRQ and use __do_IRQ directly everywhere # - kill dead X86 ifdefs # - move some variable declarations around in irq.c to recuce # of ifdefs # # Signed-off-by: Tony Luck # # include/asm-ia64/machvec_sn2.h # 2005/01/22 15:54:56-08:00 tony.luck@intel.com +0 -4 # ia64: irq handling cleanup # # include/asm-ia64/machvec_init.h # 2005/01/22 15:54:55-08:00 tony.luck@intel.com +0 -2 # ia64: irq handling cleanup # # include/asm-ia64/machvec.h # 2005/01/22 15:54:53-08:00 tony.luck@intel.com +0 -15 # ia64: irq handling cleanup # # include/asm-ia64/hw_irq.h # 2005/01/22 15:54:52-08:00 tony.luck@intel.com +2 -14 # ia64: irq handling cleanup # # arch/ia64/sn/kernel/irq.c # 2005/01/22 15:54:50-08:00 tony.luck@intel.com +0 -10 # ia64: irq handling cleanup # # arch/ia64/kernel/irq_ia64.c # 2005/01/22 15:54:49-08:00 tony.luck@intel.com +2 -4 # ia64: irq handling cleanup # # arch/ia64/kernel/irq.c # 2005/01/22 15:54:25-08:00 tony.luck@intel.com +7 -43 # ia64: irq handling cleanup # # ChangeSet # 2005/01/22 15:00:59-08:00 jbarnes@sgi.com # [IA64] remove superfluous layer from sn2 DMA API # # When I converted the sn2 code over to the new DMA API, I left the old routines # in place and added wrappers to call them from the generic DMA API functions. # This added an unnecessary level of obfuscation since the generic ia64 code # calls those functions when any of the old style PCI DMA API functions are # called. This patch rectifies the problem making the code much easier to # understand and hopefully a little more efficient (though I'm sure gcc was # already inlining things pretty well, there were a bunch of unnecessary checks # that I took this opportunity to remove). It also shrinks the size of the sn2 # pci_dma.c quite a bit. # # pci_dma.c | 480 +++++++++++++++++++----------------------------------------- # 1 files changed, 151 insertions(+), 329 deletions(-) # # Signed-off-by: Jesse Barnes # Signed-off-by: Tony Luck # # arch/ia64/sn/pci/pci_dma.c # 2005/01/22 14:59:35-08:00 jbarnes@sgi.com +151 -329 # remove superfluous layer from sn2 DMA API # # ChangeSet # 2005/01/22 14:58:21-08:00 jbarnes@sgi.com # [IA64] fix early SAL init for sn2 # # sn2 does early initialization of the SAL so it can use it for early console # support. Unfortunately, the loop to find the SAL entry point was buggy so # when we tried out new EFI and SAL system table layouts, the loop didn't # terminate. Here's the fix (doh!, use two different loop counters instead of # one and just return if we find the SAL entry point). # # Signed-off-by: Jesse Barnes # Signed-off-by: Tony Luck # # include/asm-ia64/sal.h # 2005/01/22 14:57:26-08:00 jbarnes@sgi.com +2 -0 # fix early SAL init for sn2 # # arch/ia64/sn/kernel/setup.c # 2005/01/22 14:57:15-08:00 jbarnes@sgi.com +5 -4 # fix early SAL init for sn2 # # ChangeSet # 2005/01/22 14:45:15-08:00 jbarnes@sgi.com # [IA64] new api efi_range_is_wc() # # Ok, here you go Tony. This one fixes the loop and also fixes drm_vm.c. All # of the bits aside from the efi.h bit are ia64 specific (either under # arch/ia64 or __ia64__), so your tree is probably the right place for all of # it. # # This patch adds efi_range_is_wc() to efi.h. It's used to determine whether an # address range can be mapped with the write coalescing attribute. It also # fixes up some ia64 specific callers to use the new routine instead of # unconditionally calling pgprot_writecombined, which can be dangerous if used # on ranges that don't support it. # # Signed-off-by: Jesse Barnes # Signed-off-by: Tony Luck # # include/linux/efi.h # 2005/01/22 14:43:57-08:00 jbarnes@sgi.com +21 -0 # new api efi_range_is_wc() # # drivers/video/fbmem.c # 2005/01/22 14:43:51-08:00 jbarnes@sgi.com +7 -2 # Use new efi_range_is_wc() api (inside #if ia64 code) # # drivers/char/drm/drm_vm.c # 2005/01/22 14:43:24-08:00 jbarnes@sgi.com +7 -2 # Use new efi_range_is_wc() api (inside #if ia64 code) # # arch/ia64/pci/pci.c # 2005/01/22 14:42:51-08:00 jbarnes@sgi.com +2 -1 # Use new efi_range_is_wc() api. # # ChangeSet # 2005/01/22 14:39:46-08:00 jes@trained-monkey.org # [IA64] fix PAL_PREFETCH_VISIBILITY call # # The following patch fixes the ia64_pal_prefetch_visibility function to # take a transaction type argument for either virtual or physical memory # as specified in the System Architechture Manual page 2:358. # # Signed-Off-By: Jes Sorensen # Signed-Off-By: Tony Luck # # include/asm-ia64/pal.h # 2005/01/22 14:38:52-08:00 jes@trained-monkey.org +17 -3 # fix PAL_PREFETCH_VISIBILITY call # # ChangeSet # 2005/01/22 14:35:36-08:00 eranian@hpl.hp.com # [IA64] entry.S: perfmon psr.pp fix # # Problem: # There exists a case where we stop monitoring, i.e. clear # psr.pp/dcr.pp, via IPI. This is when the stop is triggered # by a close(), either explicit in the application or implicit # via exit_files(). The IPI is necessary because at the time the # thread (controlling the context) issues a close() it may not run # on the CPU the context is bound to. Yet the call must succeed, # hence we need to propagate the call to the right CPU. # But what is the problem then? # Under IPI, we invoke a perfmon routine which clear the kernel # (live) kernel psr.pp bit and also dcr.pp. Then we return from # the function and execute the kernel exit path which restores # the interrupted state. Unfortunately, this restores the kernel # psr from ipsr which now contains a stale value. Therefore # monitoring in the kernel will be active even though we stopped it. # You cannot modify the "global" psr in an interrupt routine because # it will be systematically restored on the way back. # # Solution: # We need to patch ipsr.pp in the kernel exit path to reflect the # kernel value of the kernel psr.pp bit. This must be done only when # returning to kernel. # # The proposed patch does patch ipsr.pp such that it is identical # to psr.pp. The patch is subtle because the exit path does not have # a lot of free registers and also because we need to schedule for # a psr read. I had to shuffle things around a little bit. # # The patch is important because there will be another situation where # this problem can occur once we incorporate the support for event set # and multiplexing. In this configuration, you may be in the middle of # the idle loop and on a timer interrupt, you may stop monitoring. # Slightly different condition, yet same problem with ipsr.pp vs. psr.pp. # # # Changelog: # - update kernel exit path when returning to kernel to copy # psr.pp to ipsr.pp. This is necesary to ensure that if psr.pp # was modified during the kernel entry, the change is propagated # the the psr.pp of the of the interrupted thread. Psr.pp can # be modified as a consequence of an IPI under certain conditions, # such as when a system-wide context is closed from a remote CPU. # # Special thanks to David for reworking the patch to fit # into the enhanced exit path. # # signed-off-by: stephane eranian # Signed-off-by: Tony Luck # # arch/ia64/kernel/entry.S # 2005/01/22 14:32:20-08:00 eranian@hpl.hp.com +9 -5 # perfmon psr.pp fix # # ChangeSet # 2005/01/22 14:21:34-08:00 tony.luck@intel.com # [IA64] clean up ptrace corner cases # # Patch from yanmin.zhang@intel.com to fix up some corner cases # in ptrace. Many thanks to davidm for reviewing and improving. # # Signed-off-by: Tony Luck # # include/asm-ia64/unistd.h # 2005/01/22 14:19:22-08:00 tony.luck@intel.com +1 -1 # clean up ptrace corner cases # # arch/ia64/kernel/process.c # 2005/01/22 14:19:21-08:00 tony.luck@intel.com +1 -1 # clean up ptrace corner cases # # arch/ia64/kernel/ivt.S # 2005/01/22 14:19:19-08:00 tony.luck@intel.com +20 -5 # clean up ptrace corner cases # # arch/ia64/kernel/gate.S # 2005/01/22 14:19:18-08:00 tony.luck@intel.com +3 -1 # clean up ptrace corner cases # # arch/ia64/kernel/fsys.S # 2005/01/22 14:19:11-08:00 tony.luck@intel.com +3 -2 # clean up ptrace corner cases # # arch/ia64/kernel/entry.S # 2005/01/22 14:18:28-08:00 tony.luck@intel.com +19 -7 # clean up ptrace corner cases # # ChangeSet # 2005/01/22 13:50:44-08:00 tony.luck@intel.com # [IA64] mca.c: delete unused "return_to_sal" label # # Label is unused, and so the compiler generates a warning. # # Signed-off-by: Tony Luck # # arch/ia64/kernel/mca.c # 2005/01/22 13:48:51-08:00 tony.luck@intel.com +0 -2 # delete unused "return_to_sal" label # # ChangeSet # 2005/01/22 13:35:36-08:00 davidm@hpl.hp.com # [IA64] entry.S update the copyright year & fix a comment # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/kernel/entry.S # 2005/01/22 13:34:06-08:00 davidm@hpl.hp.com +2 -2 # update the copyright year & fix a comment # # ChangeSet # 2005/01/22 13:33:33-08:00 davidm@hpl.hp.com # [IA64] Use srlz.d instead of srlz.i in ia64_leave_syscall # # Use srlz.d instead of srlz.i. Safe because we don't care whether # the VHPT walker sees the clearing of PSR.ic (if it does, that's fine # if it doesn't, it's OK too since the kernel-text is pinned anyhow). # Good for another 11+ cycles in (normal) getpid(). # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/kernel/entry.S # 2005/01/22 13:31:53-08:00 davidm@hpl.hp.com +1 -1 # (ia64_leave_syscall): Use srlz.d instead of srlz.i # # ChangeSet # 2005/01/22 13:31:05-08:00 davidm@hpl.hp.com # [IA64] Improve ia64_leave_syscall() for McKinley-type cores. # # Optimize ia64_leave_syscall() a bit better for McKinley-type cores. # The patch looks big, but that's mostly due to renaming r16/r17 to r2/r3. # Good for a 13 cycle improvement. # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/kernel/entry.S # 2005/01/22 13:29:44-08:00 davidm@hpl.hp.com +51 -48 # Improve ia64_leave_syscall() for McKinley-type cores. # # ChangeSet # 2005/01/22 13:29:13-08:00 davidm@hpl.hp.com # [IA64] Resched skip_rbs_switch to run 4 cycles faster on McKinley-type cores # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/kernel/entry.S # 2005/01/22 13:28:01-08:00 davidm@hpl.hp.com +26 -16 # Resched skip_rbs_switch to run 4 cycles faster on McKinley-type cores # # ChangeSet # 2005/01/22 13:27:29-08:00 davidm@hpl.hp.com # [IA64] entry.S: Align rse_clear_invalid to double-bundle boundary. # # Trivial patch: align rse_clear_invalid to 32-byte boundary. Good for # a 9 cycle speed up. # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/kernel/entry.S # 2005/01/22 13:26:04-08:00 davidm@hpl.hp.com +1 -0 # Align rse_clear_invalid to double-bundle boundary. # # ChangeSet # 2005/01/22 13:25:31-08:00 davidm@hpl.hp.com # [IA64] Don't forget to initialize PKStk for kernel-threads # # Kernel-threads had both pUStk and pKStk set to FALSE, which was # unintentional. I don't think the bug has shown any ill effects, but # it's clearly wrong and could come around to bite us later, so let's # fix it now. Depends on the previous patch to clean up C usage of the # global/root-function predicates. # # Signed-off-by: Tony Luck # # arch/ia64/kernel/process.c # 2005/01/22 13:23:44-08:00 davidm@hpl.hp.com +3 -1 # Don't forget to initialize PKStk for kernel-threads # # ChangeSet # 2005/01/22 13:22:55-08:00 davidm@hpl.hp.com # [IA64] cleanup C uage of global/root-function predicates # # The patch below is purely a cleanup but it's a prerequisite for the # next bug fix patch. # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/kernel/unwind.c # 2005/01/22 13:20:30-08:00 davidm@hpl.hp.com +1 -3 # cleanup in preparation for speedup # # arch/ia64/kernel/ptrace.c # 2005/01/22 13:20:22-08:00 davidm@hpl.hp.com +2 -5 # cleanup in preparation for speedup # # arch/ia64/kernel/entry.h # 2005/01/22 13:19:53-08:00 davidm@hpl.hp.com +18 -7 # cleanup in preparation for speedup # # ChangeSet # 2005/01/22 13:16:18-08:00 nacc@us.ibm.com # [IA64] smpboot.c: use msleep(100) instead of inlined equivalent # # Use msleep() instead of schedule_timeout() to guarantee the task # delays as expected. # # Signed-off-by: Nishanth Aravamudan # Signed-off-by: Tony Luck # # arch/ia64/kernel/smpboot.c # 2005/01/22 13:13:47-08:00 nacc@us.ibm.com +1 -2 # use msleep(100) instead of inlined equivalent # # ChangeSet # 2005/01/22 13:09:59-08:00 rja@sgi.com # [IA64] increase limit on #pages to isolate for MCA errors # # The fixed sized array of pages that are isolated because of 2xECC # memory errors can run out. Increasing the size of the array is a # band-aid measure, the real fix will require changes to generic code # to add some bits to page_flags so that pages with errors can be # marked so as to prevent them ever being examined. # # Signed-off-by: Russ Anderson # Signed-off-by: Tony Luck # # arch/ia64/kernel/mca_drv.c # 2005/01/22 13:05:41-08:00 rja@sgi.com +1 -1 # increase limit on #pages to isolate for MCA errors # # ChangeSet # 2005/01/22 13:03:24-08:00 davidm@hpl.hp.com # [IA64] sys_ia32.c: add missing __user annotation for sparse # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/ia32/sys_ia32.c # 2005/01/22 13:01:53-08:00 davidm@hpl.hp.com +1 -1 # add missing __user annotation for sparse # # ChangeSet # 2005/01/22 12:59:23-08:00 kaos@sgi.com # [IA64] Sanity check unw_unwind_to_user # # Signed-off-by: Keith Owens # Signed-off-by: Tony Luck # # arch/ia64/kernel/unwind.c # 2005/01/22 12:57:36-08:00 kaos@sgi.com +4 -1 # Sanity check unw_unwind_to_user # # ChangeSet # 2005/01/22 12:51:34-08:00 davidm@hpl.hp.com # [IA64] domain.c: eliminate warning when compiling CONFIG_NUMA=n # # When compiling for non-NUMA variable "node" ended up not being used, # which solicits a warning from GCC. Fix is to evluate cpu_to_node(i) # in place. This has the effect of doing cpu_to_node(i) twice on NUMA, # but this is init code, so performance is not an issue (and even if # it were, you can just declare cpu_to_node() as being a pure function, # so the compiler can eliminate the second call). # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # arch/ia64/kernel/domain.c # 2005/01/22 12:48:48-08:00 davidm@hpl.hp.com +2 -3 # eliminate warning when compiling CONFIG_NUMA=n # # ChangeSet # 2005/01/22 12:46:27-08:00 davidm@hpl.hp.com # [IA64] uaccess.h: add missing __user annotation for sparse # # I was getting a lot of spurious warnings with "make C=1", due to a # missing "__user" attribute. I'm not sure whether this got lost or # whether earlier versions of sparse failed to warn about it, but it's # clearly needed (and the i386 version of uaccess.h does the same). # # Signed-off-by: David Mosberger-Tang # Signed-off-by: Tony Luck # # include/asm-ia64/uaccess.h # 2005/01/22 12:44:45-08:00 davidm@hpl.hp.com +1 -1 # add missing __user annotation for sparse # # ChangeSet # 2005/01/22 12:18:41-08:00 tony.luck@intel.com # [IA64] binfmt_elf32.c: BUG if insert_vm_struct fails # # It seems that in ia64_elf32_init, instead of calling return, if we insert # an overlapping vma, we should instead BUG(). We should never get into this # code path, because the vma's are set above PAGE_OFFSET, and thus a # Xmalicious user can not trigger this code path. This change is being # suggested mainly for clarity. Thanks to Stephen Tweedie for pointing out # that returning early in ia64_elf32_init could have unpredictable results. # # Signed-off-by: Tony Luck # # arch/ia64/ia32/binfmt_elf32.c # 2005/01/22 12:16:29-08:00 tony.luck@intel.com +3 -3 # BUG if insert_vm_struct fails # # ChangeSet # 2005/01/22 12:08:41-08:00 markgw@sgi.com # [IA64] fix SN2 hwperf error handling # # Fix the error handling for the SN2 hardware perf ioctl interface. # # Signed-off-by: Mark Goodwin # Signed-off-by: Tony Luck # # arch/ia64/sn/kernel/sn2/sn_hwperf.c # 2005/01/22 12:07:37-08:00 markgw@sgi.com +45 -1 # fix SN2 hwperf error handling # # ChangeSet # 2005/01/22 12:03:07-08:00 steiner@sgi.com # [IA64] Delete: arch/ia64/sn/include/shub.h # # Signed-off-by: Jack Steiner # Signed-off-by: Tony Luck # # BitKeeper/deleted/.del-shub.h~31fa7a1f3da74fcf # 2005/01/22 12:02:00-08:00 steiner@sgi.com +0 -0 # Delete: arch/ia64/sn/include/shub.h # # ChangeSet # 2005/01/22 11:57:39-08:00 steiner@sgi.com # [IA64] Delete duplicate SN2 definition of cpu_logical_id for UP build # # Signed-off-by: Jack Steiner # Signed-off-by: Tony Luck # # include/asm-ia64/sn/sn_cpuid.h # 2005/01/22 11:56:17-08:00 steiner@sgi.com +0 -1 # Delete duplicate SN2 definition of cpu_logical_id for UP build # # ChangeSet # 2005/01/22 11:50:47-08:00 bob.picco@hp.com # [IA64] fix declaration of __find_next_zero_bit, first arg is "const" # # Signed-off-by: Bob Picco # Signed-off-by: Tony Luck # # include/asm-ia64/bitops.h # 2005/01/22 11:49:20-08:00 bob.picco@hp.com +1 -1 # fix declaration of __find_next_zero_bit, first arg is "const" # # arch/ia64/lib/bitop.c # 2005/01/22 11:48:41-08:00 bob.picco@hp.com +1 -1 # fix definition of __find_next_zero_bit, first arg is "const" # # ChangeSet # 2005/01/22 11:37:01-08:00 js@linuxtv.org # [PATCH] dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # - [DVB] dvb-ttpci: re-added support for Fujitsu-Siemens DVB-S rev 1.6 0x13c2:0x0006 # - [DVB] dvb-ttpci: finally clean up debi irq/tasklet handling to make it work on SMP # - [DVB] dvb-ttpci: misc. changes to av7110_send_fw_cmd() error handling done along the way # - [DVB] dvb-ttpci: budgetpatch integrated into dvb-ttpci: enables full ts option running # in parallel with all previous functions of dvb-ttpci # - [DVB] dvb-ttpci: fix Oops provoked by insmod/rmmod test loop, patch by Emard # - [DVB] budget: Fixed start_ts_capture(): saa7146 will not issue a VPE interrupt # if VPE bit is set in PSR and VPE interrupts are enabled afterwards. # - [DVB] budget: enable satelco support. code was commented out, but actually it works, patch by Emard # - [DVB] budget: Budget patch improved driver, fixed slight packet loss by using different trigger mode # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # drivers/media/dvb/ttpci/budget.c # 2005/01/20 10:56:39-08:00 js@linuxtv.org +3 -3 # dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # drivers/media/dvb/ttpci/budget-patch.c # 2005/01/20 10:56:39-08:00 js@linuxtv.org +311 -35 # dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # drivers/media/dvb/ttpci/budget-core.c # 2005/01/20 10:56:39-08:00 js@linuxtv.org +13 -4 # dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # drivers/media/dvb/ttpci/av7110_v4l.c # 2005/01/20 10:56:39-08:00 js@linuxtv.org +2 -2 # dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # drivers/media/dvb/ttpci/av7110_hw.c # 2005/01/20 10:56:39-08:00 js@linuxtv.org +62 -30 # dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # drivers/media/dvb/ttpci/av7110.h # 2005/01/20 10:56:38-08:00 js@linuxtv.org +13 -1 # dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # drivers/media/dvb/ttpci/av7110.c # 2005/01/20 10:56:38-08:00 js@linuxtv.org +507 -85 # dvb: dvb-ttpci: fix SMP race, budget: fixe init race, misc fixes # # ChangeSet # 2005/01/22 11:36:47-08:00 js@linuxtv.org # [PATCH] dvb: nxt2002: add ATSC support, misc fixes # # - [DVB] mt352: exported a mt352_read_reg-function, implemented a single byte # write_register function (needed for dibusb) # - [DVB] nxt2002: patch by Taylor Jacob to add support for ATSC/VSB frontends # and the B2C2/BBTI Air2PC-ATSC card # - [DVB] stv0297: fix tuning problems and compile time warnings, patch by Markus Breitenberger # - [DVB] fix spelling errors in various frontend drivers # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # drivers/media/dvb/frontends/nxt2002.h # 2004/12/16 07:45:54-08:00 js@linuxtv.org +23 -0 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/tda80xx.c # 2004/11/18 06:58:34-08:00 js@linuxtv.org +1 -1 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/tda10021.h # 2005/01/20 10:56:38-08:00 js@linuxtv.org +1 -1 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/tda10021.c # 2005/01/20 10:56:38-08:00 js@linuxtv.org +1 -1 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/stv0297.h # 2004/12/17 13:00:18-08:00 js@linuxtv.org +3 -0 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/stv0297.c # 2005/01/20 10:56:38-08:00 js@linuxtv.org +63 -31 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/nxt2002.h # 2004/12/16 07:45:54-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/nxt2002.h # # drivers/media/dvb/frontends/nxt2002.c # 2004/12/16 07:45:54-08:00 js@linuxtv.org +670 -0 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/mt352.h # 2005/01/20 10:56:38-08:00 js@linuxtv.org +1 -0 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/mt352.c # 2005/01/20 10:56:38-08:00 js@linuxtv.org +18 -6 # dvb: nxt2002: add ATSC support, misc fixes # # drivers/media/dvb/frontends/nxt2002.c # 2004/12/16 07:45:54-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/frontends/nxt2002.c # # ChangeSet # 2005/01/22 11:36:33-08:00 js@linuxtv.org # [PATCH] dvb: dib3000 refactoring # # - [DVB] dib3000: driver refactoring, makes it easier to support device clones # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # drivers/media/dvb/frontends/dib3000mc_priv.h # 2005/01/20 10:56:38-08:00 js@linuxtv.org +23 -34 # dvb: dib3000 refactoring # # drivers/media/dvb/frontends/dib3000mc.c # 2005/01/20 10:56:38-08:00 js@linuxtv.org +300 -229 # dvb: dib3000 refactoring # # drivers/media/dvb/frontends/dib3000mb.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +27 -25 # dvb: dib3000 refactoring # # drivers/media/dvb/frontends/dib3000.h # 2005/01/20 10:56:37-08:00 js@linuxtv.org +10 -11 # dvb: dib3000 refactoring # # drivers/media/dvb/frontends/dib3000-common.h # 2005/01/20 10:56:37-08:00 js@linuxtv.org +11 -27 # dvb: dib3000 refactoring # # drivers/media/dvb/frontends/dib3000-common.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +1 -63 # dvb: dib3000 refactoring # # ChangeSet # 2005/01/22 11:36:18-08:00 js@linuxtv.org # [PATCH] dvb: add ATSC support, misc fixes # # - [DVB] dvb-core: vfree() checking cleanups, patch by Domen Puncer # - [DVB] dvb-core: fix handling of discontinuity indicator in section filter, # bug reported by Frank Rosengart # - [DVB] dvb-core: handle PUSI in section filter correctly, patch by Emard, # bug reported by Patrick Valsecchi # - [DVB] dvb-core: add support for ATSC/VSB frontends, patch by Taylor Jacob # - [DVB] dvb-core: removed semi-colon from a very wrong place; FE_ENABLE_HIGH_LNB_VOLTAGE # kernel oops; thanks to Christophe Massiot # - [DVB] dvb-core: Fixed slow tuning problems, remove frequeny bending support from # frontend code, code simplification # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # include/linux/dvb/version.h # 2004/12/17 13:00:18-08:00 js@linuxtv.org +1 -0 # dvb: add ATSC support, misc fixes # # include/linux/dvb/frontend.h # 2004/12/17 13:00:18-08:00 js@linuxtv.org +8 -3 # dvb: add ATSC support, misc fixes # # drivers/media/dvb/ttusb-dec/ttusb_dec.c # 2005/01/20 10:56:40-08:00 js@linuxtv.org +3 -3 # dvb: add ATSC support, misc fixes # # drivers/media/dvb/dvb-core/dvb_net.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +10 -4 # dvb: add ATSC support, misc fixes # # drivers/media/dvb/dvb-core/dvb_frontend.h # 2005/01/20 10:56:37-08:00 js@linuxtv.org +1 -22 # dvb: add ATSC support, misc fixes # # drivers/media/dvb/dvb-core/dvb_frontend.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +198 -147 # dvb: add ATSC support, misc fixes # # drivers/media/dvb/dvb-core/dvb_demux.h # 2005/01/20 10:56:37-08:00 js@linuxtv.org +1 -0 # dvb: add ATSC support, misc fixes # # drivers/media/dvb/dvb-core/dvb_demux.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +40 -18 # dvb: add ATSC support, misc fixes # # ChangeSet # 2005/01/22 11:36:05-08:00 js@linuxtv.org # [PATCH] dvb: support nxt2002 frontend, misc skystar2 fixes # # - [DVB] nxt2002: add support for nxt2002 frontend (firmware extraction, Kconfig, driver) # - [DVB] skystar2: misc cleanup, remove unneeded casts, remove unreachable # code, patches by Francois Romieu # - [DVB] skystar2: fix mt352 clock setting for VHF (6 and 7 MHz bw channels), # patch by Thomas Martin and Dieter Zander: # - [DVB] b2c2-usb-core: fix file permissions to be octal, ISO C90 compile fix, # temporally repaired the request_types # - [DVB] remove remains of dibusb driver after splitup # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # drivers/media/dvb/frontends/Makefile # 2004/12/17 13:00:17-08:00 js@linuxtv.org +2 -0 # dvb: support nxt2002 frontend, misc skystar2 fixes # # drivers/media/dvb/frontends/Kconfig # 2005/01/20 10:56:37-08:00 js@linuxtv.org +12 -0 # dvb: support nxt2002 frontend, misc skystar2 fixes # # drivers/media/dvb/b2c2/skystar2.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +195 -161 # dvb: support nxt2002 frontend, misc skystar2 fixes # # drivers/media/dvb/b2c2/b2c2-usb-core.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +12 -2 # dvb: support nxt2002 frontend, misc skystar2 fixes # # drivers/media/dvb/b2c2/Kconfig # 2004/12/17 13:00:17-08:00 js@linuxtv.org +4 -2 # dvb: support nxt2002 frontend, misc skystar2 fixes # # Documentation/dvb/get_dvb_firmware # 2004/12/17 13:00:17-08:00 js@linuxtv.org +19 -1 # dvb: support nxt2002 frontend, misc skystar2 fixes # # BitKeeper/deleted/.del-dvb-dibusb.c~44bff9a054ce6c32 # 2005/01/22 11:35:58-08:00 js@linuxtv.org +0 -0 # Delete: drivers/media/dvb/dibusb/dvb-dibusb.c # # ChangeSet # 2005/01/22 11:35:52-08:00 js@linuxtv.org # [PATCH] dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # - [DVB] dvb-dibusb: refactoring of the dibusb driver, support for device clones # from Yakumo/HAMA/Typhoon/HanfTek, update the documentation # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # drivers/media/dvb/dibusb/dvb-dibusb-usb.c # 2005/01/13 05:24:13-08:00 js@linuxtv.org +259 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb-remote.c # 2005/01/09 07:50:44-08:00 js@linuxtv.org +197 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb-pid.c # 2005/01/13 05:24:13-08:00 js@linuxtv.org +80 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb-firmware.c # 2005/01/07 03:49:57-08:00 js@linuxtv.org +85 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c # 2005/01/13 05:24:12-08:00 js@linuxtv.org +598 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb-dvb.c # 2005/01/13 05:24:12-08:00 js@linuxtv.org +205 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb.h # 2005/01/20 10:56:37-08:00 js@linuxtv.org +228 -258 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb-usb.c # 2005/01/13 05:24:13-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/dibusb/dvb-dibusb-usb.c # # drivers/media/dvb/dibusb/dvb-dibusb-remote.c # 2005/01/09 07:50:44-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/dibusb/dvb-dibusb-remote.c # # drivers/media/dvb/dibusb/dvb-dibusb-pid.c # 2005/01/13 05:24:13-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/dibusb/dvb-dibusb-pid.c # # drivers/media/dvb/dibusb/dvb-dibusb-firmware.c # 2005/01/07 03:49:57-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c # # drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c # 2005/01/13 05:24:12-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c # # drivers/media/dvb/dibusb/dvb-dibusb-dvb.c # 2005/01/13 05:24:12-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c # # drivers/media/dvb/dibusb/dvb-dibusb-core.c # 2005/01/13 05:24:12-08:00 js@linuxtv.org +471 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/Makefile # 2005/01/20 10:56:37-08:00 js@linuxtv.org +8 -0 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/Kconfig # 2005/01/20 10:56:37-08:00 js@linuxtv.org +9 -5 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # Documentation/dvb/README.dibusb # 2005/01/20 10:56:37-08:00 js@linuxtv.org +44 -16 # dvb: dibusb refactoring, support Yakumo/HAMA/Typhoon/HanfTek clones # # drivers/media/dvb/dibusb/dvb-dibusb-core.c # 2005/01/13 05:24:12-08:00 js@linuxtv.org +0 -0 # BitKeeper file /home/torvalds/v2.6/linux/drivers/media/dvb/dibusb/dvb-dibusb-core.c # # ChangeSet # 2005/01/22 11:35:38-08:00 js@linuxtv.org # [PATCH] dvb: support pinnacle pctv-sat, clean-ups # # - [DVB] dvb-bt8xx: add support for pinnacle pctv-sat, patch by Peter Hettkamp and Adam Szalkowski # - [DVB] dvb-bt8xx: minor code cleanups, patch by Arne Ahrend # - [DVB] dvb-bt8xx: make sure to compile all necessary frontend modules, remove misleading comment # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # drivers/media/dvb/bt8xx/dvb-bt8xx.h # 2005/01/20 10:56:37-08:00 js@linuxtv.org +6 -0 # dvb: support pinnacle pctv-sat, clean-ups # # drivers/media/dvb/bt8xx/dvb-bt8xx.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +80 -2 # dvb: support pinnacle pctv-sat, clean-ups # # drivers/media/dvb/bt8xx/Kconfig # 2005/01/20 10:56:37-08:00 js@linuxtv.org +2 -3 # dvb: support pinnacle pctv-sat, clean-ups # # ChangeSet # 2005/01/22 11:35:24-08:00 js@linuxtv.org # [PATCH] dvb: fix RPS init race # # - [DVB] saa7146: explicitely disable RPS tasks in saa7146_init_one() # # Signed-off-by: Michael Hunold # Signed-off-by: Johannes Stezenbach # Signed-off-by: Linus Torvalds # # drivers/media/common/saa7146_core.c # 2005/01/20 10:56:37-08:00 js@linuxtv.org +2 -2 # dvb: fix RPS init race # # ChangeSet # 2005/01/22 11:32:44-08:00 tony.luck@intel.com # [IA64] tiger_defconfig: updated for 2.6.11-rc2 # # Signed-off-by: Tony Luck # # arch/ia64/configs/tiger_defconfig # 2005/01/22 11:31:45-08:00 tony.luck@intel.com +48 -11 # updated for 2.6.11-rc2 # # ChangeSet # 2005/01/22 11:02:00-08:00 roland@redhat.com # [PATCH] PPC64: fix stack alignment for signal handlers # # The PPC64 ABI specifies that the stack should be kept aligned to 16 # bytes. However, signal handlers on PPC64 are getting run with the stack # misaligned (sp % 16 == 8). This patch fixes that by ensuring that the # signal frame allocated is a multiple of 16 bytes. # # In addition to the PPC64 signal frame itself being of misaligned size, # the explicit alignment of the starting stack pointer is also to 8 # instead of 16. I've corrected this as well, so signal frames are # aligned even if the interrupted registers contained a misaligned stack # pointer. # # Signed-off-by: Roland McGrath # # [ Paul Mackerras acked the original patch (which # also did it for the 32-bit cases), and pointed out that the 32-bit # cases all already did the alignment elsewhere and didn't need this. # Patch edited down accordingly. ] # # Signed-off-by: Linus Torvalds # # arch/ppc64/kernel/signal.c # 2005/01/21 16:00:00-08:00 roland@redhat.com +2 -2 # PPC64: fix stack alignment for signal handlers # # ChangeSet # 2005/01/22 10:31:39-08:00 nanhai.zou@intel.com # [PATCH] Fix an error in copy_page_range # # There is a bug in copy_page_range with 4 level page table change. # copy_page_range do a continue without adding pgds and addr when # pgd_none(*src_pgd) or pgd_bad(*src_pgd). # # Signed-off-by: Zou Nan hai # Acked-by: Nick Piggin # Signed-off-by: Linus Torvalds # # mm/memory.c # 2005/01/20 12:49:13-08:00 nanhai.zou@intel.com +3 -2 # Fix an error in copy_page_range # # ChangeSet # 2005/01/21 20:04:07-08:00 davem@nuts.davemloft.net # [SPARC64]: Update defconfig. # # Signed-off-by: David S. Miller # # arch/sparc64/defconfig # 2005/01/21 20:03:35-08:00 davem@nuts.davemloft.net +12 -5 # [SPARC64]: Update defconfig. # # ChangeSet # 2005/01/21 14:02:07-08:00 roland@topspin.com # [SPARC]: Hook up drivers/infiniband/Kconfig to sparc32. # # Signed-off-by: Roland Dreier # Signed-off-by: David S. Miller # # arch/sparc/Kconfig # 2005/01/21 14:01:27-08:00 roland@topspin.com +2 -0 # [SPARC]: Hook up drivers/infiniband/Kconfig to sparc32. # # ChangeSet # 2005/01/21 13:54:21-08:00 krzysztof.h1@wp.pl # [SPARC]: Fix asm constraints in muldiv.c # # Signed-off-by: David S. Miller # # arch/sparc/kernel/muldiv.c # 2005/01/21 13:53:45-08:00 krzysztof.h1@wp.pl +7 -4 # [SPARC]: Fix asm constraints in muldiv.c # # ChangeSet # 2005/01/21 13:42:18-08:00 davem@nuts.davemloft.net # Merge nuts.davemloft.net:/disk1/BK/sparcwork-2.6 # into nuts.davemloft.net:/disk1/BK/sparc-2.6 # # fs/binfmt_elf.c # 2005/01/21 13:42:06-08:00 davem@nuts.davemloft.net +0 -0 # Auto merged # # ChangeSet # 2005/01/21 12:26:19-08:00 pablo@eurodev.net # [NETLINK]: Move nl_nonroot into netlink_table. # # Signed-off-by: David S. Miller # # net/netlink/af_netlink.c # 2005/01/21 12:25:32-08:00 pablo@eurodev.net +3 -3 # [NETLINK]: Move nl_nonroot into netlink_table. # # ChangeSet # 2005/01/20 16:28:10-08:00 mchan@broadcom.com # [TG3]: add tg3_set_eeprom() # # - Add nvram size detection # - Add appropriate byte swapping to tg3_get_eeprom so that the same byte # stream is read in all systems # - Fix tg3_get_eeprom to read both eeprom and flash # - Add tg3_set_eeprom to write eeprom and flash # - Change tg3_nvram_init to detect all supported nvram devices # - Change tg3_nvram_read to properly detect Atmel flash that requires # address translation # - Increase nvram polling delay to account for slower eeprom devices # - Remove some of the flushing read that is not required for the # production 5750 devices # # Signed-off-by: Michael Chan # Signed-off-by: David S. Miller # # drivers/net/tg3.h # 2005/01/20 16:27:12-08:00 mchan@broadcom.com +46 -3 # [TG3]: add tg3_set_eeprom() # # drivers/net/tg3.c # 2005/01/20 16:27:12-08:00 mchan@broadcom.com +469 -45 # [TG3]: add tg3_set_eeprom() # # ChangeSet # 2005/01/20 13:24:38-08:00 davem@nuts.davemloft.net # Cset exclude: davem@nuts.davemloft.net|ChangeSet|20050120063740|10274 # # net/sched/sch_teql.c # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # net/sched/sch_generic.c # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # net/core/dev_mcast.c # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # net/core/dev.c # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # net/atm/clip.c # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # include/linux/netdevice.h # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/infiniband/ulp/ipoib/ipoib_main.c # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # Documentation/networking/netdevices.txt # 2005/01/20 13:24:32-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # net/core/pktgen.c # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # net/core/netpoll.c # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/net/tg3.h # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/net/tg3.c # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/net/sungem.h # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/net/sungem.c # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/net/e1000/e1000_main.c # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/net/e1000/e1000.h # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/infiniband/ulp/ipoib/ipoib_ib.c # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # drivers/infiniband/ulp/ipoib/ipoib.h # 2005/01/20 13:24:31-08:00 davem@nuts.davemloft.net +0 -0 # Exclude # # ChangeSet # 2005/01/19 17:18:08-08:00 tony.luck@intel.com # [IA64] two trivial build fixes for generic uniprocessor # # Patches supplied by Dann Frazier. # # Signed-off-by: Tony Luck # # arch/ia64/sn/kernel/irq.c # 2005/01/19 17:15:31-08:00 tony.luck@intel.com +2 -0 # set_irq_affinity_info() is only defined for SMP # # arch/ia64/sn/kernel/bte_error.c # 2005/01/19 17:15:06-08:00 tony.luck@intel.com +1 -0 # Need HZ defined for UP build. # # ChangeSet # 2005/01/18 15:23:25-08:00 rja@sgi.com # [IA64] contig.c save physical address of MCA save area # # Ashok Raj uncovered a problem while testing the MCA code # on a tiger box with contig memory. The virtual address # was getting saved instead of the physical address of the # MCA save area. This patch fixes that problem. # # Signed-off-by: Russ Anderson # Signed-off-by: Tony Luck # # arch/ia64/mm/contig.c # 2005/01/18 15:21:57-08:00 rja@sgi.com +1 -1 # save physical address of MCA save area # # ChangeSet # 2005/01/17 13:38:38-08:00 ecd@skynet.be # [SPARC64]: Missing user access return value checks in fs/binfmt_elf.c and fs/compat.c # # Signed-off-by: David S. Miller # # fs/compat_ioctl.c # 2005/01/17 13:37:56-08:00 ecd@skynet.be +12 -5 # [SPARC64]: Missing user access return value checks in fs/binfmt_elf.c and fs/compat.c # # fs/binfmt_elf.c # 2005/01/17 13:37:56-08:00 ecd@skynet.be +43 -19 # [SPARC64]: Missing user access return value checks in fs/binfmt_elf.c and fs/compat.c # diff -Nru a/Documentation/dvb/README.dibusb b/Documentation/dvb/README.dibusb --- a/Documentation/dvb/README.dibusb 2005-01-23 21:02:28 -08:00 +++ b/Documentation/dvb/README.dibusb 2005-01-23 21:02:28 -08:00 @@ -26,7 +26,7 @@ - HAMA DVB-T USB device http://www.hama.de/portal/articleId*110620/action*2598 -- CTS Portable (Chinese Television System) +- CTS Portable (Chinese Television System) (2) http://www.2cts.tv/ctsportable/ - Unknown USB DVB-T device with vendor ID Hyper-Paltek @@ -46,16 +46,16 @@ Others: ------- -- Ultima Electronic/Artec T1 USB TVBOX (AN2135 and AN2235) +- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner) http://82.161.246.249/products-tvbox.html -- Compro Videomate DVB-U2000 - DVB-T USB +- Compro Videomate DVB-U2000 - DVB-T USB (2) http://www.comprousa.com/products/vmu2000.htm - Grandtec USB DVB-T http://www.grand.com.tw/ -- Avermedia AverTV DVBT USB +- Avermedia AverTV DVBT USB (2) http://www.avermedia.com/ - DiBcom USB DVB-T reference device (non-public) @@ -63,16 +63,33 @@ Supported devices USB2.0 ======================== -- Twinhan MagicBox II +- Twinhan MagicBox II (2) http://www.twinhan.com/product_terrestrial_7.asp -- Yakumo DVB-T mobile +- Hanftek UMT-010 (1) + http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529 + +- Typhoon/Yakumo/HAMA DVB-T mobile USB2.0 (1) http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T +- Artec T1 USB TVBOX (FX2) (2) + - DiBcom USB2.0 DVB-T reference device (non-public) +1) It is working almost. +2) No test reports received yet. + 0. NEWS: + 2004-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb + - first almost working version for HanfTek UMT-010 + - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek + 2004-01-10 - refactoring completed, now everything is very delightful + - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a + Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich. + 2004-12-29 - after several days of struggling around bug of no returning URBs fixed. + 2004-12-26 - refactored the dibusb-driver, splitted into separate files + - i2c-probing enabled 2004-12-06 - possibility for demod i2c-address probing - new usb IDs (Compro,Artec) 2004-11-23 - merged changes from DiB3000MC_ver2.1 @@ -115,13 +132,15 @@ 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, 2.6.9 . +it is working with 2.6.7 and above. Linux 2.4.x support is not planned, but patches are very welcome. NOTE: I'm using Debian testing, so the following explaination (especially the hotplug-path) needn't match your system, but probably it will :). +The driver is included in the kernel since Linux 2.6.10. + 1.1. Firmware The USB driver needs to download a firmware to start working. @@ -155,9 +174,13 @@ first have a look, which debug level are available: modinfo dib3000mb +modinfo dib3000-common +modinfo dib3000mc modinfo dvb-dibusb +modprobe dib3000-common debug= modprobe dib3000mb debug= +modprobe dib3000mc debug= modprobe dvb-dibusb debug= should do the trick. @@ -168,13 +191,11 @@ At this point you should be able to start a dvb-capable application. For myself I used mplayer, dvbscan, tzap and kaxtv, they are working. Using the device -as a slave device in vdr, was not working for me. Some work has to be done -(patches and comments are very welcome). +in vdr (at least the USB2.0 one) is working. 2. Known problems and bugs -TODO: -- signal-quality and strength calculations +- none this time 2.1. Adding support for devices @@ -202,9 +223,10 @@ maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub. This is not enough for receiving the complete transport stream of a DVB-T channel (which can be about 16 MBit/s). Normally this is not a -problem, if you only want to watch TV, but watching a channel while -recording another channel on the same frequency simply does not work. -This applies to all USB1.1 DVB-T devices. +problem, if you only want to watch TV (this does not apply for HDTV), +but watching a channel while recording another channel on the same +frequency simply does not work. This applies to all USB1.1 DVB-T +devices, not only dibusb) A special problem of the dibusb for the USB1.1 is, that the USB control IC has a problem with write accesses while having MPEG2-streaming @@ -218,14 +240,20 @@ these features is maybe a solution. Additionally this behaviour of VDR exceeds the USB1.1 bandwidth. +Update: +For the USB1.1 and VDR some work has been done (patches and comments are still +very welcome). Maybe the problem is solved in the meantime because I now use +the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the +linux-dvb software filter is able to get the best of the garbled TS. + 2.3. Comments Patches, comments and suggestions are very very welcome 3. Acknowledgements 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. + providing specs, code and help, on which the dvb-dibusb, dib3000mb and + dib3000mc 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. diff -Nru a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware --- a/Documentation/dvb/get_dvb_firmware 2005-01-23 21:02:28 -08:00 +++ b/Documentation/dvb/get_dvb_firmware 2005-01-23 21:02:28 -08:00 @@ -21,7 +21,8 @@ use File::Temp qw/ tempdir /; use IO::Handle; -@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", "dec2540t", "dec3000s", "vp7041", "dibusb" ); +@components = ( "sp8870", "sp887x", "tda10045", "tda10046", "av7110", "dec2000t", + "dec2540t", "dec3000s", "vp7041", "dibusb", "nxt2002" ); # Check args syntax() if (scalar(@ARGV) != 1); @@ -231,6 +232,23 @@ verify($outfile,$hash); $outfile; +} + +sub nxt2002 { + my $sourcefile = "Broadband4PC_4_2_11.zip"; + my $url = "http://www.bbti.us/download/windows/$sourcefile"; + my $hash = "c6d2ea47a8f456d887ada0cfb718ff2a"; + my $outfile = "dvb-fe-nxt2002.fw"; + my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); + + checkstandard(); + + wgetfile($sourcefile, $url); + unzip($sourcefile, $tmpdir); + verify("$tmpdir/SkyNETU.sys", $hash); + extract("$tmpdir/SkyNETU.sys", 375832, 5908, $outfile); + + $outfile; } # --------------------------------------------------------------- diff -Nru a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt --- a/Documentation/networking/netdevices.txt 2005-01-23 21:02:28 -08:00 +++ b/Documentation/networking/netdevices.txt 2005-01-23 21:02:28 -08:00 @@ -45,9 +45,10 @@ Synchronization: dev->xmit_lock spinlock. When the driver sets NETIF_F_LLTX in dev->features this will be called without holding xmit_lock. In this case the driver - has to execute it's transmission routine in a completely lockless - manner. It is recommended only for queueless devices such - loopback and tunnels. + has to lock by itself when needed. It is recommended to use a try lock + for this and return -1 when the spin lock fails. + The locking there should also properly protect against + set_multicast_list Context: BHs disabled Notes: netif_queue_stopped() is guaranteed false Return codes: @@ -55,6 +56,8 @@ o NETDEV_TX_BUSY Cannot transmit packet, try later Usually a bug, means queue start/stop flow control is broken in the driver. Note: the driver must NOT put the skb in its DMA ring. + o NETDEV_TX_LOCKED Locking failed, please retry quickly. + Only valid when NETIF_F_LLTX is set. dev->tx_timeout: Synchronization: dev->xmit_lock spinlock. diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c --- a/arch/i386/mm/ioremap.c 2005-01-23 21:02:28 -08:00 +++ b/arch/i386/mm/ioremap.c 2005-01-23 21:02:28 -08:00 @@ -238,8 +238,9 @@ } if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) { + /* p->size includes the guard page, but cpa doesn't like that */ change_page_attr(virt_to_page(__va(p->phys_addr)), - p->size >> PAGE_SHIFT, + (p->size - PAGE_SIZE) >> PAGE_SHIFT, PAGE_KERNEL); global_flush_tlb(); } diff -Nru a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig --- a/arch/ia64/configs/tiger_defconfig 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/configs/tiger_defconfig 2005-01-23 21:02:28 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10-rc1 -# Tue Nov 2 11:35:10 2004 +# Linux kernel version: 2.6.11-rc2 +# Sat Jan 22 11:17:02 2005 # # @@ -59,12 +59,14 @@ CONFIG_64BIT=y CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_TIME_INTERPOLATION=y CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y # CONFIG_IA64_GENERIC is not set CONFIG_IA64_DIG=y # CONFIG_IA64_HP_ZX1 is not set +# CONFIG_IA64_HP_ZX1_SWIOTLB is not set # CONFIG_IA64_SGI_SN2 is not set # CONFIG_IA64_HP_SIM is not set # CONFIG_ITANIUM is not set @@ -76,6 +78,7 @@ CONFIG_IA64_L1_CACHE_SHIFT=7 # CONFIG_NUMA is not set CONFIG_VIRTUAL_MEM_MAP=y +CONFIG_HOLES_IN_ZONE=y CONFIG_IA64_CYCLONE=y CONFIG_IOSAPIC=y CONFIG_FORCE_MAX_ZONEORDER=18 @@ -89,6 +92,7 @@ CONFIG_IA64_MCA_RECOVERY=y CONFIG_PERFMON=y CONFIG_IA64_PALINFO=y +CONFIG_ACPI_DEALLOCATE_IRQ=y # # Firmware Drivers @@ -110,8 +114,10 @@ CONFIG_ACPI_BOOT=y CONFIG_ACPI_INTERPRETER=y CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_VIDEO is not set CONFIG_ACPI_FAN=m CONFIG_ACPI_PROCESSOR=m +# CONFIG_ACPI_HOTPLUG_CPU is not set CONFIG_ACPI_THERMAL=m CONFIG_ACPI_BLACKLIST_YEAR=0 # CONFIG_ACPI_DEBUG is not set @@ -119,6 +125,7 @@ CONFIG_ACPI_POWER=y CONFIG_ACPI_PCI=y CONFIG_ACPI_SYSTEM=y +# CONFIG_ACPI_CONTAINER is not set # # Bus options (PCI, PCMCIA) @@ -137,7 +144,6 @@ CONFIG_HOTPLUG_PCI_ACPI=m # CONFIG_HOTPLUG_PCI_ACPI_IBM is not set # CONFIG_HOTPLUG_PCI_CPCI is not set -# CONFIG_HOTPLUG_PCI_PCIE is not set # CONFIG_HOTPLUG_PCI_SHPC is not set # @@ -174,6 +180,7 @@ # # Plug and Play support # +# CONFIG_PNP is not set # # Block devices @@ -182,12 +189,14 @@ # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set # CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=m +CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_INITRAMFS_SOURCE="" # CONFIG_CDROM_PKTCDVD is not set @@ -199,6 +208,7 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set # # ATA/ATAPI/MFM/RLL support @@ -285,6 +295,7 @@ # CONFIG_SCSI_SPI_ATTRS=y CONFIG_SCSI_FC_ATTRS=y +# CONFIG_SCSI_ISCSI_ATTRS is not set # # SCSI low-level drivers @@ -325,7 +336,6 @@ CONFIG_SCSI_QLA2300=m CONFIG_SCSI_QLA2322=m # CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA6322 is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_DEBUG is not set @@ -342,6 +352,7 @@ CONFIG_MD_RAID5=m CONFIG_MD_RAID6=m CONFIG_MD_MULTIPATH=m +# CONFIG_MD_FAULTY is not set CONFIG_BLK_DEV_DM=m CONFIG_DM_CRYPT=m CONFIG_DM_SNAPSHOT=m @@ -392,6 +403,7 @@ # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -471,7 +483,6 @@ # CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set CONFIG_EEPRO100=m -# CONFIG_EEPRO100_PIO is not set CONFIG_E100=m # CONFIG_E100_NAPI is not set # CONFIG_FEALNX is not set @@ -564,12 +575,13 @@ # CONFIG_GAMEPORT_EMU10K1 is not set # CONFIG_GAMEPORT_VORTEX is not set # CONFIG_GAMEPORT_FM801 is not set -# CONFIG_GAMEPORT_CS461x is not set +# CONFIG_GAMEPORT_CS461X is not set CONFIG_SERIO=y CONFIG_SERIO_I8042=y # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y # CONFIG_SERIO_RAW is not set # @@ -598,6 +610,8 @@ CONFIG_SERIAL_NONSTANDARD=y # CONFIG_ROCKETPORT is not set # CONFIG_CYCLADES is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_ISI is not set # CONFIG_SYNCLINK is not set # CONFIG_SYNCLINKMP is not set # CONFIG_N_HDLC is not set @@ -645,7 +659,7 @@ # CONFIG_AGP=m CONFIG_AGP_I460=m -CONFIG_DRM=y +CONFIG_DRM=m CONFIG_DRM_TDFX=m CONFIG_DRM_R128=m CONFIG_DRM_RADEON=m @@ -691,6 +705,7 @@ # CONFIG_VGA_CONSOLE=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -722,6 +737,7 @@ # CONFIG_USB_EHCI_ROOT_HUB_TT is not set CONFIG_USB_OHCI_HCD=m CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_SL811_HCD is not set # # USB Device Class drivers @@ -729,6 +745,10 @@ # CONFIG_USB_BLUETOOTH_TTY is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set + +# +# 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 is not set @@ -762,7 +782,6 @@ # # CONFIG_USB_MDC800 is not set # CONFIG_USB_MICROTEK is not set -# CONFIG_USB_HPUSBSCSI is not set # # USB Multimedia devices @@ -774,7 +793,7 @@ # # -# USB Network adaptors +# USB Network Adapters # # CONFIG_USB_CATC is not set # CONFIG_USB_KAWETH is not set @@ -796,7 +815,6 @@ # # CONFIG_USB_EMI62 is not set # CONFIG_USB_EMI26 is not set -# CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_LEGOTOWER is not set @@ -805,6 +823,7 @@ # CONFIG_USB_CYTHERM is not set # CONFIG_USB_PHIDGETKIT is not set # CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_IDMOUSE is not set # CONFIG_USB_TEST is not set # @@ -817,6 +836,16 @@ # CONFIG_USB_GADGET is not set # +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# # File systems # CONFIG_EXT2_FS=y @@ -927,7 +956,7 @@ CONFIG_CIFS=m # CONFIG_CIFS_STATS is not set # CONFIG_CIFS_XATTR is not set -# CONFIG_CIFS_POSIX is not set +# CONFIG_CIFS_EXPERIMENTAL is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -1002,6 +1031,8 @@ # CONFIG_CRC_CCITT is not set CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y # # Profiling support @@ -1019,6 +1050,7 @@ # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_FS is not set CONFIG_IA64_GRANULE_16MB=y # CONFIG_IA64_GRANULE_64MB is not set # CONFIG_IA64_PRINT_HAZARDS is not set @@ -1055,7 +1087,12 @@ # CONFIG_CRYPTO_TEA is not set # CONFIG_CRYPTO_ARC4 is not set # CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_MICHAEL_MIC is not set # CONFIG_CRYPTO_CRC32C is not set # CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff -Nru a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c --- a/arch/ia64/ia32/binfmt_elf32.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/ia32/binfmt_elf32.c 2005-01-23 21:02:28 -08:00 @@ -103,7 +103,7 @@ if (insert_vm_struct(current->mm, vma)) { kmem_cache_free(vm_area_cachep, vma); up_write(¤t->mm->mmap_sem); - return; + BUG(); } } up_write(¤t->mm->mmap_sem); @@ -130,7 +130,7 @@ if (insert_vm_struct(current->mm, vma)) { kmem_cache_free(vm_area_cachep, vma); up_write(¤t->mm->mmap_sem); - return; + BUG(); } } up_write(¤t->mm->mmap_sem); @@ -153,7 +153,7 @@ if (insert_vm_struct(current->mm, vma)) { kmem_cache_free(vm_area_cachep, vma); up_write(¤t->mm->mmap_sem); - return; + BUG(); } } up_write(¤t->mm->mmap_sem); diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/ia32/sys_ia32.c 2005-01-23 21:02:28 -08:00 @@ -2656,7 +2656,7 @@ info.si_signo = 0; set_fs (KERNEL_DS); ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, - uru ? &ru : NULL); + uru ? (struct rusage __user *) &ru : NULL); set_fs (old_fs); if (ret < 0 || info.si_signo == 0) diff -Nru a/arch/ia64/kernel/domain.c b/arch/ia64/kernel/domain.c --- a/arch/ia64/kernel/domain.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/domain.c 2005-01-23 21:02:28 -08:00 @@ -151,10 +151,9 @@ * Set up domains. Isolated domains just stay on the dummy domain. */ for_each_cpu_mask(i, cpu_default_map) { - int node = cpu_to_node(i); int group; struct sched_domain *sd = NULL, *p; - cpumask_t nodemask = node_to_cpumask(node); + cpumask_t nodemask = node_to_cpumask(cpu_to_node(i)); cpus_and(nodemask, nodemask, cpu_default_map); @@ -172,7 +171,7 @@ sd = &per_cpu(node_domains, i); *sd = SD_NODE_INIT; - sd->span = sched_domain_node_span(node); + sd->span = sched_domain_node_span(cpu_to_node(i)); sd->parent = p; cpus_and(sd->span, sd->span, cpu_default_map); #endif diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c --- a/arch/ia64/kernel/efi.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/efi.c 2005-01-23 21:02:28 -08:00 @@ -778,6 +778,7 @@ } return 0; } +EXPORT_SYMBOL(efi_mem_attributes); int valid_phys_addr_range (unsigned long phys_addr, unsigned long *size) diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S --- a/arch/ia64/kernel/entry.S 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/entry.S 2005-01-23 21:02:28 -08:00 @@ -3,7 +3,7 @@ * * Kernel entry points. * - * Copyright (C) 1998-2003 Hewlett-Packard Co + * Copyright (C) 1998-2003, 2005 Hewlett-Packard Co * David Mosberger-Tang * Copyright (C) 1999, 2002-2003 * Asit Mallick @@ -51,8 +51,11 @@ * setup a null register window frame. */ ENTRY(ia64_execve) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(3) - alloc loc1=ar.pfs,3,2,4,0 + /* + * Allocate 8 input registers since ptrace() may clobber them + */ + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc loc1=ar.pfs,8,2,4,0 mov loc0=rp .body mov out0=in0 // filename @@ -113,8 +116,11 @@ * u64 tls) */ GLOBAL_ENTRY(sys_clone2) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(6) - alloc r16=ar.pfs,6,2,6,0 + /* + * Allocate 8 input registers since ptrace() may clobber them + */ + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc r16=ar.pfs,8,2,6,0 DO_SAVE_SWITCH_STACK adds r2=PT(R16)+IA64_SWITCH_STACK_SIZE+16,sp mov loc0=rp @@ -142,8 +148,11 @@ * Deprecated. Use sys_clone2() instead. */ GLOBAL_ENTRY(sys_clone) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5) - alloc r16=ar.pfs,5,2,6,0 + /* + * Allocate 8 input registers since ptrace() may clobber them + */ + .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) + alloc r16=ar.pfs,8,2,6,0 DO_SAVE_SWITCH_STACK adds r2=PT(R16)+IA64_SWITCH_STACK_SIZE+16,sp mov loc0=rp @@ -633,10 +642,12 @@ * r13: restored (user-level thread pointer) * r14: cleared * r15: restored (syscall #) - * r16-r19: cleared + * r16-r17: cleared + * r18: user-level b6 + * r19: cleared * r20: user-level ar.fpsr * r21: user-level b0 - * r22: user-level b6 + * r22: cleared * r23: user-level ar.bspstore * r24: user-level ar.rnat * r25: user-level ar.unat @@ -661,7 +672,7 @@ * ar.csd: cleared * ar.ssd: cleared */ -GLOBAL_ENTRY(ia64_leave_syscall) +ENTRY(ia64_leave_syscall) PT_REGS_UNWIND_INFO(0) /* * work.need_resched etc. mustn't get changed by this CPU before it returns to @@ -690,79 +701,80 @@ (pUStk) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUStk #endif .work_processed_syscall: - adds r16=PT(LOADRS)+16,r12 - adds r17=PT(AR_BSPSTORE)+16,r12 + adds r2=PT(LOADRS)+16,r12 + adds r3=PT(AR_BSPSTORE)+16,r12 adds r18=TI_FLAGS+IA64_TASK_SIZE,r13 ;; (p6) ld4 r31=[r18] // load current_thread_info()->flags - ld8 r19=[r16],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs" - nop.i 0 + ld8 r19=[r2],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs" + mov b7=r0 // clear b7 ;; - ld8 r23=[r17],PT(R9)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage) - ld8 r22=[r16],PT(R8)-PT(B6) // load b6 + ld8 r23=[r3],PT(R9)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage) + ld8 r18=[r2],PT(R8)-PT(B6) // load b6 (p6) and r15=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE? ;; - - mov.m ar.ccv=r0 // clear ar.ccv + mov r16=ar.bsp // M2 get existing backing store pointer (p6) cmp4.ne.unc p6,p0=r15, r0 // any special work pending? (p6) br.cond.spnt .work_pending ;; // start restoring the state saved on the kernel stack (struct pt_regs): - ld8.fill r8=[r16],16 - ld8.fill r9=[r17],16 + ld8.fill r8=[r2],16 + ld8.fill r9=[r3],16 mov f6=f0 // clear f6 ;; - ld8.fill r10=[r16],16 - ld8.fill r11=[r17],16 + invala // M0|1 invalidate ALAT + rsm psr.i | psr.ic // M2 initiate turning off of interrupt and interruption collection + mov f9=f0 // clear f9 + + ld8.fill r10=[r2],16 + ld8.fill r11=[r3],16 mov f7=f0 // clear f7 ;; - ld8 r29=[r16],16 // load cr.ipsr - ld8 r28=[r17],16 // load cr.iip + ld8 r29=[r2],16 // load cr.ipsr + ld8 r28=[r3],16 // load cr.iip mov f8=f0 // clear f8 ;; - ld8 r30=[r16],16 // load cr.ifs - ld8 r25=[r17],16 // load ar.unat + ld8 r30=[r2],16 // M0|1 load cr.ifs + mov.m ar.ssd=r0 // M2 clear ar.ssd cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ;; - rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection - invala // invalidate ALAT - mov f9=f0 // clear f9 - - mov.m ar.ssd=r0 // clear ar.ssd - mov.m ar.csd=r0 // clear ar.csd + ld8 r25=[r3],16 // M0|1 load ar.unat + mov.m ar.csd=r0 // M2 clear ar.csd + mov r22=r0 // clear r22 + ;; + ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs +(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled mov f10=f0 // clear f10 ;; - ld8 r26=[r16],16 // load ar.pfs - ld8 r27=[r17],PT(PR)-PT(AR_RSC) // load ar.rsc + ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // load b0 + ld8 r27=[r3],PT(PR)-PT(AR_RSC) // load ar.rsc mov f11=f0 // clear f11 ;; - ld8 r24=[r16],PT(B0)-PT(AR_RNAT) // load ar.rnat (may be garbage) - ld8 r31=[r17],PT(R1)-PT(PR) // load predicates + ld8 r24=[r2],PT(AR_FPSR)-PT(AR_RNAT) // load ar.rnat (may be garbage) + ld8 r31=[r3],PT(R1)-PT(PR) // load predicates (pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 ;; - ld8 r21=[r16],PT(R12)-PT(B0) // load b0 - ld8.fill r1=[r17],16 // load r1 -(pUStk) mov r3=1 - ;; - ld8.fill r12=[r16],16 - ld8.fill r13=[r17],16 - mov r2=r0 // clear r2 + ld8 r20=[r2],PT(R12)-PT(AR_FPSR) // load ar.fpsr + ld8.fill r1=[r3],16 // load r1 +(pUStk) mov r17=1 ;; - ld8 r20=[r16] // load ar.fpsr - ld8.fill r15=[r17] // load r15 - mov b7=r0 // clear b7 + srlz.d // M0 ensure interruption collection is off + ld8.fill r13=[r3],16 + nop.i 0 ;; -(pUStk) st1 [r14]=r3 - addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 + ld8.fill r12=[r2] // restore r12 (sp) + ld8.fill r15=[r3] // restore r15 + addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0 + ;; +(pUStk) ld4 r3=[r3] // r3 = cpu_data->phys_stacked_size_p8 +(pUStk) st1 [r14]=r17 + mov b6=r18 // I0 restore b6 ;; - mov r16=ar.bsp // get existing backing store pointer - srlz.i // ensure interruption collection is off + shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition mov r14=r0 // clear r14 - ;; - ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 - mov b6=r22 // restore b6 - shr.u r18=r19,16 // get byte size of existing "dirty" partition (pKStk) br.cond.dpnt.many skip_rbs_switch + + mov.m ar.ccv=r0 // clear ar.ccv (pNonSys) br.cond.dpnt.many dont_preserve_current_frame br.cond.sptk.many rbs_switch END(ia64_leave_syscall) @@ -883,12 +895,16 @@ srlz.i // ensure interruption collection is off mov ar.ccv=r15 ;; + ldf.fill f11=[r2] bsw.0 // switch back to bank 0 (no stop bit required beforehand...) ;; - ldf.fill f11=[r2] -(pUStk) mov r18=IA64_KR(CURRENT) // Itanium 2: 12 cycle read latency +(pUStk) mov r18=IA64_KR(CURRENT)// M2 (12 cycle read latency) adds r16=PT(CR_IPSR)+16,r12 adds r17=PT(CR_IIP)+16,r12 + +(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled + nop.i 0 + nop.i 0 ;; ld8 r29=[r16],16 // load cr.ipsr ld8 r28=[r17],16 // load cr.iip @@ -901,7 +917,7 @@ cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs ;; ld8 r24=[r16],16 // load ar.rnat (may be garbage) - ld8 r23=[r17],16// load ar.bspstore (may be garbage) + ld8 r23=[r17],16 // load ar.bspstore (may be garbage) ;; ld8 r31=[r16],16 // load predicates ld8 r21=[r17],16 // load b0 @@ -971,6 +987,7 @@ shladd in0=loc1,3,r17 mov in1=0 ;; + .align 32 rse_clear_invalid: #ifdef CONFIG_ITANIUM // cycle 0 @@ -1031,23 +1048,33 @@ loadrs ;; skip_rbs_switch: -(pLvSys) mov r19=r0 // clear r19 for leave_syscall, no-op otherwise - mov b0=r21 - mov ar.pfs=r26 -(pUStk) mov ar.bspstore=r23 -(p9) mov cr.ifs=r30 -(pLvSys)mov r16=r0 // clear r16 for leave_syscall, no-op otherwise - mov cr.ipsr=r29 - mov ar.fpsr=r20 -(pLvSys)mov r17=r0 // clear r17 for leave_syscall, no-op otherwise - mov cr.iip=r28 - ;; -(pUStk) mov ar.rnat=r24 // must happen with RSE in lazy mode -(pLvSys)mov r18=r0 // clear r18 for leave_syscall, no-op otherwise - mov ar.rsc=r27 - mov ar.unat=r25 - mov pr=r31,-1 - rfi + mov ar.unat=r25 // M2 +(pKStk) extr.u r22=r22,21,1 // I0 extract current value of psr.pp from r22 +(pLvSys)mov r19=r0 // A clear r19 for leave_syscall, no-op otherwise + ;; +(pUStk) mov ar.bspstore=r23 // M2 +(pKStk) dep r29=r22,r29,21,1 // I0 update ipsr.pp with psr.pp +(pLvSys)mov r16=r0 // A clear r16 for leave_syscall, no-op otherwise + ;; + mov cr.ipsr=r29 // M2 + mov ar.pfs=r26 // I0 +(pLvSys)mov r17=r0 // A clear r17 for leave_syscall, no-op otherwise + +(p9) mov cr.ifs=r30 // M2 + mov b0=r21 // I0 +(pLvSys)mov r18=r0 // A clear r18 for leave_syscall, no-op otherwise + + mov ar.fpsr=r20 // M2 + mov cr.iip=r28 // M2 + nop 0 + ;; +(pUStk) mov ar.rnat=r24 // M2 must happen with RSE in lazy mode + nop 0 +(pLvSys)mov r2=r0 + + mov ar.rsc=r27 // M2 + mov pr=r31,-1 // I0 + rfi // B /* * On entry: @@ -1198,7 +1225,10 @@ ENTRY(sys_rt_sigreturn) PT_REGS_UNWIND_INFO(0) - alloc r2=ar.pfs,0,0,1,0 + /* + * Allocate 8 input registers since ptrace() may clobber them + */ + alloc r2=ar.pfs,8,0,1,0 .prologue PT_REGS_SAVES(16) adds sp=-16,sp diff -Nru a/arch/ia64/kernel/entry.h b/arch/ia64/kernel/entry.h --- a/arch/ia64/kernel/entry.h 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/entry.h 2005-01-23 21:02:28 -08:00 @@ -1,14 +1,25 @@ #include /* - * Preserved registers that are shared between code in ivt.S and entry.S. Be - * careful not to step on these! + * Preserved registers that are shared between code in ivt.S and + * entry.S. Be careful not to step on these! */ -#define pLvSys p1 /* set 1 if leave from syscall; otherwise, set 0 */ -#define pKStk p2 /* will leave_{kernel,syscall} return to kernel-stacks? */ -#define pUStk p3 /* will leave_{kernel,syscall} return to user-stacks? */ -#define pSys p4 /* are we processing a (synchronous) system call? */ -#define pNonSys p5 /* complement of pSys */ +#define PRED_LEAVE_SYSCALL 1 /* TRUE iff leave from syscall */ +#define PRED_KERNEL_STACK 2 /* returning to kernel-stacks? */ +#define PRED_USER_STACK 3 /* returning to user-stacks? */ +#define PRED_SYSCALL 4 /* inside a system call? */ +#define PRED_NON_SYSCALL 5 /* complement of PRED_SYSCALL */ + +#ifdef __ASSEMBLY__ +# define PASTE2(x,y) x##y +# define PASTE(x,y) PASTE2(x,y) + +# define pLvSys PASTE(p,PRED_LEAVE_SYSCALL) +# define pKStk PASTE(p,PRED_KERNEL_STACK) +# define pUStk PASTE(p,PRED_USER_STACK) +# define pSys PASTE(p,PRED_SYSCALL) +# define pNonSys PASTE(p,PRED_NON_SYSCALL) +#endif #define PT(f) (IA64_PT_REGS_##f##_OFFSET) #define SW(f) (IA64_SWITCH_STACK_##f##_OFFSET) diff -Nru a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S --- a/arch/ia64/kernel/fsys.S 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/fsys.S 2005-01-23 21:02:28 -08:00 @@ -612,8 +612,9 @@ ;; mov rp=r2 // set the real return addr tbit.z p8,p0=r3,TIF_SYSCALL_TRACE - -(p8) br.call.sptk.many b6=b6 // ignore this return addr + ;; +(p10) br.cond.spnt.many ia64_ret_from_syscall // p10==true means out registers are more than 8 +(p8) br.call.sptk.many b6=b6 // ignore this return addr br.cond.sptk ia64_trace_syscall END(fsys_bubble_down) diff -Nru a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S --- a/arch/ia64/kernel/gate.S 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/gate.S 2005-01-23 21:02:28 -08:00 @@ -81,6 +81,7 @@ LOAD_FSYSCALL_TABLE(r14) mov r16=IA64_KR(CURRENT) // 12 cycle read latency + tnat.nz p10,p9=r15 mov r19=NR_syscalls-1 ;; shladd r18=r17,3,r14 @@ -119,7 +120,8 @@ #endif mov r10=-1 - mov r8=ENOSYS +(p10) mov r8=EINVAL +(p9) mov r8=ENOSYS FSYS_RETURN END(__kernel_syscall_via_epc) diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/irq.c 2005-01-23 21:02:28 -08:00 @@ -32,35 +32,7 @@ printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id()); } -/* - * do_IRQ handles all normal device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - */ -unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs) -{ - return __do_IRQ(irq, regs); -} - -#ifdef CONFIG_SMP -/* - * This is updated when the user sets irq affinity via /proc - */ -cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; -static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)]; -#endif - #ifdef CONFIG_IA64_GENERIC -irq_desc_t * __ia64_irq_desc (unsigned int irq) -{ - return irq_desc + irq; -} - -ia64_vector __ia64_irq_to_vector (unsigned int irq) -{ - return (ia64_vector) irq; -} - unsigned int __ia64_local_vector_to_irq (ia64_vector vec) { return (unsigned int) vec; @@ -113,27 +85,19 @@ seq_putc(p, '\n'); skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } else if (i == NR_IRQS) { -#if defined(CONFIG_X86_LOCAL_APIC) - seq_puts(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", - irq_stat[j].apic_timer_irqs); - seq_putc(p, '\n'); -#endif + } else if (i == NR_IRQS) seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); -#if defined(CONFIG_X86_IO_APIC) - seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); -#endif - } return 0; } #ifdef CONFIG_SMP +/* + * This is updated when the user sets irq affinity via /proc + */ +cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS]; +static unsigned long pending_irq_redir[BITS_TO_LONGS(NR_IRQS)]; static cpumask_t irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL }; - static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; void set_irq_affinity_info (unsigned int irq, int hwid, int redir) @@ -250,7 +214,7 @@ for (irq=0; irq < NR_IRQS; irq++) { if (vectors_in_migration[irq]) { vectors_in_migration[irq]=0; - do_IRQ(irq, NULL); + __do_IRQ(irq, NULL); } } diff -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c --- a/arch/ia64/kernel/irq_ia64.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/irq_ia64.c 2005-01-23 21:02:28 -08:00 @@ -90,8 +90,6 @@ printk(KERN_WARNING "%s: double free!\n", __FUNCTION__); } -extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs); - #ifdef CONFIG_SMP # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) #else @@ -150,7 +148,7 @@ ia64_setreg(_IA64_REG_CR_TPR, vector); ia64_srlz_d(); - do_IRQ(local_vector_to_irq(vector), regs); + __do_IRQ(local_vector_to_irq(vector), regs); /* * Disable interrupts and send EOI: @@ -201,7 +199,7 @@ * Probably could shared code. */ vectors_in_migration[local_vector_to_irq(vector)]=0; - do_IRQ(local_vector_to_irq(vector), NULL); + __do_IRQ(local_vector_to_irq(vector), NULL); /* * Disable interrupts and send EOI diff -Nru a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S --- a/arch/ia64/kernel/ivt.S 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/ivt.S 2005-01-23 21:02:28 -08:00 @@ -51,6 +51,7 @@ #include #include #include +#include #if 1 # define PSR_DEFAULT_BITS psr.ac @@ -732,10 +733,12 @@ ssm psr.ic | PSR_DEFAULT_BITS ;; srlz.i // guarantee that interruption collection is on + mov r3=NR_syscalls - 1 ;; (p15) ssm psr.i // restore psr.i + // p10==true means out registers are more than 8 or r15's Nat is true +(p10) br.cond.spnt.many ia64_ret_from_syscall ;; - mov r3=NR_syscalls - 1 movl r16=sys_call_table adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024 @@ -836,8 +839,11 @@ * On exit: * - executing on bank 1 registers * - psr.ic enabled, interrupts restored + * - p10: TRUE if syscall is invoked with more than 8 out + * registers or r15's Nat is true * - r1: kernel's gp * - r3: preserved (same as on entry) + * - r8: -EINVAL if p10 is true * - r12: points to kernel stack * - r13: points to current task * - p15: TRUE if interrupts need to be re-enabled @@ -871,12 +877,17 @@ ;; st8 [r16]=r19,PT(AR_RNAT)-PT(CR_IFS) // store ar.pfs.pfm in cr.ifs + extr.u r11=r19,7,7 // I0 // get sol of ar.pfs + and r8=0x7f,r19 // A // get sof of ar.pfs + st8 [r17]=r27,PT(AR_BSPSTORE)-PT(AR_RSC)// save ar.rsc + tbit.nz p15,p0=r29,IA64_PSR_I_BIT // I0 (p9) mov in1=-1 + ;; (pUStk) sub r18=r18,r22 // r18=RSE.ndirty*8 - tbit.nz p15,p0=r29,IA64_PSR_I_BIT tnat.nz p10,p0=in2 + add r11=8,r11 ;; (pKStk) adds r16=PT(PR)-PT(AR_RNAT),r16 // skip over ar_rnat field (pKStk) adds r17=PT(B0)-PT(AR_BSPSTORE),r17 // skip over ar_bspstore field @@ -904,25 +915,29 @@ (p13) mov in5=-1 ;; st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr - st8.spill [r17]=r15 // save r15 tnat.nz p14,p0=in6 + cmp.lt p10,p9=r11,r8 // frame size can't be more than local+8 ;; stf8 [r16]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error) +(p9) tnat.nz p10,p0=r15 adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch) + + st8.spill [r17]=r15 // save r15 tnat.nz p8,p0=in7 + nop.i 0 mov r13=r2 // establish `current' movl r1=__gp // establish kernel global pointer ;; (p14) mov in6=-1 (p8) mov in7=-1 - tnat.nz p9,p0=r15 + nop.i 0 cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 movl r17=FPSR_DEFAULT ;; mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value -(p9) mov r15=-1 +(p10) mov r8=-EINVAL br.ret.sptk.many b7 END(ia64_syscall_setup) diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/mca.c 2005-01-23 21:02:28 -08:00 @@ -882,8 +882,6 @@ &ia64_sal_to_os_handoff_state, &ia64_os_to_sal_handoff_state)); -return_to_sal: - if (recover) { sal_log_record_header_t *rh = IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA); rh->severity = sal_log_severity_corrected; diff -Nru a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c --- a/arch/ia64/kernel/mca_drv.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/mca_drv.c 2005-01-23 21:02:28 -08:00 @@ -52,7 +52,7 @@ MCA_IS_GLOBAL = 1 } mca_type_t; -#define MAX_PAGE_ISOLATE 32 +#define MAX_PAGE_ISOLATE 1024 static struct page *page_isolate[MAX_PAGE_ISOLATE]; static int num_page_isolate = 0; diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/process.c 2005-01-23 21:02:28 -08:00 @@ -40,6 +40,8 @@ #include #include +#include "entry.h" + #ifdef CONFIG_PERFMON # include #endif @@ -630,7 +632,7 @@ return 1; /* f0-f31 are always valid so we always return 1 */ } -asmlinkage long +long sys_execve (char __user *filename, char __user * __user *argv, char __user * __user *envp, struct pt_regs *regs) { @@ -667,7 +669,7 @@ regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */ regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; - + regs.sw.pr = (1 << PRED_KERNEL_STACK); return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s.pt, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c --- a/arch/ia64/kernel/ptrace.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/ptrace.c 2005-01-23 21:02:28 -08:00 @@ -31,9 +31,6 @@ #include "entry.h" -#define p4 (1UL << 4) /* for pSys (see entry.h) */ -#define p5 (1UL << 5) /* for pNonSys (see entry.h) */ - /* * Bits in the PSR that we allow ptrace() to change: * be, up, ac, mfl, mfh (the user mask; five bits total) @@ -669,8 +666,8 @@ } unw_get_pr(&prev_info, &pr); - pr &= ~pSys; - pr |= pNonSys; + pr &= ~(1UL << PRED_SYSCALL); + pr |= (1UL << PRED_NON_SYSCALL); unw_set_pr(&prev_info, pr); pt->cr_ifs = (1UL << 63) | cfm; diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c --- a/arch/ia64/kernel/smpboot.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/smpboot.c 2005-01-23 21:02:28 -08:00 @@ -612,8 +612,7 @@ */ return; } - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(HZ/10); + msleep(100); } printk(KERN_ERR "CPU %u didn't die...\n", cpu); } diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c --- a/arch/ia64/kernel/unwind.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/kernel/unwind.c 2005-01-23 21:02:28 -08:00 @@ -47,8 +47,6 @@ #include "entry.h" #include "unwind_i.h" -#define p5 5 - #define UNW_LOG_CACHE_SIZE 7 /* each unw_script is ~256 bytes in size */ #define UNW_CACHE_SIZE (1 << UNW_LOG_CACHE_SIZE) @@ -1899,7 +1897,7 @@ num_regs = 0; if ((info->flags & UNW_FLAG_INTERRUPT_FRAME)) { info->pt = info->sp + 16; - if ((pr & (1UL << pNonSys)) != 0) + if ((pr & (1UL << PRED_NON_SYSCALL)) != 0) num_regs = *info->cfm_loc & 0x7f; /* size of frame */ info->pfs_loc = (unsigned long *) (info->pt + offsetof(struct pt_regs, ar_pfs)); @@ -1945,7 +1943,7 @@ int unw_unwind_to_user (struct unw_frame_info *info) { - unsigned long ip; + unsigned long ip, sp; while (unw_unwind(info) >= 0) { if (unw_get_rp(info, &ip) < 0) { @@ -1954,6 +1952,9 @@ __FUNCTION__, ip); return -1; } + unw_get_sp(info, &sp); + if (sp >= (unsigned long)info->task + IA64_STK_OFFSET) + break; if (ip < FIXADDR_USER_END) return 0; } diff -Nru a/arch/ia64/lib/bitop.c b/arch/ia64/lib/bitop.c --- a/arch/ia64/lib/bitop.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/lib/bitop.c 2005-01-23 21:02:28 -08:00 @@ -8,7 +8,7 @@ * Find next zero bit in a bitmap reasonably efficiently.. */ -int __find_next_zero_bit (void *addr, unsigned long size, unsigned long offset) +int __find_next_zero_bit (const void *addr, unsigned long size, unsigned long offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 6); unsigned long result = offset & ~63UL; diff -Nru a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c --- a/arch/ia64/mm/contig.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/mm/contig.c 2005-01-23 21:02:28 -08:00 @@ -195,7 +195,7 @@ __per_cpu_offset[cpu] = (char *) cpu_data - __per_cpu_start; cpu_data += PERCPU_PAGE_SIZE; per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu]; - __per_cpu_mca[cpu] = (unsigned long)mca_data; + __per_cpu_mca[cpu] = (unsigned long)__pa(mca_data); mca_data += PERCPU_MCA_SIZE; } } diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c --- a/arch/ia64/pci/pci.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/pci/pci.c 2005-01-23 21:02:28 -08:00 @@ -539,7 +539,8 @@ */ vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO); - if (write_combine) + if (write_combine && efi_range_is_wc(vma->vm_start, + vma->vm_end - vma->vm_start)) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); else vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); diff -Nru a/arch/ia64/sn/include/shub.h b/arch/ia64/sn/include/shub.h --- a/arch/ia64/sn/include/shub.h 2005-01-23 21:02:28 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,39 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2001-2004 Silicon Graphics, Inc. All rights reserved. - */ - -#ifndef _ASM_IA64_SN_SHUB_H -#define _ASM_IA64_SN_SHUB_H - - -#define MD_MEM_BANKS 4 - - -/* - * Junk Bus Address Space - * The junk bus is used to access the PROM, LED's, and UART. It's - * accessed through the local block MMR space. The data path is - * 16 bits wide. This space requires address bits 31-27 to be set, and - * is further divided by address bits 26:15. - * The LED addresses are write-only. To read the LEDs, you need to use - * SH_JUNK_BUS_LED0-3, defined in shub_mmr.h - * - */ -#define SH_REAL_JUNK_BUS_LED0 0x7fed00000UL -#define SH_REAL_JUNK_BUS_LED1 0x7fed10000UL -#define SH_REAL_JUNK_BUS_LED2 0x7fed20000UL -#define SH_REAL_JUNK_BUS_LED3 0x7fed30000UL -#define SH_JUNK_BUS_UART0 0x7fed40000UL -#define SH_JUNK_BUS_UART1 0x7fed40008UL -#define SH_JUNK_BUS_UART2 0x7fed40010UL -#define SH_JUNK_BUS_UART3 0x7fed40018UL -#define SH_JUNK_BUS_UART4 0x7fed40020UL -#define SH_JUNK_BUS_UART5 0x7fed40028UL -#define SH_JUNK_BUS_UART6 0x7fed40030UL -#define SH_JUNK_BUS_UART7 0x7fed40038UL - -#endif /* _ASM_IA64_SN_SHUB_H */ diff -Nru a/arch/ia64/sn/kernel/bte_error.c b/arch/ia64/sn/kernel/bte_error.c --- a/arch/ia64/sn/kernel/bte_error.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/sn/kernel/bte_error.c 2005-01-23 21:02:28 -08:00 @@ -15,6 +15,7 @@ #include "xtalk/xwidgetdev.h" #include "xtalk/hubdev.h" #include +#include /* * Bte error handling is done in two parts. The first captures diff -Nru a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c --- a/arch/ia64/sn/kernel/irq.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/sn/kernel/irq.c 2005-01-23 21:02:28 -08:00 @@ -183,7 +183,9 @@ sn_irq_info = sn_irq_info->irq_next; +#ifdef CONFIG_SMP set_irq_affinity_info((irq & 0xff), cpuphys, 0); +#endif } else { break; /* snp_affinity failed the intr_alloc */ } @@ -201,16 +203,6 @@ sn_end_irq, sn_set_affinity_irq }; - -struct irq_desc *sn_irq_desc(unsigned int irq) -{ - return (irq_desc + irq); -} - -u8 sn_irq_to_vector(unsigned int irq) -{ - return irq; -} unsigned int sn_local_vector_to_irq(u8 vector) { diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c --- a/arch/ia64/sn/kernel/setup.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/sn/kernel/setup.c 2005-01-23 21:02:28 -08:00 @@ -163,13 +163,12 @@ void __init early_sn_setup(void) { - void ia64_sal_handler_init(void *entry_point, void *gpval); efi_system_table_t *efi_systab; efi_config_table_t *config_tables; struct ia64_sal_systab *sal_systab; struct ia64_sal_desc_entry_point *ep; char *p; - int i; + int i, j; /* * Parse enough of the SAL tables to locate the SAL entry point. Since, console @@ -185,19 +184,21 @@ 0) { sal_systab = __va(config_tables[i].table); p = (char *)(sal_systab + 1); - for (i = 0; i < sal_systab->entry_count; i++) { + for (j = 0; j < sal_systab->entry_count; j++) { if (*p == SAL_DESC_ENTRY_POINT) { ep = (struct ia64_sal_desc_entry_point *)p; ia64_sal_handler_init(__va (ep->sal_proc), __va(ep->gp)); - break; + return; } p += SAL_DESC_SIZE(*p); } } } + /* Uh-oh, SAL not available?? */ + printk(KERN_ERR "failed to find SAL entry point\n"); } extern int platform_intr_list[]; diff -Nru a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c 2005-01-23 21:02:28 -08:00 @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2004-2005 Silicon Graphics, Inc. All rights reserved. * * SGI Altix topology and hardware performance monitoring API. * Mark Goodwin . @@ -374,6 +374,42 @@ return r; } +/* map SAL hwperf error code to system error code */ +static int sn_hwperf_map_err(int hwperf_err) +{ + int e; + + switch(hwperf_err) { + case SN_HWPERF_OP_OK: + e = 0; + break; + + case SN_HWPERF_OP_NOMEM: + e = -ENOMEM; + break; + + case SN_HWPERF_OP_NO_PERM: + e = -EPERM; + break; + + case SN_HWPERF_OP_IO_ERROR: + e = -EIO; + break; + + case SN_HWPERF_OP_BUSY: + case SN_HWPERF_OP_RECONFIGURE: + e = -EAGAIN; + break; + + case SN_HWPERF_OP_INVAL: + default: + e = -EINVAL; + break; + } + + return e; +} + /* * ioctl for "sn_hwperf" misc device */ @@ -511,12 +547,20 @@ op_info.v0 = &v0; op_info.op = op; r = sn_hwperf_op_cpu(&op_info); + if (r) { + r = sn_hwperf_map_err(r); + goto error; + } break; default: /* all other ops are a direct SAL call */ r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op, a.arg, a.sz, (u64) p, 0, 0, &v0); + if (r) { + r = sn_hwperf_map_err(r); + goto error; + } a.v0 = v0; break; } diff -Nru a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c --- a/arch/ia64/sn/pci/pci_dma.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ia64/sn/pci/pci_dma.c 2005-01-23 21:02:28 -08:00 @@ -3,52 +3,85 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2000,2002-2004 Silicon Graphics, Inc. All rights reserved. + * Copyright (C) 2000,2002-2005 Silicon Graphics, Inc. All rights reserved. * - * Routines for PCI DMA mapping. See Documentation/DMA-mapping.txt for + * Routines for PCI DMA mapping. See Documentation/DMA-API.txt for * a description of how these routines should be used. */ #include +#include #include #include "pci/pcibus_provider_defs.h" #include "pci/pcidev.h" #include "pci/pcibr_provider.h" -void sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, - int direction); +#define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset) +#define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) /** - * sn_pci_alloc_consistent - allocate memory for coherent DMA - * @hwdev: device to allocate for + * sn_dma_supported - test a DMA mask + * @dev: device to test + * @mask: DMA mask to test + * + * Return whether the given PCI device DMA address mask can be supported + * properly. For example, if your device can only drive the low 24-bits + * during PCI bus mastering, then you would pass 0x00ffffff as the mask to + * this function. Of course, SN only supports devices that have 32 or more + * address bits when using the PMU. + */ +int sn_dma_supported(struct device *dev, u64 mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + if (mask < 0x7fffffff) + return 0; + return 1; +} +EXPORT_SYMBOL(sn_dma_supported); + +/** + * sn_dma_set_mask - set the DMA mask + * @dev: device to set + * @dma_mask: new mask + * + * Set @dev's DMA mask if the hw supports it. + */ +int sn_dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG_ON(dev->bus != &pci_bus_type); + + if (!sn_dma_supported(dev, dma_mask)) + return 0; + + *dev->dma_mask = dma_mask; + return 1; +} +EXPORT_SYMBOL(sn_dma_set_mask); + +/** + * sn_dma_alloc_coherent - allocate memory for coherent DMA + * @dev: device to allocate for * @size: size of the region * @dma_handle: DMA (bus) address + * @flags: memory allocation flags * - * pci_alloc_consistent() returns a pointer to a memory region suitable for + * dma_alloc_coherent() returns a pointer to a memory region suitable for * coherent DMA traffic to/from a PCI device. On SN platforms, this means * that @dma_handle will have the %PCIIO_DMA_CMD flag set. * * This interface is usually used for "command" streams (e.g. the command - * queue for a SCSI controller). See Documentation/DMA-mapping.txt for + * queue for a SCSI controller). See Documentation/DMA-API.txt for * more information. - * - * Also known as platform_pci_alloc_consistent() by the IA64 machvec code. */ -void *sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t * dma_handle) +void *sn_dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t * dma_handle, int flags) { void *cpuaddr; unsigned long phys_addr; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev); + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); - if (bussoft == NULL) { - return NULL; - } - - if (! IS_PCI_BRIDGE_ASIC(bussoft->bs_asic_type)) { - return NULL; /* unsupported asic type */ - } + BUG_ON(dev->bus != &pci_bus_type); /* * Allocate the memory. @@ -66,151 +99,52 @@ /* * 64 bit address translations should never fail. * 32 bit translations can fail if there are insufficient mapping - * resources. + * resources. */ - *dma_handle = pcibr_dma_map(pcidev_info, phys_addr, size, SN_PCIDMA_CONSISTENT); + *dma_handle = pcibr_dma_map(pcidev_info, phys_addr, size, + SN_PCIDMA_CONSISTENT); if (!*dma_handle) { - printk(KERN_ERR - "sn_pci_alloc_consistent(): failed *dma_handle = 0x%lx hwdev->dev.coherent_dma_mask = 0x%lx \n", - *dma_handle, hwdev->dev.coherent_dma_mask); + printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); free_pages((unsigned long)cpuaddr, get_order(size)); return NULL; } return cpuaddr; } +EXPORT_SYMBOL(sn_dma_alloc_coherent); /** - * sn_pci_free_consistent - free memory associated with coherent DMAable region - * @hwdev: device to free for + * sn_pci_free_coherent - free memory associated with coherent DMAable region + * @dev: device to free for * @size: size to free - * @vaddr: kernel virtual address to free + * @cpu_addr: kernel virtual address to free * @dma_handle: DMA address associated with this region * - * Frees the memory allocated by pci_alloc_consistent(). Also known - * as platform_pci_free_consistent() by the IA64 machvec code. + * Frees the memory allocated by dma_alloc_coherent(), potentially unmapping + * any associated IOMMU mappings. */ -void -sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, - dma_addr_t dma_handle) +void sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_handle) { - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev); + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); - if (! bussoft) { - return; - } + BUG_ON(dev->bus != &pci_bus_type); pcibr_dma_unmap(pcidev_info, dma_handle, 0); - free_pages((unsigned long)vaddr, get_order(size)); -} - -/** - * sn_pci_map_sg - map a scatter-gather list for DMA - * @hwdev: device to map for - * @sg: scatterlist to map - * @nents: number of entries - * @direction: direction of the DMA transaction - * - * Maps each entry of @sg for DMA. Also known as platform_pci_map_sg by the - * IA64 machvec code. - */ -int -sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, - int direction) -{ - - int i; - unsigned long phys_addr; - struct scatterlist *saved_sg = sg; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev); - - /* can't go anywhere w/o a direction in life */ - if (direction == PCI_DMA_NONE) - BUG(); - - if (! bussoft) { - return 0; - } - - /* SN cannot support DMA addresses smaller than 32 bits. */ - if (hwdev->dma_mask < 0x7fffffff) - return 0; - - /* - * Setup a DMA address for each entry in the - * scatterlist. - */ - for (i = 0; i < nents; i++, sg++) { - phys_addr = - __pa((unsigned long)page_address(sg->page) + sg->offset); - sg->dma_address = pcibr_dma_map(pcidev_info, phys_addr, sg->length, 0); - - if (!sg->dma_address) { - printk(KERN_ERR "sn_pci_map_sg: Unable to allocate " - "anymore page map entries.\n"); - /* - * We will need to free all previously allocated entries. - */ - if (i > 0) { - sn_pci_unmap_sg(hwdev, saved_sg, i, direction); - } - return (0); - } - - sg->dma_length = sg->length; - } - - return nents; - -} - -/** - * sn_pci_unmap_sg - unmap a scatter-gather list - * @hwdev: device to unmap - * @sg: scatterlist to unmap - * @nents: number of scatterlist entries - * @direction: DMA direction - * - * Unmap a set of streaming mode DMA translations. Again, cpu read rules - * concerning calls here are the same as for pci_unmap_single() below. Also - * known as sn_pci_unmap_sg() by the IA64 machvec code. - */ -void -sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, - int direction) -{ - int i; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev); - - /* can't go anywhere w/o a direction in life */ - if (direction == PCI_DMA_NONE) - BUG(); - - if (! bussoft) { - return; - } - - for (i = 0; i < nents; i++, sg++) { - pcibr_dma_unmap(pcidev_info, sg->dma_address, direction); - sg->dma_address = (dma_addr_t) NULL; - sg->dma_length = 0; - } + free_pages((unsigned long)cpu_addr, get_order(size)); } +EXPORT_SYMBOL(sn_dma_free_coherent); /** - * sn_pci_map_single - map a single region for DMA - * @hwdev: device to map for - * @ptr: kernel virtual address of the region to map + * sn_dma_map_single - map a single page for DMA + * @dev: device to map for + * @cpu_addr: kernel virtual address of the region to map * @size: size of the region * @direction: DMA direction * - * Map the region pointed to by @ptr for DMA and return the - * DMA address. Also known as platform_pci_map_single() by - * the IA64 machvec code. + * Map the region pointed to by @cpu_addr for DMA and return the + * DMA address. * * We map this to the one step pcibr_dmamap_trans interface rather than * the two step pcibr_dmamap_alloc/pcibr_dmamap_addr because we have @@ -218,262 +152,150 @@ * (which is pretty much unacceptable). * * TODO: simplify our interface; - * get rid of dev_desc and vhdl (seems redundant given a pci_dev); * figure out how to save dmamap handle so can use two step. */ -dma_addr_t -sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) +dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, + int direction) { dma_addr_t dma_addr; unsigned long phys_addr; - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev); - - if (direction == PCI_DMA_NONE) - BUG(); + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); - if (bussoft == NULL) { - return 0; - } - - if (! IS_PCI_BRIDGE_ASIC(bussoft->bs_asic_type)) { - return 0; /* unsupported asic type */ - } - - /* SN cannot support DMA addresses smaller than 32 bits. */ - if (hwdev->dma_mask < 0x7fffffff) - return 0; - - /* - * Call our dmamap interface - */ + BUG_ON(dev->bus != &pci_bus_type); - phys_addr = __pa(ptr); + phys_addr = __pa(cpu_addr); dma_addr = pcibr_dma_map(pcidev_info, phys_addr, size, 0); if (!dma_addr) { - printk(KERN_ERR "pci_map_single: Unable to allocate anymore " - "page map entries.\n"); + printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); return 0; } - return ((dma_addr_t) dma_addr); + return dma_addr; } +EXPORT_SYMBOL(sn_dma_map_single); /** - * sn_pci_dma_sync_single_* - make sure all DMAs or CPU accesses - * have completed - * @hwdev: device to sync - * @dma_handle: DMA address to sync + * sn_dma_unmap_single - unamp a DMA mapped page + * @dev: device to sync + * @dma_addr: DMA address to sync * @size: size of region * @direction: DMA direction * * This routine is supposed to sync the DMA region specified - * by @dma_handle into the 'coherence domain'. We do not need to do - * anything on our platform. + * by @dma_handle into the coherence domain. On SN, we're always cache + * coherent, so we just need to free any ATEs associated with this mapping. */ -void -sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, - int direction) +void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + int direction) { - struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); - struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(hwdev); - - if (direction == PCI_DMA_NONE) - BUG(); - - if (bussoft == NULL) { - return; - } - - if (! IS_PCI_BRIDGE_ASIC(bussoft->bs_asic_type)) { - return; /* unsupported asic type */ - } + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + BUG_ON(dev->bus != &pci_bus_type); pcibr_dma_unmap(pcidev_info, dma_addr, direction); } +EXPORT_SYMBOL(sn_dma_unmap_single); /** - * sn_dma_supported - test a DMA mask - * @hwdev: device to test - * @mask: DMA mask to test + * sn_dma_unmap_sg - unmap a DMA scatterlist + * @dev: device to unmap + * @sg: scatterlist to unmap + * @nhwentries: number of scatterlist entries + * @direction: DMA direction * - * Return whether the given PCI device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during PCI bus mastering, then you would pass 0x00ffffff as the mask to - * this function. Of course, SN only supports devices that have 32 or more - * address bits when using the PMU. We could theoretically support <32 bit - * cards using direct mapping, but we'll worry about that later--on the off - * chance that someone actually wants to use such a card. + * Unmap a set of streaming mode DMA translations. */ -int sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask) -{ - if (mask < 0x7fffffff) - return 0; - return 1; -} - -/* - * New generic DMA routines just wrap sn2 PCI routines until we - * support other bus types (if ever). - */ - -int sn_dma_supported(struct device *dev, u64 mask) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return sn_pci_dma_supported(to_pci_dev(dev), mask); -} - -EXPORT_SYMBOL(sn_dma_supported); - -int sn_dma_set_mask(struct device *dev, u64 dma_mask) +void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nhwentries, int direction) { - BUG_ON(dev->bus != &pci_bus_type); - - if (!sn_dma_supported(dev, dma_mask)) - return 0; - - *dev->dma_mask = dma_mask; - return 1; -} - -EXPORT_SYMBOL(sn_dma_set_mask); - -void *sn_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, int flag) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return sn_pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); -} - -EXPORT_SYMBOL(sn_dma_alloc_coherent); + int i; + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); -void -sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, - dma_addr_t dma_handle) -{ BUG_ON(dev->bus != &pci_bus_type); - sn_pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); + for (i = 0; i < nhwentries; i++, sg++) { + pcibr_dma_unmap(pcidev_info, sg->dma_address, direction); + sg->dma_address = (dma_addr_t) NULL; + sg->dma_length = 0; + } } +EXPORT_SYMBOL(sn_dma_unmap_sg); -EXPORT_SYMBOL(sn_dma_free_coherent); - -dma_addr_t -sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, +/** + * sn_dma_map_sg - map a scatterlist for DMA + * @dev: device to map for + * @sg: scatterlist to map + * @nhwentries: number of entries + * @direction: direction of the DMA transaction + * + * Maps each entry of @sg for DMA. + */ +int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, int direction) { - BUG_ON(dev->bus != &pci_bus_type); - - return sn_pci_map_single(to_pci_dev(dev), cpu_addr, size, - (int)direction); -} - -EXPORT_SYMBOL(sn_dma_map_single); - -void -sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); -} - -EXPORT_SYMBOL(sn_dma_unmap_single); + unsigned long phys_addr; + struct scatterlist *saved_sg = sg; + struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(to_pci_dev(dev)); + int i; -dma_addr_t -sn_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, int direction) -{ BUG_ON(dev->bus != &pci_bus_type); - return pci_map_page(to_pci_dev(dev), page, offset, size, - (int)direction); -} - -EXPORT_SYMBOL(sn_dma_map_page); - -void -sn_dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); + /* + * Setup a DMA address for each entry in the scatterlist. + */ + for (i = 0; i < nhwentries; i++, sg++) { + phys_addr = SG_ENT_PHYS_ADDRESS(sg); + sg->dma_address = pcibr_dma_map(pcidev_info, phys_addr, + sg->length, 0); - pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); -} + if (!sg->dma_address) { + printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); -EXPORT_SYMBOL(sn_dma_unmap_page); + /* + * Free any successfully allocated entries. + */ + if (i > 0) + sn_dma_unmap_sg(dev, saved_sg, i, direction); + return 0; + } -int -sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); + sg->dma_length = sg->length; + } - return sn_pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); + return nhwentries; } - EXPORT_SYMBOL(sn_dma_map_sg); -void -sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); -} - -EXPORT_SYMBOL(sn_dma_unmap_sg); - -void -sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, int direction) +void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, + size_t size, int direction) { BUG_ON(dev->bus != &pci_bus_type); } - EXPORT_SYMBOL(sn_dma_sync_single_for_cpu); -void -sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, int direction) +void sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, + size_t size, int direction) { BUG_ON(dev->bus != &pci_bus_type); } - EXPORT_SYMBOL(sn_dma_sync_single_for_device); -void -sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - int direction) +void sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nelems, int direction) { BUG_ON(dev->bus != &pci_bus_type); } - EXPORT_SYMBOL(sn_dma_sync_sg_for_cpu); -void -sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, - int nelems, int direction) +void sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nelems, int direction) { BUG_ON(dev->bus != &pci_bus_type); } +EXPORT_SYMBOL(sn_dma_sync_sg_for_device); int sn_dma_mapping_error(dma_addr_t dma_addr) { return 0; } - -EXPORT_SYMBOL(sn_dma_sync_sg_for_device); -EXPORT_SYMBOL(sn_pci_unmap_single); -EXPORT_SYMBOL(sn_pci_map_single); -EXPORT_SYMBOL(sn_pci_map_sg); -EXPORT_SYMBOL(sn_pci_unmap_sg); -EXPORT_SYMBOL(sn_pci_alloc_consistent); -EXPORT_SYMBOL(sn_pci_free_consistent); -EXPORT_SYMBOL(sn_pci_dma_supported); EXPORT_SYMBOL(sn_dma_mapping_error); char *sn_pci_get_legacy_mem(struct pci_bus *bus) diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c --- a/arch/ppc64/kernel/signal.c 2005-01-23 21:02:28 -08:00 +++ b/arch/ppc64/kernel/signal.c 2005-01-23 21:02:28 -08:00 @@ -67,7 +67,7 @@ struct siginfo info; /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */ char abigap[288]; -}; +} __attribute__ ((aligned (16))); /* @@ -254,7 +254,7 @@ newsp = (current->sas_ss_sp + current->sas_ss_size); } - return (void __user *)((newsp - frame_size) & -8ul); + return (void __user *)((newsp - frame_size) & -16ul); } /* diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig --- a/arch/sparc/Kconfig 2005-01-23 21:02:28 -08:00 +++ b/arch/sparc/Kconfig 2005-01-23 21:02:28 -08:00 @@ -380,6 +380,8 @@ source "drivers/usb/Kconfig" +source "drivers/infiniband/Kconfig" + source "drivers/char/watchdog/Kconfig" source "arch/sparc/Kconfig.debug" diff -Nru a/arch/sparc/kernel/muldiv.c b/arch/sparc/kernel/muldiv.c --- a/arch/sparc/kernel/muldiv.c 2005-01-23 21:02:28 -08:00 +++ b/arch/sparc/kernel/muldiv.c 2005-01-23 21:02:28 -08:00 @@ -4,6 +4,9 @@ * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * + * 2004-12-25 Krzysztof Helt (krzysztof.h1@wp.pl) + * - fixed registers constrains in inline assembly declarations */ #include @@ -132,7 +135,7 @@ "mov %%o0, %0\n\t" "mov %%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) - : + : "0" (rs1), "1" (rs2) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); #ifdef DEBUG_MULDIV printk ("0x%x%08x\n", rs2, rs1); @@ -152,7 +155,7 @@ "mov %%o0, %0\n\t" "mov %%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) - : + : "0" (rs1), "1" (rs2) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); #ifdef DEBUG_MULDIV printk ("0x%x%08x\n", rs2, rs1); @@ -181,7 +184,7 @@ "mov %%o1, %0\n\t" "mov %%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) - : "r" (regs->y) + : "r" (regs->y), "0" (rs1), "1" (rs2) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "cc"); #ifdef DEBUG_MULDIV @@ -210,7 +213,7 @@ "mov %%o1, %0\n\t" "mov %%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) - : "r" (regs->y) + : "r" (regs->y), "0" (rs1), "1" (rs2) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "cc"); #ifdef DEBUG_MULDIV diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig 2005-01-23 21:02:28 -08:00 +++ b/arch/sparc64/defconfig 2005-01-23 21:02:28 -08:00 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.10 -# Mon Jan 10 11:24:25 2005 +# Linux kernel version: 2.6.11-rc1 +# Fri Jan 21 20:03:21 2005 # CONFIG_64BIT=y CONFIG_MMU=y @@ -66,13 +66,13 @@ CONFIG_NR_CPUS=4 CONFIG_CPU_FREQ=y # CONFIG_CPU_FREQ_DEBUG is not set -CONFIG_CPU_FREQ_PROC_INTF=y +CONFIG_CPU_FREQ_STAT=m +CONFIG_CPU_FREQ_STAT_DETAILS=y CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set CONFIG_CPU_FREQ_GOV_PERFORMANCE=y CONFIG_CPU_FREQ_GOV_POWERSAVE=m CONFIG_CPU_FREQ_GOV_USERSPACE=m -# CONFIG_CPU_FREQ_24_API is not set CONFIG_CPU_FREQ_GOV_ONDEMAND=m CONFIG_CPU_FREQ_TABLE=y CONFIG_US3_FREQ=m @@ -189,6 +189,7 @@ # CONFIG_LOGO_LINUX_VGA16 is not set # CONFIG_LOGO_LINUX_CLUT224 is not set CONFIG_LOGO_SUN_CLUT224=y +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Serial drivers @@ -228,6 +229,7 @@ # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_CRYPTOLOOP=m CONFIG_BLK_DEV_NBD=m @@ -247,6 +249,7 @@ CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y +CONFIG_ATA_OVER_ETH=m # # ATA/ATAPI/MFM/RLL support @@ -1202,6 +1205,7 @@ CONFIG_SENSORS_LM90=m CONFIG_SENSORS_MAX1619=m CONFIG_SENSORS_PC87360=m +CONFIG_SENSORS_SMSC47B397=m CONFIG_SENSORS_SMSC47M1=m CONFIG_SENSORS_VIA686A=m CONFIG_SENSORS_W83781D=m @@ -1759,6 +1763,7 @@ # CONFIG_USB_SERIAL_IR is not set CONFIG_USB_SERIAL_EDGEPORT=m # CONFIG_USB_SERIAL_EDGEPORT_TI is not set +CONFIG_USB_SERIAL_GARMIN=m CONFIG_USB_SERIAL_IPW=m CONFIG_USB_SERIAL_KEYSPAN_PDA=m CONFIG_USB_SERIAL_KEYSPAN=m @@ -1779,6 +1784,7 @@ CONFIG_USB_SERIAL_MCT_U232=m CONFIG_USB_SERIAL_PL2303=m # CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_TI=m CONFIG_USB_SERIAL_CYBERJACK=m CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OMNINET=m @@ -1789,7 +1795,6 @@ # CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m -# CONFIG_USB_TIGL is not set CONFIG_USB_AUERSWALD=m CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m @@ -1798,6 +1803,7 @@ CONFIG_USB_CYTHERM=m CONFIG_USB_PHIDGETKIT=m CONFIG_USB_PHIDGETSERVO=m +CONFIG_USB_IDMOUSE=m CONFIG_USB_TEST=m # @@ -1863,6 +1869,7 @@ # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set +CONFIG_DEBUG_FS=y # CONFIG_DEBUG_STACK_USAGE is not set CONFIG_KPROBES=y # CONFIG_DEBUG_DCFLUSH is not set diff -Nru a/arch/sparc64/lib/memmove.S b/arch/sparc64/lib/memmove.S --- a/arch/sparc64/lib/memmove.S 2005-01-23 21:02:28 -08:00 +++ b/arch/sparc64/lib/memmove.S 2005-01-23 21:02:28 -08:00 @@ -8,18 +8,16 @@ .align 32 .globl memmove .type memmove,#function -memmove: +memmove: /* o0=dst o1=src o2=len */ mov %o0, %g1 cmp %o0, %o1 - blu,pt %xcc, memcpy - sub %o0, %o1, %g5 - add %o1, %o2, %g3 - cmp %g3, %o0 bleu,pt %xcc, memcpy add %o1, %o2, %g5 - add %o0, %o2, %o5 - + cmp %g5, %o0 + bleu,pt %xcc, memcpy + add %o0, %o2, %o5 sub %g5, 1, %o1 + sub %o5, 1, %o0 1: ldub [%o1], %g5 subcc %o2, 1, %o2 diff -Nru a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c --- a/arch/x86_64/kernel/early_printk.c 2005-01-23 21:02:28 -08:00 +++ b/arch/x86_64/kernel/early_printk.c 2005-01-23 21:02:28 -08:00 @@ -198,9 +198,6 @@ early_console = &early_serial_console; } else if (!strncmp(buf, "vga", 3)) { early_console = &early_vga_console; - } else { - early_console = NULL; - return -1; } early_console_initialized = 1; register_console(early_console); diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c 2005-01-23 21:02:28 -08:00 +++ b/arch/x86_64/kernel/traps.c 2005-01-23 21:02:28 -08:00 @@ -917,7 +917,7 @@ set_intr_gate(0,÷_error); set_intr_gate_ist(1,&debug,DEBUG_STACK); set_intr_gate_ist(2,&nmi,NMI_STACK); - set_intr_gate(3,&int3); + set_system_gate(3,&int3); set_system_gate(4,&overflow); /* int4-5 can be called from all */ set_system_gate(5,&bounds); set_intr_gate(6,&invalid_op); diff -Nru a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c --- a/arch/x86_64/mm/ioremap.c 2005-01-23 21:02:28 -08:00 +++ b/arch/x86_64/mm/ioremap.c 2005-01-23 21:02:28 -08:00 @@ -265,8 +265,9 @@ unmap_vm_area(p); if ((p->flags >> 20) && p->phys_addr + p->size - 1 < virt_to_phys(high_memory)) { + /* p->size includes the guard page, but cpa doesn't like that */ change_page_attr(virt_to_page(__va(p->phys_addr)), - p->size >> PAGE_SHIFT, + (p->size - PAGE_SIZE) >> PAGE_SHIFT, PAGE_KERNEL); global_flush_tlb(); } diff -Nru a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c --- a/drivers/char/drm/drm_vm.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/char/drm/drm_vm.c 2005-01-23 21:02:28 -08:00 @@ -34,6 +34,9 @@ */ #include "drmP.h" +#if defined(__ia64__) +#include +#endif /** @@ -612,8 +615,13 @@ vma->vm_flags |= VM_IO; /* not in core dump */ } #if defined(__ia64__) - if (map->type != _DRM_AGP) - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + if (efi_range_is_wc(vma->vm_start, vma->vm_end - + vma->vm_start)) + vma->vm_page_prot = + pgprot_writecombine(vma->vm_page_prot); + else + vma->vm_page_prot = + pgprot_noncached(vma->vm_page_prot); #endif offset = dev->driver->get_reg_ofs(dev); #ifdef __sparc__ diff -Nru a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h --- a/drivers/infiniband/ulp/ipoib/ipoib.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/infiniband/ulp/ipoib/ipoib.h 2005-01-23 21:02:28 -08:00 @@ -104,10 +104,10 @@ }; /* - * Device private locking: netdev->xmit_lock protects members used - * in TX fast path. - * lock protects everything else. lock nests inside of xmit_lock (ie - * xmit_lock must be acquired first if needed). + * Device private locking: tx_lock protects members used in TX fast + * path (and we use LLTX so upper layers don't do extra locking). + * lock protects everything else. lock nests inside of tx_lock (ie + * tx_lock must be acquired first if needed). */ struct ipoib_dev_priv { spinlock_t lock; @@ -150,6 +150,7 @@ struct ipoib_buf *rx_ring; + spinlock_t tx_lock; struct ipoib_buf *tx_ring; unsigned tx_head; unsigned tx_tail; diff -Nru a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c 2005-01-23 21:02:28 -08:00 @@ -247,12 +247,12 @@ dev_kfree_skb_any(tx_req->skb); - spin_lock_irqsave(&dev->xmit_lock, flags); + spin_lock_irqsave(&priv->tx_lock, flags); ++priv->tx_tail; if (netif_queue_stopped(dev) && priv->tx_head - priv->tx_tail <= IPOIB_TX_RING_SIZE / 2) netif_wake_queue(dev); - spin_unlock_irqrestore(&dev->xmit_lock, flags); + spin_unlock_irqrestore(&priv->tx_lock, flags); if (wc->status != IB_WC_SUCCESS && wc->status != IB_WC_WR_FLUSH_ERR) diff -Nru a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c 2005-01-23 21:02:28 -08:00 @@ -411,7 +411,7 @@ /* * We can only be called from ipoib_start_xmit, so we're - * inside dev->xmit_lock -- no need to save/restore flags. + * inside tx_lock -- no need to save/restore flags. */ spin_lock(&priv->lock); @@ -483,7 +483,7 @@ /* * We can only be called from ipoib_start_xmit, so we're - * inside dev->xmit_lock -- no need to save/restore flags. + * inside tx_lock -- no need to save/restore flags. */ spin_lock(&priv->lock); @@ -526,11 +526,27 @@ spin_unlock(&priv->lock); } -/* Called with dev->xmit_lock held and IRQs disabled. */ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_neigh *neigh; + unsigned long flags; + + local_irq_save(flags); + if (!spin_trylock(&priv->tx_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + /* + * Check if our queue is stopped. Since we have the LLTX bit + * set, we can't rely on netif_stop_queue() preventing our + * xmit function from being called with a full queue. + */ + if (unlikely(netif_queue_stopped(dev))) { + spin_unlock_irqrestore(&priv->tx_lock, flags); + return NETDEV_TX_BUSY; + } if (skb->dst && skb->dst->neighbour) { if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { @@ -585,6 +601,7 @@ } out: + spin_unlock_irqrestore(&priv->tx_lock, flags); return NETDEV_TX_OK; } @@ -780,7 +797,7 @@ dev->addr_len = INFINIBAND_ALEN; dev->type = ARPHRD_INFINIBAND; dev->tx_queue_len = IPOIB_TX_RING_SIZE * 2; - dev->features = NETIF_F_VLAN_CHALLENGED; + dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX; /* MTU will be reset when mcast join happens */ dev->mtu = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN; @@ -795,6 +812,7 @@ priv->dev = dev; spin_lock_init(&priv->lock); + spin_lock_init(&priv->tx_lock); init_MUTEX(&priv->mcast_mutex); init_MUTEX(&priv->vlan_mutex); diff -Nru a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c --- a/drivers/media/common/saa7146_core.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/common/saa7146_core.c 2005-01-23 21:02:28 -08:00 @@ -380,8 +380,8 @@ /* disable all irqs */ saa7146_write(dev, IER, 0); - /* shut down all dma transfers */ - saa7146_write(dev, MC1, 0x00ff0000); + /* shut down all dma transfers and rps tasks */ + saa7146_write(dev, MC1, 0x30ff0000); /* clear out any rps-signals pending */ saa7146_write(dev, MC2, 0xf8000000); diff -Nru a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig --- a/drivers/media/dvb/b2c2/Kconfig 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/b2c2/Kconfig 2005-01-23 21:02:28 -08:00 @@ -4,9 +4,11 @@ select DVB_STV0299 select DVB_MT352 select DVB_MT312 + select DVB_NXT2002 help Support for the Skystar2 PCI DVB card by Technisat, which - is equipped with the FlexCopII chipset by B2C2. + is equipped with the FlexCopII chipset by B2C2, and + for the B2C2/BBTI Air2PC-ATSC card. Say Y if you own such a device and want to use it. @@ -17,7 +19,7 @@ select DVB_MT352 help Support for the Air/Sky/Cable2PC USB DVB device by B2C2. Currently - this does nothing, but providing basic function for the used usb + the does nothing, but providing basic function for the used usb protocol. Say Y if you own such a device and want to use it. diff -Nru a/drivers/media/dvb/b2c2/b2c2-usb-core.c b/drivers/media/dvb/b2c2/b2c2-usb-core.c --- a/drivers/media/dvb/b2c2/b2c2-usb-core.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/b2c2/b2c2-usb-core.c 2005-01-23 21:02:28 -08:00 @@ -33,7 +33,7 @@ } static int debug; -module_param(debug, int, 0x644); +module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4 (or-able))."); #define deb_info(args...) dprintk(0x01,args) @@ -89,12 +89,22 @@ /* request types */ typedef enum { + +/* something is wrong with this part RTYPE_READ_DW = (1 << 6), RTYPE_WRITE_DW_1 = (3 << 6), RTYPE_READ_V8_MEMORY = (6 << 6), RTYPE_WRITE_V8_MEMORY = (7 << 6), RTYPE_WRITE_V8_FLASH = (8 << 6), RTYPE_GENERIC = (9 << 6), +*/ + RTYPE_READ_DW = (3 << 6), + RTYPE_WRITE_DW_1 = (1 << 6), + + RTYPE_READ_V8_MEMORY = (6 << 6), + RTYPE_WRITE_V8_MEMORY = (7 << 6), + RTYPE_WRITE_V8_FLASH = (8 << 6), + RTYPE_GENERIC = (9 << 6), } b2c2_usb_request_type_t; /* request */ @@ -391,9 +401,9 @@ } /* initialising and submitting iso urbs */ for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { - deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset); int frame_offset = 0; struct urb *urb = b2c2->iso_urb[i]; + deb_info("initializing and submitting urb no. %d (buf_offset: %d).\n",i,buffer_offset); urb->dev = b2c2->udev; urb->context = b2c2; diff -Nru a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c --- a/drivers/media/dvb/b2c2/skystar2.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/b2c2/skystar2.c 2005-01-23 21:02:28 -08:00 @@ -53,7 +53,7 @@ #include "stv0299.h" #include "mt352.h" #include "mt312.h" - +#include "nxt2002.h" static int debug; static int enable_hw_filters = 2; @@ -1379,10 +1379,7 @@ write_reg_dw(adapter, 0x008, adapter->dmaq1.bus_addr & 0xfffffffc); udelay(1000); - if (subbuffers == 0) - dma_enable_disable_irq(adapter, 0, 1, 0); - else - dma_enable_disable_irq(adapter, 0, 1, 1); + dma_enable_disable_irq(adapter, 0, 1, subbuffers ? 1 : 0); irq_dma_enable_disable_irq(adapter, 1); @@ -1681,84 +1678,80 @@ return IRQ_HANDLED; } -static void init_dma_queue(struct adapter *adapter) +static int init_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq, + int size, int dmaq_offset) { + struct pci_dev *pdev = adapter->pdev; dma_addr_t dma_addr; - if (adapter->dmaq1.buffer != 0) - return; - - adapter->dmaq1.head = 0; - adapter->dmaq1.tail = 0; - adapter->dmaq1.buffer = NULL; - - adapter->dmaq1.buffer = pci_alloc_consistent(adapter->pdev, SIZE_OF_BUF_DMA1 + 0x80, &dma_addr); + dmaq->head = 0; + dmaq->tail = 0; - if (adapter->dmaq1.buffer != 0) { - memset(adapter->dmaq1.buffer, 0, SIZE_OF_BUF_DMA1); - - adapter->dmaq1.bus_addr = dma_addr; - adapter->dmaq1.buffer_size = SIZE_OF_BUF_DMA1; - - dma_init_dma(adapter, 0); + dmaq->buffer = pci_alloc_consistent(pdev, size + 0x80, &dma_addr); + if (!dmaq->buffer) + return -ENOMEM; - adapter->dma_status = adapter->dma_status | 0x10000000; + dmaq->bus_addr = dma_addr; + dmaq->buffer_size = size; - ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n", __FUNCTION__, adapter->dmaq1.buffer, SIZE_OF_BUF_DMA1); + dma_init_dma(adapter, dmaq_offset); - } else { + ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n", + __FUNCTION__, dmaq->buffer, size); - adapter->dma_status = adapter->dma_status & ~0x10000000; + return 0; } - if (adapter->dmaq2.buffer != 0) - return; - - adapter->dmaq2.head = 0; - adapter->dmaq2.tail = 0; - adapter->dmaq2.buffer = NULL; - - adapter->dmaq2.buffer = pci_alloc_consistent(adapter->pdev, SIZE_OF_BUF_DMA2 + 0x80, &dma_addr); - - if (adapter->dmaq2.buffer != 0) { - memset(adapter->dmaq2.buffer, 0, SIZE_OF_BUF_DMA2); - - adapter->dmaq2.bus_addr = dma_addr; - adapter->dmaq2.buffer_size = SIZE_OF_BUF_DMA2; - - dma_init_dma(adapter, 1); - - adapter->dma_status = adapter->dma_status | 0x20000000; - - ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n", __FUNCTION__, adapter->dmaq2.buffer, (int) SIZE_OF_BUF_DMA2); +static int init_dma_queue(struct adapter *adapter) +{ + struct { + struct dmaq *dmaq; + u32 dma_status; + int size; + } dmaq_desc[] = { + { &adapter->dmaq1, 0x10000000, SIZE_OF_BUF_DMA1 }, + { &adapter->dmaq2, 0x20000000, SIZE_OF_BUF_DMA2 } + }, *p = dmaq_desc; + int i; - } else { + for (i = 0; i < 2; i++, p++) { + if (init_dma_queue_one(adapter, p->dmaq, p->size, i) < 0) + adapter->dma_status &= ~p->dma_status; + else + adapter->dma_status |= p->dma_status; + } + return (adapter->dma_status & 0x30000000) ? 0 : -ENOMEM; +} - adapter->dma_status = adapter->dma_status & ~0x20000000; +static void free_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq) +{ + if (dmaq->buffer) { + pci_free_consistent(adapter->pdev, dmaq->buffer_size + 0x80, + dmaq->buffer, dmaq->bus_addr); + memset(dmaq, 0, sizeof(*dmaq)); } } static void free_dma_queue(struct adapter *adapter) { - if (adapter->dmaq1.buffer != 0) { - pci_free_consistent(adapter->pdev, SIZE_OF_BUF_DMA1 + 0x80, adapter->dmaq1.buffer, adapter->dmaq1.bus_addr); + struct dmaq *dmaq[] = { + &adapter->dmaq1, + &adapter->dmaq2, + NULL + }, **p; - adapter->dmaq1.bus_addr = 0; - adapter->dmaq1.head = 0; - adapter->dmaq1.tail = 0; - adapter->dmaq1.buffer_size = 0; - adapter->dmaq1.buffer = NULL; - } - - if (adapter->dmaq2.buffer != 0) { - pci_free_consistent(adapter->pdev, SIZE_OF_BUF_DMA2 + 0x80, adapter->dmaq2.buffer, adapter->dmaq2.bus_addr); - - adapter->dmaq2.bus_addr = 0; - adapter->dmaq2.head = 0; - adapter->dmaq2.tail = 0; - adapter->dmaq2.buffer_size = 0; - adapter->dmaq2.buffer = NULL; + for (p = dmaq; *p; p++) + free_dma_queue_one(adapter, *p); } + +static void release_adapter(struct adapter *adapter) +{ + struct pci_dev *pdev = adapter->pdev; + + iounmap(adapter->io_mem); + pci_disable_device(pdev); + pci_release_region(pdev, 0); + pci_release_region(pdev, 1); } static void free_adapter_object(struct adapter *adapter) @@ -1766,16 +1759,9 @@ dprintk("%s:\n", __FUNCTION__); close_stream(adapter, 0); - - if (adapter->irq != 0) free_irq(adapter->irq, adapter); - free_dma_queue(adapter); - - if (adapter->io_mem) - iounmap(adapter->io_mem); - - if (adapter != 0) + release_adapter(adapter); kfree(adapter); } @@ -1784,21 +1770,24 @@ static int claim_adapter(struct adapter *adapter) { struct pci_dev *pdev = adapter->pdev; - u16 var; + int ret; - if (!request_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1), skystar2_pci_driver.name)) - return -EBUSY; + ret = pci_request_region(pdev, 1, skystar2_pci_driver.name); + if (ret < 0) + goto out; - if (!request_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), skystar2_pci_driver.name)) - return -EBUSY; + ret = pci_request_region(pdev, 0, skystar2_pci_driver.name); + if (ret < 0) + goto err_pci_release_1; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision); dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision); - if (pci_enable_device(pdev)) - return -EIO; + ret = pci_enable_device(pdev); + if (ret < 0) + goto err_pci_release_0; pci_read_config_word(pdev, 4, &var); @@ -1811,13 +1800,23 @@ if (!adapter->io_mem) { dprintk("%s: can not map io memory\n", __FUNCTION__); - - return 2; + ret = -EIO; + goto err_pci_disable; } dprintk("%s: io memory maped at %p\n", __FUNCTION__, adapter->io_mem); - return 1; + ret = 1; +out: + return ret; + +err_pci_disable: + pci_disable_device(pdev); +err_pci_release_0: + pci_release_region(pdev, 0); +err_pci_release_1: + pci_release_region(pdev, 1); + goto out; } /* @@ -1873,11 +1872,12 @@ { struct adapter *adapter; u32 tmp; + int ret = -ENOMEM; - if (!(adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL))) { + adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL); + if (!adapter) { dprintk("%s: out of memory!\n", __FUNCTION__); - - return -ENOMEM; + goto out; } memset(adapter, 0, sizeof(struct adapter)); @@ -1887,20 +1887,16 @@ adapter->pdev = pdev; adapter->irq = pdev->irq; - if ((claim_adapter(adapter)) != 1) { - free_adapter_object(adapter); - - return -ENODEV; - } + ret = claim_adapter(adapter); + if (ret < 0) + goto err_kfree; irq_dma_enable_disable_irq(adapter, 0); - if (request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter) != 0) { + ret = request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter); + if (ret < 0) { dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq); - - free_adapter_object(adapter); - - return -ENODEV; + goto err_release_adapter; } read_reg_dw(adapter, 0x208); @@ -1908,13 +1904,9 @@ write_reg_dw(adapter, 0x210, 0xb2ff); write_reg_dw(adapter, 0x208, 0x40); - init_dma_queue(adapter); - - if ((adapter->dma_status & 0x30000000) == 0) { - free_adapter_object(adapter); - - return -ENODEV; - } + ret = init_dma_queue(adapter); + if (ret < 0) + goto err_free_irq; adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18); @@ -1931,11 +1923,8 @@ default: printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision); printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__); - free_adapter_object(adapter); - pci_set_drvdata(pdev, NULL); - release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - return -ENODEV; + ret = -ENODEV; + goto err_free_dma_queue; } decide_how_many_hw_filters(adapter); @@ -1979,16 +1968,26 @@ ctrl_enable_mac(adapter, 1); } - spin_lock_init(&adapter->lock); + adapter->lock = SPIN_LOCK_UNLOCKED; - return 0; +out: + return ret; + +err_free_dma_queue: + free_dma_queue(adapter); +err_free_irq: + free_irq(pdev->irq, adapter); +err_release_adapter: + release_adapter(adapter); +err_kfree: + pci_set_drvdata(pdev, NULL); + kfree(adapter); + goto out; } static void driver_halt(struct pci_dev *pdev) { - struct adapter *adapter; - - adapter = pci_get_drvdata(pdev); + struct adapter *adapter = pci_get_drvdata(pdev); irq_dma_enable_disable_irq(adapter, 0); @@ -1998,9 +1997,9 @@ pci_set_drvdata(pdev, NULL); - release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); - - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + pci_disable_device(pdev); + pci_release_region(pdev, 1); + pci_release_region(pdev, 0); } static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) @@ -2325,11 +2324,22 @@ +static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct adapter* adapter = (struct adapter*) fe->dvb->priv; + + return request_firmware(fw, name, &adapter->pdev->dev); +} + +static struct nxt2002_config samsung_tbmv_config = { + .demod_address = 0x0A, + .request_firmware = nxt2002_request_firmware, +}; static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) { - static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d }; + static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; static u8 mt352_reset [] = { 0x50, 0x80 }; static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; @@ -2407,7 +2417,15 @@ static void frontend_init(struct adapter *skystar2) { switch(skystar2->pdev->device) { - case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 + case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC) + + // Attempt to load the Nextwave nxt2002 for ATSC support + skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe_sleep = skystar2->fe->ops->sleep; + skystar2->fe->ops->sleep = flexcop_sleep; + break; + } // try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935)) skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); @@ -2462,26 +2480,24 @@ struct adapter *adapter; struct dvb_adapter *dvb_adapter; struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret = -ENODEV; - int ret; - - if (pdev == NULL) - return -ENODEV; + if (!pdev) + goto out; - if (driver_initialize(pdev) != 0) - return -ENODEV; - - dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name, THIS_MODULE); + ret = driver_initialize(pdev); + if (ret < 0) + goto out; - if (dvb_adapter == NULL) { + ret = dvb_register_adapter(&dvb_adapter, skystar2_pci_driver.name, + THIS_MODULE); + if (ret < 0) { printk("%s: Error registering DVB adapter\n", __FUNCTION__); - - driver_halt(pdev); - - return -ENODEV; + goto err_halt; } - adapter = (struct adapter *) pci_get_drvdata(pdev); + adapter = pci_get_drvdata(pdev); dvb_adapter->priv = adapter; adapter->dvb_adapter = dvb_adapter; @@ -2504,14 +2520,13 @@ adapter->i2c_adap.algo_data = NULL; adapter->i2c_adap.id = I2C_ALGO_BIT; - if (i2c_add_adapter(&adapter->i2c_adap) < 0) { - dvb_unregister_adapter (adapter->dvb_adapter); - return -ENOMEM; - } + ret = i2c_add_adapter(&adapter->i2c_adap); + if (ret < 0) + goto err_dvb_unregister; dvbdemux = &adapter->demux; - dvbdemux->priv = (void *) adapter; + dvbdemux->priv = adapter; dvbdemux->filternum = N_PID_SLOTS; dvbdemux->feednum = N_PID_SLOTS; dvbdemux->start_feed = dvb_start_feed; @@ -2519,68 +2534,87 @@ dvbdemux->write_to_decoder = NULL; dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - dvb_dmx_init(&adapter->demux); + ret = dvb_dmx_init(&adapter->demux); + if (ret < 0) + goto err_i2c_del; - adapter->hw_frontend.source = DMX_FRONTEND_0; + dmx = &dvbdemux->dmx; + adapter->hw_frontend.source = DMX_FRONTEND_0; adapter->dmxdev.filternum = N_PID_SLOTS; - adapter->dmxdev.demux = &dvbdemux->dmx; + adapter->dmxdev.demux = dmx; adapter->dmxdev.capabilities = 0; - dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter); + ret = dvb_dmxdev_init(&adapter->dmxdev, adapter->dvb_adapter); + if (ret < 0) + goto err_dmx_release; - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->hw_frontend); + ret = dmx->add_frontend(dmx, &adapter->hw_frontend); if (ret < 0) - return ret; + goto err_dmxdev_release; adapter->mem_frontend.source = DMX_MEMORY_FE; - ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &adapter->mem_frontend); + ret = dmx->add_frontend(dmx, &adapter->mem_frontend); if (ret < 0) - return ret; + goto err_remove_hw_frontend; - ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &adapter->hw_frontend); + ret = dmx->connect_frontend(dmx, &adapter->hw_frontend); if (ret < 0) - return ret; + goto err_remove_mem_frontend; dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); frontend_init(adapter); +out: + return ret; - return 0; +err_remove_mem_frontend: + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend); +err_remove_hw_frontend: + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend); +err_dmxdev_release: + dvb_dmxdev_release(&adapter->dmxdev); +err_dmx_release: + dvb_dmx_release(&adapter->demux); +err_i2c_del: + i2c_del_adapter(&adapter->i2c_adap); +err_dvb_unregister: + dvb_unregister_adapter(adapter->dvb_adapter); +err_halt: + driver_halt(pdev); + goto out; } static void skystar2_remove(struct pci_dev *pdev) { - struct adapter *adapter; + struct adapter *adapter = pci_get_drvdata(pdev); struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; - if (pdev == NULL) + if (!adapter) return; - adapter = pci_get_drvdata(pdev); - - if (adapter != NULL) { dvb_net_release(&adapter->dvbnet); dvbdemux = &adapter->demux; + dmx = &dvbdemux->dmx; - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend); + dmx->close(dmx); + dmx->remove_frontend(dmx, &adapter->hw_frontend); + dmx->remove_frontend(dmx, &adapter->mem_frontend); dvb_dmxdev_release(&adapter->dmxdev); - dvb_dmx_release(&adapter->demux); + dvb_dmx_release(dvbdemux); + + if (adapter->fe != NULL) + dvb_unregister_frontend(adapter->fe); - if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe); + dvb_unregister_adapter(adapter->dvb_adapter); - if (adapter->dvb_adapter != NULL) { i2c_del_adapter(&adapter->i2c_adap); - dvb_unregister_adapter(adapter->dvb_adapter); - } driver_halt(pdev); } -} static struct pci_device_id skystar2_pci_tbl[] = { {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, diff -Nru a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig --- a/drivers/media/dvb/bt8xx/Kconfig 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/bt8xx/Kconfig 2005-01-23 21:02:28 -08:00 @@ -3,6 +3,8 @@ depends on DVB_CORE && PCI && VIDEO_BT848 select DVB_MT352 select DVB_SP887X + select DVB_NXT6000 + select DVB_CX24110 help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards and Twinhan DST cards. @@ -10,9 +12,6 @@ Since these cards have no MPEG decoder onboard, they transmit only compressed MPEG data over the PCI bus, so you need an external software decoder to watch TV on your computer. - - If you have a Twinhan card, don't forget to select - "Twinhan DST based DVB-S/-T frontend". Say Y if you own such a device and want to use it. 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c 2005-01-23 21:02:28 -08:00 @@ -181,6 +181,70 @@ .pll_set = thomson_dtt7579_pll_set, }; +static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u32 freq = params->frequency; + + int i, a, n, pump; + u32 band, pll; + + + u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, + 1576000,1718000,1856000,2036000,2150000}; + 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 */ + printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); + + /* This is really the bit driving the tuner chip cx24108 */ + + 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;(ibt->dev->dev); } -struct sp887x_config microtune_mt7202dtf_config = { +static struct sp887x_config microtune_mt7202dtf_config = { .demod_address = 0x70, .pll_set = microtune_mt7202dtf_pll_set, @@ -387,6 +451,13 @@ break; } break; + + case BTTV_PINNACLESAT: + card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter); + if (card->fe != NULL) { + break; + } + break; } if (card->fe == NULL) { @@ -510,7 +581,14 @@ switch(sub->core->type) { -/* case BTTV_PINNACLESAT: UNDEFINED HARDWARE */ + case BTTV_PINNACLESAT: + card->gpio_mode = 0x0400c060; + /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, + BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ + card->op_sync_orin = 0; + card->irq_err_ignore = 0; + break; + #ifdef BTTV_DVICO_DVBT_LITE case BTTV_DVICO_DVBT_LITE: #endif 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h 2005-01-23 21:02:28 -08:00 @@ -22,6 +22,9 @@ * */ +#ifndef DVB_BT8XX_H +#define DVB_BT8XX_H + #include #include "dvbdev.h" #include "dvb_net.h" @@ -30,6 +33,7 @@ #include "sp887x.h" #include "dst.h" #include "nxt6000.h" +#include "cx24110.h" struct dvb_bt8xx_card { struct semaphore lock; @@ -50,3 +54,5 @@ struct dvb_frontend* fe; }; + +#endif /* DVB_BT8XX_H */ diff -Nru a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig --- a/drivers/media/dvb/dibusb/Kconfig 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dibusb/Kconfig 2005-01-23 21:02:28 -08:00 @@ -1,12 +1,13 @@ config DVB_DIBUSB - tristate "DiBcom USB DVB-T devices (see help for device list)" + tristate "DiBcom USB DVB-T devices (see help for a complete device list)" depends on DVB_CORE && USB select FW_LOADER select DVB_DIB3000MB select DVB_DIB3000MC + select DVB_MT352 help Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by - DiBcom (). + DiBcom (http://www.dibcom.fr) and C&E. Devices supported by this driver: @@ -14,12 +15,14 @@ TwinhanDTV Magic Box (VP7041e) KWorld V-Stream XPERT DTV - DVB-T USB Hama DVB-T USB-Box - DiBcom reference device (non-public) + DiBcom reference devices (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 + Artec T1 USB1.1 and USB2.0 boxes + Yakumo/Typhoon DVB-T USB2.0 + Hanftek UMT-010 USB2.0 The VP7041 seems to be identical to "CTS Portable" (Chinese Television System). @@ -27,7 +30,7 @@ These devices can be understood as budget ones, they "only" deliver (a part of) the MPEG2 transport stream. - A firmware is needed to get the device working. See + 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 @@ -46,6 +49,7 @@ 0x0574:0x2235 (Artec T1 USB1.1, cold) 0x04b4:0x8613 (Artec T1 USB2.0, cold) 0x0574:0x1002 (Artec T1 USB2.0, warm) + 0x0574:0x2131 (aged DiBcom USB1.1 test device) Say Y if your device has one of the mentioned IDs. diff -Nru a/drivers/media/dvb/dibusb/Makefile b/drivers/media/dvb/dibusb/Makefile --- a/drivers/media/dvb/dibusb/Makefile 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dibusb/Makefile 2005-01-23 21:02:28 -08:00 @@ -1,3 +1,11 @@ +dvb-dibusb-objs = dvb-dibusb-core.o \ + dvb-dibusb-dvb.o \ + dvb-dibusb-fe-i2c.o \ + dvb-dibusb-firmware.o \ + dvb-dibusb-remote.o \ + dvb-dibusb-usb.o \ + dvb-dibusb-pid.o + obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-core.c b/drivers/media/dvb/dibusb/dvb-dibusb-core.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-core.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,471 @@ +/* + * Driver for mobile USB Budget DVB-T devices based on reference + * design made by DiBcom (http://www.dibcom.fr/) + * + * dvb-dibusb-core.c + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * based on GPL code from DiBcom, which has + * 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. + * + * Acknowledgements + * + * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver + * sources, on which this driver (and the dib3000mb/mc/p frontends) are based. + * + * see Documentation/dvb/README.dibusb for more information + */ +#include "dvb-dibusb.h" + +#include + +/* debug */ +#ifdef CONFIG_DVB_DIBCOM_DEBUG +int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))."); +#endif + +int pid_parse; +module_param(pid_parse, int, 0644); +MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0"); + +int rc_query_interval; +module_param(rc_query_interval, int, 0644); +MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)"); + +/* Vendor IDs */ +#define USB_VID_ANCHOR 0x0547 +#define USB_VID_AVERMEDIA 0x14aa +#define USB_VID_COMPRO 0x185b +#define USB_VID_COMPRO_UNK 0x145f +#define USB_VID_CYPRESS 0x04b4 +#define USB_VID_DIBCOM 0x10b8 +#define USB_VID_EMPIA 0xeb1a +#define USB_VID_GRANDTEC 0x5032 +#define USB_VID_HYPER_PALTEK 0x1025 +#define USB_VID_HANFTEK 0x15f4 +#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_COMPRO_DVBU2000_UNK_COLD 0x010c +#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d +#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_DIBCOM_ANCHOR_2135_COLD 0x2131 +#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_ULTIMA_TVBOX_USB2_COLD 0x8109 +#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 +#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 +#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e +#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f +#define USB_PID_HANFTEK_UMT_010_COLD 0x0001 +#define USB_PID_HANFTEK_UMT_010_WARM 0x0025 +#define USB_PID_YAKUMO_DTT200U_COLD 0x0201 +#define USB_PID_YAKUMO_DTT200U_WARM 0x0301 + +/* USB Driver stuff + * table of devices that this driver is working with + * + * ATTENTION: Never ever change the order of this table, the particular + * devices depend on this order + * + * Each entry is used as a reference in the device_struct. Currently this is + * the only non-redundant way of assigning USB ids to actual devices I'm aware + * of, because there is only one place in the code where the assignment of + * vendor and product id is done, here. + */ +static struct usb_device_id dib_table [] = { +/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_COLD)}, +/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_WARM)}, +/* 02 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_COLD) }, + +/* the following device is actually not supported, but when loading the + * correct firmware (ie. its usb ids will change) everything works fine then + */ +/* 03 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_WARM) }, + +/* 04 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, +/* 05 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, +/* 06 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, +/* 07 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, +/* 08 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, +/* 09 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, +/* 10 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, +/* 11 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, +/* 12 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, +/* 13 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, +/* 14 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, +/* 15 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, +/* 16 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, +/* 17 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, +/* 18 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, +/* 19 */ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_COLD) }, +/* 20 */ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_WARM) }, +/* 21 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, +/* 22 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, +/* 23 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, +/* 24 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, +/* 25 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, +/* 26 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, +/* 27 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, + +/* 28 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, +/* 29 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, + +/* + * activate the following define when you have one of the devices and want to + * build it from build-2.6 in dvb-kernel + */ +// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES +#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES +/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +/* 31 */ { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) }, +/* 32 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) }, +/* 33 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_DIBCOM_ANCHOR_2135_COLD) }, +#endif + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, dib_table); + +static struct dibusb_usb_controller dibusb_usb_ctrl[] = { + { .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 }, + { .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 }, + { .name = "Cypress FX2", .cpu_cs_register = 0xe600 }, +}; + +struct dibusb_tuner dibusb_tuner[] = { + { DIBUSB_TUNER_CABLE_THOMSON, + 0x61 + }, + { DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5, + 0x60 + }, + { DIBUSB_TUNER_CABLE_LG_TDTP_E102P, + 0x61 + }, + { DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5, + 0x60 + }, +}; + +static struct dibusb_demod dibusb_demod[] = { + { DIBUSB_DIB3000MB, + 16, + { 0x8, 0 }, + }, + { DIBUSB_DIB3000MC, + 32, + { 0x9, 0xa, 0xb, 0xc }, + }, + { DIBUSB_MT352, + 254, + { 0xf, 0 }, + }, +}; + +static struct dibusb_device_class dibusb_device_classes[] = { + { .id = DIBUSB1_1, .usb_ctrl = &dibusb_usb_ctrl[0], + .firmware = "dvb-dibusb-5.0.0.11.fw", + .pipe_cmd = 0x01, .pipe_data = 0x02, + .urb_count = 3, .urb_buffer_size = 4096, + DIBUSB_RC_NEC_PROTOCOL, + &dibusb_demod[DIBUSB_DIB3000MB], + &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON], + }, + { DIBUSB1_1_AN2235, &dibusb_usb_ctrl[1], + "dvb-dibusb-an2235-1.fw", + 0x01, 0x02, + 3, 4096, + DIBUSB_RC_NEC_PROTOCOL, + &dibusb_demod[DIBUSB_DIB3000MB], + &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON], + }, + { DIBUSB2_0,&dibusb_usb_ctrl[2], + "dvb-dibusb-6.0.0.5.fw", + 0x01, 0x06, + 3, 188*210, + DIBUSB_RC_NEC_PROTOCOL, + &dibusb_demod[DIBUSB_DIB3000MC], + &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5], + }, + { UMT2_0, &dibusb_usb_ctrl[2], + "dvb-dibusb-umt-1.fw", + 0x01, 0x02, + 15, 188*21, + DIBUSB_RC_NO, + &dibusb_demod[DIBUSB_MT352], +// &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5], + &dibusb_tuner[DIBUSB_TUNER_CABLE_LG_TDTP_E102P], + }, +}; + +static struct dibusb_usb_device dibusb_devices[] = { + { "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[19], &dib_table[21], NULL}, + { &dib_table[20], &dib_table[22], NULL}, + }, + { "KWorld V-Stream XPERT DTV - DVB-T USB1.1", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[11], NULL }, + { &dib_table[12], NULL }, + }, + { "Grandtec USB1.1 DVB-T", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[13], &dib_table[15], NULL }, + { &dib_table[14], &dib_table[16], NULL }, + }, + { "DiBcom USB1.1 DVB-T reference design (MOD3000)", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[7], NULL }, + { &dib_table[8], NULL }, + }, + { "Artec T1 USB1.1 TVBOX with AN2135", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[23], NULL }, + { &dib_table[24], NULL }, + }, + { "Artec T1 USB1.1 TVBOX with AN2235", + &dibusb_device_classes[DIBUSB1_1_AN2235], + { &dib_table[25], NULL }, + { &dib_table[26], NULL }, + }, + { "Avermedia AverTV DVBT USB1.1", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[0], NULL }, + { &dib_table[1], NULL }, + }, + { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[4], &dib_table[6], NULL}, + { &dib_table[5], NULL }, + }, + { "Unkown USB1.1 DVB-T device ???? please report the name to the author", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[17], NULL }, + { &dib_table[18], NULL }, + }, + { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", + &dibusb_device_classes[DIBUSB2_0], + { &dib_table[9], NULL }, + { &dib_table[10], NULL }, + }, + { "Artec T1 USB2.0 TVBOX (please report the warm ID)", + &dibusb_device_classes[DIBUSB2_0], + { &dib_table[27], NULL }, + { NULL }, + }, + { "AVermedia/Yakumo/Hama/Typhoon DVB-T USB2.0", + &dibusb_device_classes[UMT2_0], + { &dib_table[2], NULL }, + { NULL }, + }, + { "Hanftek UMT-010 DVB-T USB2.0", + &dibusb_device_classes[UMT2_0], + { &dib_table[28], NULL }, + { &dib_table[29], NULL }, + }, +#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES + { "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)", + &dibusb_device_classes[DIBUSB1_1_AN2235], + { &dib_table[30], NULL }, + { NULL }, + }, + { "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)", + &dibusb_device_classes[DIBUSB2_0], + { &dib_table[31], NULL }, + { &dib_table[32], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */ + }, + { "DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs", + &dibusb_device_classes[DIBUSB1_1], + { &dib_table[33], NULL }, + { NULL }, + }, +#endif +}; + +static int dibusb_exit(struct usb_dibusb *dib) +{ + deb_info("init_state before exiting everything: %x\n",dib->init_state); + dibusb_remote_exit(dib); + dibusb_fe_exit(dib); + dibusb_i2c_exit(dib); + dibusb_pid_list_exit(dib); + dibusb_dvb_exit(dib); + dibusb_urb_exit(dib); + deb_info("init_state should be zero now: %x\n",dib->init_state); + dib->init_state = DIBUSB_STATE_INIT; + kfree(dib); + return 0; +} + +static int dibusb_init(struct usb_dibusb *dib) +{ + int ret = 0; + sema_init(&dib->usb_sem, 1); + sema_init(&dib->i2c_sem, 1); + + dib->init_state = DIBUSB_STATE_INIT; + + if ((ret = dibusb_urb_init(dib)) || + (ret = dibusb_dvb_init(dib)) || + (ret = dibusb_pid_list_init(dib)) || + (ret = dibusb_i2c_init(dib))) { + dibusb_exit(dib); + return ret; + } + + if ((ret = dibusb_fe_init(dib))) + err("could not initialize a frontend."); + + if ((ret = dibusb_remote_init(dib))) + err("could not initialize remote control."); + + return 0; +} + +static struct dibusb_usb_device * dibusb_find_device (struct usb_device *udev,int *cold) +{ + int i,j; + *cold = -1; + for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) { + for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].cold_ids[j] != NULL; j++) { + deb_info("check for cold %x %x\n",dibusb_devices[i].cold_ids[j]->idVendor, dibusb_devices[i].cold_ids[j]->idProduct); + if (dibusb_devices[i].cold_ids[j]->idVendor == udev->descriptor.idVendor && + dibusb_devices[i].cold_ids[j]->idProduct == udev->descriptor.idProduct) { + *cold = 1; + return &dibusb_devices[i]; + } + } + + for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].warm_ids[j] != NULL; j++) { + deb_info("check for warm %x %x\n",dibusb_devices[i].warm_ids[j]->idVendor, dibusb_devices[i].warm_ids[j]->idProduct); + if (dibusb_devices[i].warm_ids[j]->idVendor == udev->descriptor.idVendor && + dibusb_devices[i].warm_ids[j]->idProduct == udev->descriptor.idProduct) { + *cold = 0; + return &dibusb_devices[i]; + } + } + } + return NULL; +} + +/* + * USB + */ +static int dibusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_dibusb *dib = NULL; + struct dibusb_usb_device *dibdev = NULL; + + int ret = -ENOMEM,cold=0; + + if ((dibdev = dibusb_find_device(udev,&cold)) == NULL) { + err("something went very wrong, " + "unknown product ID: %.4x",udev->descriptor.idProduct); + return -ENODEV; + } + + if (cold == 1) { + info("found a '%s' in cold state, will try to load a firmware",dibdev->name); + ret = dibusb_loadfirmware(udev,dibdev); + } else { + info("found a '%s' in warm state.",dibdev->name); + dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL); + if (dib == NULL) { + err("no memory"); + return ret; + } + memset(dib,0,sizeof(struct usb_dibusb)); + + dib->udev = udev; + dib->dibdev = dibdev; + + usb_set_intfdata(intf, dib); + + ret = dibusb_init(dib); + } + + if (ret == 0) + info("%s successfully initialized and connected.",dibdev->name); + else + info("%s error while loading driver (%d)",dibdev->name,ret); + return ret; +} + +static void dibusb_disconnect(struct usb_interface *intf) +{ + struct usb_dibusb *dib = usb_get_intfdata(intf); + const char *name = DRIVER_DESC; + + usb_set_intfdata(intf,NULL); + if (dib != NULL && dib->dibdev != NULL) { + name = dib->dibdev->name; + dibusb_exit(dib); + } + info("%s successfully deinitialized and disconnected.",name); + +} + +/* usb specific object needed to register this driver with the usb subsystem */ +struct usb_driver dibusb_driver = { + .owner = THIS_MODULE, + .name = DRIVER_DESC, + .probe = dibusb_probe, + .disconnect = dibusb_disconnect, + .id_table = dib_table, +}; + +/* module stuff */ +static int __init usb_dibusb_init(void) +{ + int result; + if ((result = usb_register(&dibusb_driver))) { + err("usb_register failed. Error number %d",result); + return result; + } + + return 0; +} + +static void __exit usb_dibusb_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&dibusb_driver); +} + +module_init (usb_dibusb_init); +module_exit (usb_dibusb_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,205 @@ +/* + * dvb-dibusb-dvb.c is part of the driver for mobile USB Budget DVB-T devices + * based on reference design made by DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * see dvb-dibusb-core.c for more copyright details. + * + * This file contains functions for initializing and handling the + * linux-dvb API. + */ +#include "dvb-dibusb.h" + +#include +#include + +static u32 urb_compl_count; + +/* + * MPEG2 TS DVB stuff + */ +void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs) +{ + struct usb_dibusb *dib = urb->context; + int ret; + + deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status, + urb->actual_length); + + urb_compl_count++; + if (urb_compl_count % 500 == 0) + deb_info("%d urbs completed so far.\n",urb_compl_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + warn("urb completition error %d.", urb->status); + } + + if (dib->feedcount > 0) { + deb_ts("URB return len: %d\n",urb->actual_length); + if (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, at least for USB1.1 + * + * if (urb->actual_length == dib->dibdev->parm->default_size && dib->dvb_is_ready) */ + if (dib->init_state & DIBUSB_STATE_DVB) + dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length); + else + deb_ts("URB dropped because of the " + "actual_length or !dvb_is_ready (%d).\n",dib->init_state & DIBUSB_STATE_DVB); + } else + deb_ts("URB dropped because of feedcount.\n"); + + ret = usb_submit_urb(urb,GFP_ATOMIC); + deb_ts("urb resubmitted, (%d)\n",ret); +} + +static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + struct usb_dibusb *dib = dvbdmxfeed->demux->priv; + int newfeedcount; + + if (dib == NULL) + return -ENODEV; + + newfeedcount = dib->feedcount + (onoff ? 1 : -1); + + /* + * stop feed before setting a new pid if there will be no pid anymore + */ +// if ((dib->dibdev->parm->firmware_bug && dib->feedcount) || + if (newfeedcount == 0) { + 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; + } + } + } + + dib->feedcount = newfeedcount; + + /* get a free pid from the list and activate it on the device + * specific pid_filter + */ + if (dib->pid_parse) + dibusb_ctrl_pid(dib,dvbdmxfeed,onoff); + + /* + * start the feed, either if there is the firmware bug or + * if this was the first pid to set and there is still a pid for + * reception. + */ + +// if ((dib->dibdev->parm->firmware_bug) + if (dib->feedcount == onoff && dib->feedcount > 0) { + + deb_ts("controlling pid parser\n"); + if (dib->xfer_ops.pid_parse != NULL) { + if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) { + err("could not handle pid_parser"); + } + } + + 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; + } + } + dibusb_streaming(dib,1); + } + return 0; +} + +static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); + return dibusb_ctrl_feed(dvbdmxfeed,1); +} + +static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); + return dibusb_ctrl_feed(dvbdmxfeed,0); +} + +int dibusb_dvb_init(struct usb_dibusb *dib) +{ + int ret; + + urb_compl_count = 0; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4) + if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC)) < 0) { +#else + if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC , + THIS_MODULE)) < 0) { +#endif + deb_info("dvb_register_adapter failed: error %d", ret); + goto err; + } + dib->adapter->priv = dib; + +/* i2c is done in dibusb_i2c_init */ + + dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; + + dib->demux.priv = (void *)dib; + /* get pidcount from demod */ + dib->demux.feednum = dib->demux.filternum = 255; + dib->demux.start_feed = dibusb_start_feed; + dib->demux.stop_feed = dibusb_stop_feed; + dib->demux.write_to_decoder = NULL; + if ((ret = dvb_dmx_init(&dib->demux)) < 0) { + err("dvb_dmx_init failed: error %d",ret); + goto err_dmx; + } + + dib->dmxdev.filternum = dib->demux.filternum; + dib->dmxdev.demux = &dib->demux.dmx; + dib->dmxdev.capabilities = 0; + if ((ret = dvb_dmxdev_init(&dib->dmxdev, dib->adapter)) < 0) { + err("dvb_dmxdev_init failed: error %d",ret); + goto err_dmx_dev; + } + + dvb_net_init(dib->adapter, &dib->dvb_net, &dib->demux.dmx); + + goto success; +err_dmx_dev: + dvb_dmx_release(&dib->demux); +err_dmx: + dvb_unregister_adapter(dib->adapter); +err: + return ret; +success: + dib->init_state |= DIBUSB_STATE_DVB; + return 0; +} + +int dibusb_dvb_exit(struct usb_dibusb *dib) +{ + if (dib->init_state & DIBUSB_STATE_DVB) { + dib->init_state &= ~DIBUSB_STATE_DVB; + 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); + dvb_unregister_adapter(dib->adapter); + } + return 0; +} diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,598 @@ +/* + * dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices + * based on reference design made by DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * see dvb-dibusb-core.c for more copyright details. + * + * This file contains functions for attaching, initializing of an appropriate + * demodulator/frontend. I2C-stuff is also located here. + * + */ +#include "dvb-dibusb.h" + +#include + +int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ + /* write only ? */ + int wo = (rbuf == NULL || rlen == 0), + len = 2 + wlen + (wo ? 0 : 2); + + sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; + sndbuf[1] = (addr << 1) | (wo ? 0 : 1); + + memcpy(&sndbuf[2],wbuf,wlen); + + if (!wo) { + sndbuf[wlen+2] = (rlen >> 8) & 0xff; + sndbuf[wlen+3] = rlen & 0xff; + } + + return dibusb_readwrite_usb(dib,sndbuf,len,rbuf,rlen); +} + +/* + * I2C master xfer function + */ +static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) +{ + struct usb_dibusb *dib = i2c_get_adapdata(adap); + int i; + + if (down_interruptible(&dib->i2c_sem) < 0) + return -EAGAIN; + + if (num > 2) + warn("more than 2 i2c messages at a time is not handled yet. TODO."); + + for (i = 0; i < num; i++) { + /* write/read request */ + if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len, + msg[i+1].buf,msg[i+1].len) < 0) + break; + i++; + } else + if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) + break; + } + + up(&dib->i2c_sem); + return i; +} + +static u32 dibusb_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dibusb_algo = { + .name = "DiBcom USB i2c algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = dibusb_i2c_xfer, + .functionality = dibusb_i2c_func, +}; + +static int dibusb_general_demod_init(struct dvb_frontend *fe); +static u8 dibusb_general_pll_addr(struct dvb_frontend *fe); +static int dibusb_general_pll_init(struct dvb_frontend *fe, u8 pll_buf[5]); +static int dibusb_general_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters* params, u8 pll_buf[5]); + +static struct mt352_config mt352_hanftek_umt_010_config = { + .demod_address = 0x1e, + .demod_init = dibusb_general_demod_init, + .pll_set = dibusb_general_pll_set, +}; + +static int dibusb_tuner_quirk(struct usb_dibusb *dib) +{ + switch (dib->dibdev->dev_cl->id) { + case DIBUSB1_1: /* some these device have the ENV77H11D5 and some the THOMSON CABLE */ + case DIBUSB1_1_AN2235: { /* actually its this device, but in warm state they are indistinguishable */ + struct dibusb_tuner *t; + u8 b[2] = { 0,0 } ,b2[1]; + struct i2c_msg msg[2] = { + { .flags = 0, .buf = b, .len = 2 }, + { .flags = I2C_M_RD, .buf = b2, .len = 1}, + }; + + t = &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5]; + + msg[0].addr = msg[1].addr = t->pll_addr; + + if (dib->xfer_ops.tuner_pass_ctrl != NULL) + dib->xfer_ops.tuner_pass_ctrl(dib->fe,1,t->pll_addr); + dibusb_i2c_xfer(&dib->i2c_adap,msg,2); + if (dib->xfer_ops.tuner_pass_ctrl != NULL) + dib->xfer_ops.tuner_pass_ctrl(dib->fe,0,t->pll_addr); + + if (b2[0] == 0xfe) + info("this device has the Thomson Cable onboard. Which is default."); + else { + dib->tuner = t; + info("this device has the Panasonic ENV77H11D5 onboard."); + } + break; + } + default: + break; + } + return 0; +} + +/* there is a ugly pid_filter in the firmware of the umt devices, it is accessible + * by i2c address 0x8. Don't know how to deactivate it and how many rows it has. + */ +static int dibusb_umt_pid_control(struct dvb_frontend *fe, int index, int pid, int onoff) +{ + struct usb_dibusb *dib = fe->dvb->priv; + u8 b[3]; + b[0] = index; + if (onoff) { + b[1] = (pid >> 8) & 0xff; + b[2] = pid & 0xff; + } else { + b[1] = 0; + b[2] = 0; + } + dibusb_i2c_msg(dib, 0x8, b, 3, NULL,0); + dibusb_set_streaming_mode(dib,0); + dibusb_set_streaming_mode(dib,1); + return 0; +} + +int dibusb_fe_init(struct usb_dibusb* dib) +{ + struct dib3000_config demod_cfg; + int i; + + if (dib->init_state & DIBUSB_STATE_I2C) { + for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) && + dib->dibdev->dev_cl->demod->i2c_addrs[i] != 0; i++) { + + demod_cfg.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i]; + demod_cfg.pll_addr = dibusb_general_pll_addr; + demod_cfg.pll_set = dibusb_general_pll_set; + demod_cfg.pll_init = dibusb_general_pll_init; + + switch (dib->dibdev->dev_cl->demod->id) { + case DIBUSB_DIB3000MB: + dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops); + break; + case DIBUSB_DIB3000MC: + dib->fe = dib3000mc_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops); + break; + case DIBUSB_MT352: + mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i]; + dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap); + dib->xfer_ops.pid_ctrl = dibusb_umt_pid_control; + break; + } + if (dib->fe != NULL) { + info("found demodulator at i2c address 0x%x",dib->dibdev->dev_cl->demod->i2c_addrs[i]); + break; + } + } + if (dib->fe->ops->sleep != NULL) + dib->fe_sleep = dib->fe->ops->sleep; + dib->fe->ops->sleep = dibusb_hw_sleep; + + if (dib->fe->ops->init != NULL ) + dib->fe_init = dib->fe->ops->init; + dib->fe->ops->init = dibusb_hw_wakeup; + + /* setting the default tuner */ + dib->tuner = dib->dibdev->dev_cl->tuner; + + /* check which tuner is mounted on this device, in case this is unsure */ + dibusb_tuner_quirk(dib); + } + if (dib->fe == NULL) { + err("A frontend driver was not found for device '%s'.", + dib->dibdev->name); + return -ENODEV; + } else { + if (dvb_register_frontend(dib->adapter, dib->fe)) { + err("Frontend registration failed."); + if (dib->fe->ops->release) + dib->fe->ops->release(dib->fe); + dib->fe = NULL; + return -ENODEV; + } + } + return 0; +} + +int dibusb_fe_exit(struct usb_dibusb *dib) +{ + if (dib->fe != NULL) + dvb_unregister_frontend(dib->fe); + return 0; +} + +int dibusb_i2c_init(struct usb_dibusb *dib) +{ + int ret = 0; + + dib->adapter->priv = dib; + + strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE); +#ifdef I2C_ADAP_CLASS_TV_DIGITAL + dib->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, +#else + dib->i2c_adap.class = I2C_CLASS_TV_DIGITAL, +#endif + dib->i2c_adap.algo = &dibusb_algo; + dib->i2c_adap.algo_data = NULL; + dib->i2c_adap.id = I2C_ALGO_BIT; + + i2c_set_adapdata(&dib->i2c_adap, dib); + + if ((ret = i2c_add_adapter(&dib->i2c_adap)) < 0) + err("could not add i2c adapter"); + + dib->init_state |= DIBUSB_STATE_I2C; + + return ret; +} + +int dibusb_i2c_exit(struct usb_dibusb *dib) +{ + if (dib->init_state & DIBUSB_STATE_I2C) + i2c_del_adapter(&dib->i2c_adap); + dib->init_state &= ~DIBUSB_STATE_I2C; + return 0; +} + + +/* pll stuff, maybe removed soon (thx to Gerd/Andrew in advance) */ +static int thomson_cable_eu_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4]) +{ + u32 tfreq = (fep->frequency + 36125000) / 62500; + int vu,p0,p1,p2; + + if (fep->frequency > 403250000) + vu = 1, p2 = 1, p1 = 0, p0 = 1; + else if (fep->frequency > 115750000) + vu = 0, p2 = 1, p1 = 1, p0 = 0; + else if (fep->frequency > 44250000) + vu = 0, p2 = 0, p1 = 1, p0 = 1; + else + return -EINVAL; + + pllbuf[0] = (tfreq >> 8) & 0x7f; + pllbuf[1] = tfreq & 0xff; + pllbuf[2] = 0x8e; + pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0; + return 0; +} + +static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4]) +{ + u32 freq = fep->frequency; + u32 tfreq = ((freq + 36125000)*6 + 500000) / 1000000; + u8 TA, T210, R210, ctrl1, cp210, p4321; + if (freq > 858000000) { + err("frequency cannot be larger than 858 MHz."); + return -EINVAL; + } + + // contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0 + TA = 1; + T210 = 0; + R210 = 0x2; + ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210; + +// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES ***************** + if (freq < 470000000) + cp210 = 2; // VHF Low and High band ch E12 to E4 to E12 + else if (freq < 526000000) + cp210 = 4; // UHF band Ch E21 to E27 + else // if (freq < 862000000) + cp210 = 5; // UHF band ch E28 to E69 + +//********************* BW select ******************************* + if (freq < 153000000) + p4321 = 1; // BW selected for VHF low + else if (freq < 470000000) + p4321 = 2; // BW selected for VHF high E5 to E12 + else // if (freq < 862000000) + p4321 = 4; // BW selection for UHF E21 to E69 + + pllbuf[0] = (tfreq >> 8) & 0xff; + pllbuf[1] = (tfreq >> 0) & 0xff; + pllbuf[2] = 0xff & ctrl1; + pllbuf[3] = (cp210 << 5) | (p4321); + + return 0; +} + +/* + * 7 6 5 4 3 2 1 0 + * Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0 + * + * Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8 + * Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0 + * + * Control byte 1 1 T/A=1 T2 T1 T0 R2 R1 R0 + * 1 T/A=0 0 0 ATC AL2 AL1 AL0 + * + * Control byte 2 CP2 CP1 CP0 BS5 BS4 BS3 BS2 BS1 + * + * MA0/1 = programmable address bits + * R/~W = read/write bit (0 for writing) + * N14-0 = programmable LO frequency + * + * T/A = test AGC bit (0 = next 6 bits AGC setting, + * 1 = next 6 bits test and reference divider ratio settings) + * T2-0 = test bits + * R2-0 = reference divider ratio and programmable frequency step + * ATC = AGC current setting and time constant + * ATC = 0: AGC current = 220nA, AGC time constant = 2s + * ATC = 1: AGC current = 9uA, AGC time constant = 50ms + * AL2-0 = AGC take-over point bits + * CP2-0 = charge pump current + * BS5-1 = PMOS ports control bits; + * BSn = 0 corresponding port is off, high-impedance state (at power-on) + * BSn = 1 corresponding port is on + */ + + +static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4]) +{ + pllbuf[0] = 0x0b; + pllbuf[1] = 0xf5; + pllbuf[2] = 0x85; + pllbuf[3] = 0xab; + return 0; +} + +static int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend_parameters *fep,u8 pllbuf[4]) +{ + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = fep->frequency + 36166000; + 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 (fep->frequency < 49000000) + return -EINVAL; + else if (fep->frequency < 161000000) + band = 1; + else if (fep->frequency < 444000000) + band = 2; + else if (fep->frequency < 861000000) + band = 4; + else + return -EINVAL; + + // setup PLL filter + switch (fep->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + case BANDWIDTH_7_MHZ: + filter = 0; + break; + case BANDWIDTH_8_MHZ: + filter = 1; + break; + default: + return -EINVAL; + } + + // calculate divisor + // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((fep->frequency / 1000) * 6) + 217496) / 1000; + + // setup tuner buffer + pllbuf[0] = (tuner_frequency >> 8) & 0x7f; + pllbuf[1] = tuner_frequency & 0xff; + pllbuf[2] = 0xca; + pllbuf[3] = (cp << 5) | (filter << 3) | band; + return 0; +} + +/* + * 7 6 5 4 3 2 1 0 + * Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0 + * + * Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8 + * Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0 + * + * Control byte 1 CP T2 T1 T0 RSA RSB OS + * + * Band Switch byte X X X P4 P3 P2 P1 P0 + * + * Auxiliary byte ATC AL2 AL1 AL0 0 0 0 0 + * + * Address: MA1 MA0 Address + * 0 0 c0 + * 0 1 c2 (always valid) + * 1 0 c4 + * 1 1 c6 + * + * + * + */ + +static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4]) +{ + u32 div; + u8 p3210, p4; + +#define TUNER_MUL 62500 + + div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL; + + if (fep->frequency < 174500000) + p3210 = 1; // not supported by the tdtp_e102p + else if (fep->frequency < 230000000) // VHF + p3210 = 2; + else + p3210 = 4; + + if (fep->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) + p4 = 0; + else + p4 = 1; + + pllbuf[0] = (div >> 8) & 0x7f; + pllbuf[1] = div & 0xff; + pllbuf[2] = 0xce; + pllbuf[3] = (p4 << 4) | p3210; + + return 0; +} + +static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe) +{ + static u8 mt352_clock_config[] = { 0x89, 0xb0, 0x2d }; + static u8 mt352_reset[] = { 0x50, 0x80 }; + static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 }; + static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg[] = { 0x67, 0x14, 0x22 }; + static u8 mt352_sec_agc_cfg[] = { 0x69, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x40, 0x40 }; + + static u8 mt352_unk [] = { 0xb5, 0x7a }; + + static u8 mt352_acq_ctl[] = { 0x53, 0x5f }; + static u8 mt352_input_freq_1[] = { 0x56, 0xf1, 0x05 }; + +// 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_mclk_ratio, sizeof(mt352_mclk_ratio)); + + 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_sec_agc_cfg, sizeof(mt352_sec_agc_cfg)); + + mt352_write(fe, mt352_unk, sizeof(mt352_unk)); + + mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl)); + mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1)); + +// mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int dibusb_general_demod_init(struct dvb_frontend *fe) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + switch (dib->dibdev->dev_cl->id) { + case UMT2_0: + return lg_tdtp_e102p_mt352_demod_init(fe); + default: /* other device classes do not have device specific demod inits */ + break; + } + return 0; +} + +static u8 dibusb_general_pll_addr(struct dvb_frontend *fe) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + return dib->tuner->pll_addr; +} + +static int dibusb_pll_i2c_helper(struct usb_dibusb *dib, u8 pll_buf[5], u8 buf[4]) +{ + if (pll_buf == NULL) { + struct i2c_msg msg = { + .addr = dib->tuner->pll_addr, + .flags = 0, + .buf = buf, + .len = sizeof(buf) + }; + if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) + return -EIO; + msleep(1); + } else { + pll_buf[0] = dib->tuner->pll_addr << 1; + memcpy(&pll_buf[1],buf,4); + } + + return 0; +} + +static int dibusb_general_pll_init(struct dvb_frontend *fe, + u8 pll_buf[5]) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + u8 buf[4]; + int ret=0; + switch (dib->tuner->id) { + case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5: + ret = panasonic_cofdm_env77h11d5_tda6650_init(fe,buf); + break; + default: + break; + } + + if (ret) + return ret; + + return dibusb_pll_i2c_helper(dib,pll_buf,buf); +} + +static int dibusb_general_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep, u8 pll_buf[5]) +{ + struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; + u8 buf[4]; + int ret=0; + + switch (dib->tuner->id) { + case DIBUSB_TUNER_CABLE_THOMSON: + ret = thomson_cable_eu_pll_set(fep, buf); + break; + case DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5: + ret = panasonic_cofdm_env57h1xd5_pll_set(fep, buf); + break; + case DIBUSB_TUNER_CABLE_LG_TDTP_E102P: + ret = lg_tdtp_e102p_tua6034(fep, buf); + break; + case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5: + ret = panasonic_cofdm_env77h11d5_tda6650_set(fep,buf); + break; + default: + warn("no pll programming routine found for tuner %d.\n",dib->tuner->id); + ret = -ENODEV; + break; + } + + if (ret) + return ret; + + return dibusb_pll_i2c_helper(dib,pll_buf,buf); +} diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,85 @@ +/* + * dvb-dibusb-firmware.c is part of the driver for mobile USB Budget DVB-T devices + * based on reference design made by DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * see dvb-dibusb-core.c for more copyright details. + * + * This file contains functions for downloading the firmware to the device. + */ +#include "dvb-dibusb.h" + +#include +#include + +/* + * load a firmware packet to the device + */ +static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev,0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ); +} + +int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev) +{ + const struct firmware *fw = NULL; + u16 addr; + u8 *b,*p; + int ret = 0,i; + + if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) { + err("did not find a valid firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems.", + dibdev->dev_cl->firmware); + return ret; + } + + p = kmalloc(fw->size,GFP_KERNEL); + if (p != NULL) { + u8 reset; + /* + * you cannot use the fw->data as buffer for + * usb_control_msg, a new buffer has to be + * created + */ + memcpy(p,fw->data,fw->size); + + /* stop the CPU */ + reset = 1; + if ((ret = dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&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]; + addr = *((u16 *) &b[1]); + + ret = dibusb_writemem(udev,addr,&b[4],b[0]); + + if (ret != b[0]) { + err("error while transferring firmware " + "(transferred size: %d, block size: %d)", + ret,b[0]); + ret = -EINVAL; + break; + } + i += 5 + b[0]; + } + /* length in ret */ + if (ret > 0) + ret = 0; + /* restart the CPU */ + reset = 0; + if (ret || dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1) != 1) { + err("could not restart the USB controller CPU."); + ret = -EINVAL; + } + + kfree(p); + } else { + ret = -ENOMEM; + } + release_firmware(fw); + + return ret; +} diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-pid.c b/drivers/media/dvb/dibusb/dvb-dibusb-pid.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-pid.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,80 @@ +/* + * dvb-dibusb-pid.c is part of the driver for mobile USB Budget DVB-T devices + * based on reference design made by DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * see dvb-dibusb-core.c for more copyright details. + * + * This file contains functions for initializing and handling the internal + * pid-list. This pid-list mirrors the information currently stored in the + * devices pid-list. + */ +#include "dvb-dibusb.h" + +int dibusb_pid_list_init(struct usb_dibusb *dib) +{ + int i; + dib->pid_list = kmalloc(sizeof(struct dibusb_pid) * dib->dibdev->dev_cl->demod->pid_filter_count,GFP_KERNEL); + if (dib->pid_list == NULL) + return -ENOMEM; + + deb_xfer("initializing %d pids for the pid_list.\n",dib->dibdev->dev_cl->demod->pid_filter_count); + + dib->pid_list_lock = SPIN_LOCK_UNLOCKED; + memset(dib->pid_list,0,dib->dibdev->dev_cl->demod->pid_filter_count*(sizeof(struct dibusb_pid))); + for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++) { + dib->pid_list[i].index = i; + dib->pid_list[i].pid = 0; + dib->pid_list[i].active = 0; + } + + dib->init_state |= DIBUSB_STATE_PIDLIST; + return 0; +} + +void dibusb_pid_list_exit(struct usb_dibusb *dib) +{ + if (dib->init_state & DIBUSB_STATE_PIDLIST) + kfree(dib->pid_list); + dib->init_state &= ~DIBUSB_STATE_PIDLIST; +} + +/* fetch a pid from pid_list and set it on or off */ +int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff) +{ + int i,ret = -1; + unsigned long flags; + u16 pid = dvbdmxfeed->pid; + + if (onoff) { + spin_lock_irqsave(&dib->pid_list_lock,flags); + for (i=0; i < dib->dibdev->dev_cl->demod->pid_filter_count; i++) + if (!dib->pid_list[i].active) { + dib->pid_list[i].pid = pid; + dib->pid_list[i].active = 1; + ret = i; + break; + } + dvbdmxfeed->priv = &dib->pid_list[ret]; + spin_unlock_irqrestore(&dib->pid_list_lock,flags); + + if (dib->xfer_ops.pid_ctrl != NULL) + dib->xfer_ops.pid_ctrl(dib->fe,dib->pid_list[ret].index,dib->pid_list[ret].pid,1); + } else { + struct dibusb_pid *dpid = dvbdmxfeed->priv; + + if (dib->xfer_ops.pid_ctrl != NULL) + dib->xfer_ops.pid_ctrl(dib->fe,dpid->index,0,0); + + dpid->pid = 0; + dpid->active = 0; + ret = dpid->index; + } + + /* a free pid from the list */ + deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off"); + + return ret; +} + diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,197 @@ +/* + * dvb-dibusb-remote.c is part of the driver for mobile USB Budget DVB-T devices + * based on reference design made by DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * see dvb-dibusb-core.c for more copyright details. + * + * This file contains functions for handling the event device on the software + * side and the remote control on the hardware side. + */ +#include "dvb-dibusb.h" + +/* 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. */ + /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ + { 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */ + { 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */ + { 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */ + { 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */ + { 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */ + { 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */ + /* 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 }, +}; + +/* + * 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_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; + } + return 0; +} + +/* Remote-control poll function - called every dib->rc_query_interval ms to see + whether the remote control has received anything. */ +static void dibusb_remote_query(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)); +} + +int dibusb_remote_init(struct usb_dibusb *dib) +{ + int i; + + if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO) + return 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_remote_query, dib); + + /* Start the remote-control polling. */ + if (rc_query_interval < 40) + rc_query_interval = 100; /* default */ + + info("schedule remote query interval to %d msecs.",rc_query_interval); + schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(rc_query_interval)); + + dib->init_state |= DIBUSB_STATE_REMOTE; + + return 0; +} + +int dibusb_remote_exit(struct usb_dibusb *dib) +{ + if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO) + return 0; + + if (dib->init_state & DIBUSB_STATE_REMOTE) { + cancel_delayed_work(&dib->rc_query_work); + flush_scheduled_work(); + input_unregister_device(&dib->rc_input_dev); + } + dib->init_state &= ~DIBUSB_STATE_REMOTE; + return 0; +} diff -Nru a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,259 @@ +/* + * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices + * based on reference design made by DiBcom (http://www.dibcom.fr/) + * + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) + * + * see dvb-dibusb-core.c for more copyright details. + * + * This file contains functions for initializing and handling the + * usb specific stuff. + */ +#include "dvb-dibusb.h" + +#include +#include + +int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf, + u16 rlen) +{ + int actlen,ret = -ENOMEM; + + if (wbuf == NULL || wlen == 0) + return -EINVAL; + + if ((ret = down_interruptible(&dib->usb_sem))) + return ret; + + if (dib->feedcount && + wbuf[0] == DIBUSB_REQ_I2C_WRITE && + dib->dibdev->dev_cl->id == DIBUSB1_1) + deb_err("BUG: writing to i2c, while TS-streaming destroys the stream." + "(%x reg: %x %x)\n", wbuf[0],wbuf[2],wbuf[3]); + + debug_dump(wbuf,wlen); + + ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev, + dib->dibdev->dev_cl->pipe_cmd), 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, and no error before */ + if (!ret && rbuf && rlen) { + ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev, + dib->dibdev->dev_cl->pipe_cmd),rbuf,rlen,&actlen, + DIBUSB_I2C_TIMEOUT); + + if (ret) + err("recv bulk message failed: %d",ret); + else { + deb_alot("rlen: %d\n",rlen); + debug_dump(rbuf,actlen); + } + } + + up(&dib->usb_sem); + return ret; +} + +/* + * Cypress controls + */ + +#if 0 +/* + * #if 0'ing the following functions as they are not in use _now_, + * but probably will be sometime. + */ + +/* + * do not use this, just a workaround for a bug, + * which will hopefully never occur :). + */ +int dibusb_interrupt_read_loop(struct usb_dibusb *dib) +{ + u8 b[1] = { DIBUSB_REQ_INTR_READ }; + return dibusb_write_usb(dib,b,1); +} + +#endif +static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len) +{ + return dibusb_readwrite_usb(dib,buf,len,NULL,0); +} + +/* + * ioctl for the firmware + */ +static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen) +{ + u8 b[34]; + int size = plen > 32 ? 32 : plen; + memset(b,0,34); + b[0] = DIBUSB_REQ_SET_IOCTL; + b[1] = cmd; + + if (size > 0) + memcpy(&b[2],param,size); + + return dibusb_write_usb(dib,b,34); //2+size); +} + +/* + * ioctl for power control + */ +int dibusb_hw_wakeup(struct dvb_frontend *fe) +{ + struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv; + u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP }; + deb_info("dibusb-device is getting up.\n"); + dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1); + + if (dib->fe_init) + return dib->fe_init(fe); + + return 0; +} + +int dibusb_hw_sleep(struct dvb_frontend *fe) +{ + struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv; + u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP }; + deb_info("dibusb-device is going to bed.\n"); + dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1); + + if (dib->fe_sleep) + return dib->fe_sleep(fe); + + return 0; +} + +int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode) +{ + u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode }; + return dibusb_readwrite_usb(dib,b,2,NULL,0); +} + +int dibusb_streaming(struct usb_dibusb *dib,int onoff) +{ + switch (dib->dibdev->dev_cl->id) { + case DIBUSB2_0: + if (onoff) + return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0); + else + return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0); + break; + case UMT2_0: + return dibusb_set_streaming_mode(dib,onoff); + break; + default: + break; + } + return 0; +} + +int dibusb_urb_init(struct usb_dibusb *dib) +{ + int ret,i,bufsize; + + /* + * when reloading the driver w/o replugging the device + * a timeout occures, this helps + */ + usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd)); + usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd)); + usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data)); + + /* allocate the array for the data transfer URBs */ + dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL); + if (dib->urb_list == NULL) + return -ENOMEM; + memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *)); + + dib->init_state |= DIBUSB_STATE_URB_LIST; + + bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_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) { + deb_info("not enough memory.\n"); + return -ENOMEM; + } + deb_info("allocation complete\n"); + memset(dib->buffer,0,bufsize); + + dib->init_state |= DIBUSB_STATE_URB_BUF; + + /* allocate and submit the URBs */ + for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) { + if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) { + return -ENOMEM; + } + deb_info("submitting URB no. %d\n",i); + + usb_fill_bulk_urb( dib->urb_list[i], dib->udev, + usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data), + &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size], + dib->dibdev->dev_cl->urb_buffer_size, + dibusb_urb_complete, dib); + + dib->urb_list[i]->transfer_flags = 0; + + if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) { + err("could not submit buffer urb no. %d\n",i); + return ret; + } + dib->init_state |= DIBUSB_STATE_URB_SUBMIT; + } + + + dib->pid_parse = 1; + switch (dib->dibdev->dev_cl->id) { + case DIBUSB2_0: + if (dib->udev->speed == USB_SPEED_HIGH && !pid_parse) { + dib->pid_parse = 0; + info("running at HIGH speed, will deliver the complete TS."); + } else + info("will use pid_parsing."); + break; + default: + break; + } + + return 0; +} + +int dibusb_urb_exit(struct usb_dibusb *dib) +{ + int i; + if (dib->init_state & DIBUSB_STATE_URB_LIST) { + for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) { + if (dib->urb_list[i] != NULL) { + deb_info("killing URB no. %d.\n",i); + + /* stop the URBs */ + usb_kill_urb(dib->urb_list[i]); + + deb_info("freeing URB no. %d.\n",i); + /* free the URBs */ + usb_free_urb(dib->urb_list[i]); + } + } + /* free the urb array */ + kfree(dib->urb_list); + dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT; + dib->init_state &= ~DIBUSB_STATE_URB_LIST; + } + + if (dib->init_state & DIBUSB_STATE_URB_BUF) + pci_free_consistent(NULL, + dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count, + dib->buffer,dib->dma_handle); + + dib->init_state &= ~DIBUSB_STATE_URB_BUF; + return 0; +} 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 2005-01-23 21:02:28 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,1032 +0,0 @@ -/* - * Driver for mobile USB Budget DVB-T devices based on reference - * design made by DiBcom (http://www.dibcom.fr/) - * - * dvb-dibusb.c - * - * 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) - * - * 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. - * - * Acknowledgements - * - * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver - * sources, on which this driver (and the dib3000mb/mc/p frontends) are based. - * - * see Documentation/dvb/README.dibusb for more information - */ - -#include -#include -#include -#include -#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 */ -#ifdef CONFIG_DVB_DIBCOM_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) { printk(args); } } while (0) - -#define debug_dump(b,l) if (debug) {\ - int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \ - for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \ - deb_xfer("\n");\ -} - -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,32=rc (|-able))."); -#else -#define dprintk(args...) -#define debug_dump(b,l) -#endif - -#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) - -static int pid_parse; -module_param(pid_parse, int, 0x644); -MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0"); - -/* Version information */ -#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" - -static int dibusb_readwrite_usb(struct usb_dibusb *dib, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - int actlen,ret = -ENOMEM; - - if (wbuf == NULL || wlen == 0) - return -EINVAL; - - if ((ret = down_interruptible(&dib->usb_sem))) - return ret; - - 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)\n", wbuf[0],wbuf[2],wbuf[3]); - - debug_dump(wbuf,wlen); - - 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, and no error before */ - if (!ret && rbuf && rlen) { - 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); - else { - deb_alot("rlen: %d\n",rlen); - debug_dump(rbuf,actlen); - } - } - - up(&dib->usb_sem); - return ret; -} - -static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */ - /* write only ? */ - int wo = (rbuf == NULL || rlen == 0), - len = 2 + wlen + (wo ? 0 : 2); - - deb_alot("wo: %d, wlen: %d, len: %d\n",wo,wlen,len); - - sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ; - sndbuf[1] = (addr & 0xfe) | (wo ? 0 : 1); - - memcpy(&sndbuf[2],wbuf,wlen); - - if (!wo) { - sndbuf[wlen+2] = (rlen >> 8) & 0xff; - sndbuf[wlen+3] = rlen & 0xff; - } - - return dibusb_readwrite_usb(dib,sndbuf,len,rbuf,rlen); -} - -/* - * DVB stuff - */ -static void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs) -{ - struct usb_dibusb *dib = urb->context; - - deb_ts("urb complete feedcount: %d, status: %d\n",dib->feedcount,urb->status); - - if (dib->feedcount > 0 && urb->status == 0) { - deb_ts("URB return len: %d\n",urb->actual_length); - if (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 == 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 " - "actual_length or !dvb_is_ready (%d).\n",dib->dvb_is_ready); - } else - deb_ts("URB dropped because of feedcount or status.\n"); - - usb_submit_urb(urb,GFP_KERNEL); -} - -static int dibusb_ctrl_feed(struct usb_dibusb *dib, int pid, int onoff) -{ - 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; - } - } - - dib->feedcount += onoff ? 1 : -1; - - if (dib->pid_parse) { - 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; - } - } 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("controlling pid parser\n"); - if (dib->xfer_ops.pid_parse != NULL) { - if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) { - err("could not handle pid_parser"); - } - } - - 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; -} - } - return 0; -} - -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); -} - -static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - 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. */ - /* additional keys TwinHan VisionPlus, the Artec seemingly not have */ - { 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */ - { 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */ - { 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */ - { 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */ - { 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */ - { 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */ - /* 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 }, -}; - -/* - * 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_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; - } - - 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 functions as they are not in use _now_, - * but probably will be sometime. - */ - -/* - * 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 power control - */ -static int dibusb_hw_sleep(struct usb_dibusb *dib) -{ - u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP }; - return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1); -} - -#endif -static int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len) -{ - return dibusb_readwrite_usb(dib,buf,len,NULL,0); -} - -/* - * ioctl for the firmware - */ -static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen) -{ - u8 b[34]; - int size = plen > 32 ? 32 : plen; - b[0] = DIBUSB_REQ_SET_IOCTL; - b[1] = cmd; - memcpy(&b[2],param,size); - - return dibusb_write_usb(dib,b,2+size); -} - -static int dibusb_hw_wakeup(struct usb_dibusb *dib) -{ - u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP }; - return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1); -} - -/* - * I2C - */ -static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num) -{ - struct usb_dibusb *dib = i2c_get_adapdata(adap); - int i; - - if (down_interruptible(&dib->i2c_sem) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len, - msg[i+1].buf,msg[i+1].len) < 0) - break; - i++; - } else - if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) - break; - } - - up(&dib->i2c_sem); - return i; -} - -static u32 dibusb_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C; -} - -static int thomson_cable_eu_pll_set(struct dvb_frontend* fe, struct - dvb_frontend_parameters* params); - -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 = (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; -} - -static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct - dvb_frontend_parameters *params); - -static struct dib3000_config panasonic_cofdm_env57h1xd5 = { - .demod_address = 0x18, - .pll_addr = 192, - .pll_set = panasonic_cofdm_env57h1xd5_pll_set, -}; - -static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend *fe, struct - dvb_frontend_parameters *params) -{ - struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv; - u8 buf[4]; - u32 freq = params->frequency; - u32 tfreq = (freq + 36125000) / 1000000 * 6 + 1; - u8 TA, T210, R210, ctrl1, cp210, p4321; - struct i2c_msg msg = { - .addr = panasonic_cofdm_env57h1xd5.pll_addr, - .flags = 0, - .buf = buf, - .len = sizeof(buf) - }; - - if (freq > 858000000) { - err("frequency cannot be larger than 858 MHz."); - return -EINVAL; - } - - // contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0 - TA = 1; - T210 = 0; - R210 = 0x2; - ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210; - -// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES ***************** - if (freq < 470000000) - cp210 = 2; // VHF Low and High band ch E12 to E4 to E12 - else if (freq < 526000000) - cp210 = 4; // UHF band Ch E21 to E27 - else // if (freq < 862000000) - cp210 = 5; // UHF band ch E28 to E69 - -//********************* BW select ******************************* - if (freq < 153000000) - p4321 = 1; // BW selected for VHF low - else if (freq < 470000000) - p4321 = 2; // BW selected for VHF high E5 to E12 - else // if (freq < 862000000) - p4321 = 4; // BW selection for UHF E21 to E69 - - buf[0] = (tfreq >> 8) & 0xff; - buf[1] = (tfreq >> 0) & 0xff; - buf[2] = 0xff & ctrl1; - buf[3] = (cp210 << 5) | (p4321); - - if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1) - return -EIO; - - msleep(1); - return 0; -} - -static struct i2c_algorithm dibusb_algo = { - .name = "DiBcom USB i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = dibusb_i2c_xfer, - .functionality = dibusb_i2c_func, -}; - -static void frontend_init(struct usb_dibusb* dib) -{ - switch (dib->dibdev->parm->type) { - case DIBUSB1_1: - case DIBUSB1_1_AN2235: - dib->fe = dib3000mb_attach(&thomson_cable_eu_config, &dib->i2c_adap,&dib->xfer_ops); - break; - case DIBUSB2_0: - dib->fe = dib3000mc_attach(&panasonic_cofdm_env57h1xd5,&dib->i2c_adap, &dib->xfer_ops); - break; - } - - if (dib->fe == NULL) { - printk("dvb-dibusb: A frontend driver was not found for device %04x/%04x\n", - le16_to_cpu(dib->udev->descriptor.idVendor), - le16_to_cpu(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; - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,4) - if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC)) < 0) { -#else - if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC , - THIS_MODULE)) < 0) { -#endif - 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 - dib->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, -#else - dib->i2c_adap.class = I2C_CLASS_TV_DIGITAL, -#endif - dib->i2c_adap.algo = &dibusb_algo; - dib->i2c_adap.algo_data = NULL; - dib->i2c_adap.id = I2C_ALGO_BIT; - - i2c_set_adapdata(&dib->i2c_adap, dib); - - if ((i2c_add_adapter(&dib->i2c_adap) < 0)) { - err("could not add i2c adapter"); - goto err_i2c; - } - - dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING; - - dib->demux.priv = (void *)dib; - /* 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; - if ((ret = dvb_dmx_init(&dib->demux)) < 0) { - err("dvb_dmx_init failed: error %d",ret); - goto err_dmx; - } - - dib->dmxdev.filternum = dib->demux.filternum; - dib->dmxdev.demux = &dib->demux.dmx; - dib->dmxdev.capabilities = 0; - if ((ret = dvb_dmxdev_init(&dib->dmxdev, dib->adapter)) < 0) { - err("dvb_dmxdev_init failed: error %d",ret); - goto err_dmx_dev; - } - - 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); -err_dmx: - i2c_del_adapter(&dib->i2c_adap); -err_i2c: - dvb_unregister_adapter(dib->adapter); -err: - return ret; -success: - dib->dvb_is_ready = 1; - return 0; -} - -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); - - return 0; -} - -static int dibusb_exit(struct usb_dibusb *dib) -{ - int i; - 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); - - /* 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); - /* free the URBs */ - usb_free_urb(dib->urb_list[i]); - } - } - /* 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,bufsize; - sema_init(&dib->usb_sem, 1); - sema_init(&dib->i2c_sem, 1); - - /* - * when reloading the driver w/o replugging the device - * a timeout occures, this helps - */ - 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 *)); - - 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) { - deb_info("not enough memory.\n"); - dibusb_exit(dib); - return -ENOMEM; - } - deb_info("allocation complete\n"); - 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->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->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; - } - } - - 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); - - dibusb_hw_wakeup(dib); - - if ((ret = dibusb_dvb_init(dib))) { - dibusb_exit(dib); - return ret; - } - return 0; -} - -/* - * load a firmware packet to the device - */ -static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len) -{ - return usb_control_msg(udev, usb_sndctrlpipe(udev,0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ); -} - -static int dibusb_loadfirmware(struct usb_device *udev, - struct dibusb_device *dibdev) -{ - const struct firmware *fw = NULL; - const char **fws; - u16 addr; - u8 *b,*p; - int ret = 0,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", - fws[i],ret); - } - - if (fw == NULL) { - err("did not find a valid firmware file. " - "Please see linux/Documentation/dvb/ for more details on firmware-problems."); - return -EINVAL; - } - p = kmalloc(fw->size,GFP_KERNEL); - if (p != NULL) { - u8 reset; - /* - * you cannot use the fw->data as buffer for - * usb_control_msg, a new buffer has to be - * created - */ - memcpy(p,fw->data,fw->size); - - /* stop the CPU */ - reset = 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]; - addr = *((u16 *) &b[1]); - - ret = dibusb_writemem(udev,addr,&b[4],b[0]); - - if (ret != b[0]) { - err("error while transferring firmware " - "(transferred size: %d, block size: %d)", - ret,b[0]); - ret = -EINVAL; - break; - } - i += 5 + b[0]; - } - /* length in ret */ - if (ret > 0) - ret = 0; - /* restart the CPU */ - reset = 0; - if (ret || dibusb_writemem(udev,dibdev->parm->usb_cpu_csreg,&reset,1) != 1) { - err("could not restart the USB controller CPU."); - ret = -EINVAL; - } - - kfree(p); - } else { - ret = -ENOMEM; - } - release_firmware(fw); - - return ret; -} - -/* - * USB - */ -static int dibusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_dibusb *dib = NULL; - struct dibusb_device *dibdev = NULL; - - int ret = -ENOMEM,i,cold=0; - - for (i = 0; i < DIBUSB_SUPPORTED_DEVICES; i++) - if (dibusb_devices[i].cold_product_id == le16_to_cpu(udev->descriptor.idProduct) || - dibusb_devices[i].warm_product_id == le16_to_cpu(udev->descriptor.idProduct)) { - dibdev = &dibusb_devices[i]; - - cold = dibdev->cold_product_id == le16_to_cpu(udev->descriptor.idProduct); - - if (cold) - info("found a '%s' in cold state, will try to load a firmware",dibdev->name); - else - info("found a '%s' in warm state.",dibdev->name); - } - - if (dibdev == NULL) { - err("something went very wrong, " - "unknown product ID: %.4x",le16_to_cpu(udev->descriptor.idProduct)); - return -ENODEV; - } - - if (cold) - ret = dibusb_loadfirmware(udev,dibdev); - else { - dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL); - if (dib == NULL) { - err("no memory"); - return ret; - } - memset(dib,0,sizeof(struct usb_dibusb)); - - dib->pid_parse = 1; - 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 parsing."); - break; - case USB_SPEED_HIGH: - if (!pid_parse) { - dib->pid_parse = 0; - info("running at HIGH speed, will deliver the complete TS."); - } else - info("running at HIGH speed, will use pid_parsing anyway."); - break; - case USB_SPEED_UNKNOWN: /* fall through */ - default: - err("cannot handle USB speed because it is unkown."); - break; - } - - dib->udev = udev; - dib->dibdev = dibdev; - - usb_set_intfdata(intf, dib); - - ret = dibusb_init(dib); - } - - if (ret == 0) - info("%s successfully initialized and connected.",dibdev->name); - else - info("%s error while loading driver (%d)",dibdev->name,ret); - return ret; -} - -static void dibusb_disconnect(struct usb_interface *intf) -{ - struct usb_dibusb *dib = usb_get_intfdata(intf); - const char *name = DRIVER_DESC; - - usb_set_intfdata(intf,NULL); - if (dib != NULL) { - name = dib->dibdev->name; - dibusb_dvb_exit(dib); - dibusb_exit(dib); - kfree(dib); - } - info("%s successfully deinitialized and disconnected.",name); - -} - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver dibusb_driver = { - .owner = THIS_MODULE, - .name = "dvb_dibusb", - .probe = dibusb_probe, - .disconnect = dibusb_disconnect, - .id_table = dibusb_table, -}; - -/* module stuff */ -static int __init usb_dibusb_init(void) -{ - int result; - if ((result = usb_register(&dibusb_driver))) { - err("usb_register failed. Error number %d",result); - return result; - } - - return 0; -} - -static void __exit usb_dibusb_exit(void) -{ - /* deregister this driver from the USB subsystem */ - usb_deregister(&dibusb_driver); -} - -module_init (usb_dibusb_init); -module_exit (usb_dibusb_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dibusb/dvb-dibusb.h 2005-01-23 21:02:28 -08:00 @@ -1,293 +1,171 @@ /* * dvb-dibusb.h * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-5 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 dvb-dibusb.c . + * for more information see dvb-dibusb-core.c . */ - #ifndef __DVB_DIBUSB_H__ #define __DVB_DIBUSB_H__ +#include +#include +#include + +#include "dvb_frontend.h" +#include "dvb_demux.h" +#include "dvb_net.h" +#include "dmxdev.h" + #include "dib3000.h" +#include "mt352.h" + +/* debug */ +#ifdef CONFIG_DVB_DIBCOM_DEBUG +#define dprintk(level,args...) \ + do { if ((debug & level)) { printk(args); } } while (0) + +#define debug_dump(b,l) if (debug) {\ + int i; deb_xfer("%s: %d > ",__FUNCTION__,l); \ + for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \ + deb_xfer("\n");\ +} + +/* module parameters - declared in -core.c */ +extern int debug; + +#else +#define dprintk(args...) +#define debug_dump(b,l) +#endif + +/* Version information */ +#define DRIVER_VERSION "0.3" +#define DRIVER_DESC "Driver for DiBcom based USB Budget DVB-T device" +#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de" + +/* module parameters - declared in -core.c */ +extern int pid_parse; +extern int rc_query_interval; + +#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) + +/* generic log methods - taken from usb.h */ +#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) + +struct dibusb_usb_controller { + const char *name; /* name of the usb controller */ + u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */ +}; typedef enum { DIBUSB1_1 = 0, - DIBUSB2_0, DIBUSB1_1_AN2235, -} dibusb_type; + DIBUSB2_0, + UMT2_0, +} dibusb_class_t; -static const char * dibusb_fw_filenames1_1[] = { - "dvb-dibusb-5.0.0.11.fw" -}; +typedef enum { + DIBUSB_TUNER_CABLE_THOMSON = 0, + DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5, + DIBUSB_TUNER_CABLE_LG_TDTP_E102P, + DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5, +} dibusb_tuner_t; -static const char * dibusb_fw_filenames1_1_an2235[] = { - "dvb-dibusb-an2235-1.fw" -}; +typedef enum { + DIBUSB_DIB3000MB = 0, + DIBUSB_DIB3000MC, + DIBUSB_MT352, +} dibusb_demodulator_t; -static const char * dibusb_fw_filenames2_0[] = { - "dvb-dibusb-6.0.0.5.fw" -}; +typedef enum { + DIBUSB_RC_NO = 0, + DIBUSB_RC_NEC_PROTOCOL = 1, +} dibusb_remote_t; -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; -}; +struct dibusb_tuner { + dibusb_tuner_t id; -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 = 0x18, - .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, - } + u8 pll_addr; /* tuner i2c address */ }; +extern struct dibusb_tuner dibusb_tuner[]; -struct dibusb_device { - const char *name; - u16 cold_product_id; - u16 warm_product_id; - struct dibusb_device_parameter *parm; -}; +#define DIBUSB_POSSIBLE_I2C_ADDR_NUM 4 +struct dibusb_demod { + dibusb_demodulator_t id; -/* Vendor IDs */ -#define USB_VID_ANCHOR 0x0547 -#define USB_VID_AVERMEDIA 0x14aa -#define USB_VID_COMPRO 0x185b -#define USB_VID_COMPRO_UNK 0x145f -#define USB_VID_CYPRESS 0x04b4 -#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_COMPRO_DVBU2000_UNK_COLD 0x010c -#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d -#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_ULTIMA_TVBOX_USB2_COLD 0x8109 -#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 -#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 -#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e -#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 15 - -/* USB Driver stuff */ -static struct dibusb_device dibusb_devices[DIBUSB_SUPPORTED_DEVICES] = { - { .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 = "Artec T1 USB2.0 TVBOX (please report the warm ID)", - .cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_COLD, - .warm_product_id = 0, /* don't know, it is most likely that the device will get another USB ID in warm state */ - .parm = &dibusb_dev_parm[1], - }, - { .name = "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)", - .cold_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_COLD, - .warm_product_id = USB_PID_ULTIMA_TVBOX_USB2_FX_WARM, /* undefined, it could be that the device will get another USB ID in warm state */ - .parm = &dibusb_dev_parm[1], - }, - { .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 = "Compro Videomate DVB-U2000 - DVB-T USB1.1 (really ?? please report the name!)", - .cold_product_id = USB_PID_COMPRO_DVBU2000_UNK_COLD, - .warm_product_id = USB_PID_COMPRO_DVBU2000_UNK_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], - } + int pid_filter_count; /* counter of the internal pid_filter */ + u8 i2c_addrs[DIBUSB_POSSIBLE_I2C_ADDR_NUM]; /* list of possible i2c addresses of the demod */ }; -/* USB Driver stuff */ -/* table of devices that work with this driver */ -static struct usb_device_id dibusb_table [] = { - { 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) }, - { USB_DEVICE(USB_PID_COMPRO_DVBU2000_UNK_COLD, USB_VID_COMPRO_UNK) }, - { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +#define DIBUSB_MAX_TUNER_NUM 2 +struct dibusb_device_class { + dibusb_class_t id; + + const struct dibusb_usb_controller *usb_ctrl; /* usb controller */ + const char *firmware; /* valid firmware filenames */ + + int pipe_cmd; /* command pipe (read/write) */ + int pipe_data; /* data pipe */ + + int urb_count; /* number of data URBs to be submitted */ + int urb_buffer_size; /* the size of the buffer for each URB */ -/* - * activate the following define when you have one of the devices and want to - * build it from build-2.6 in dvb-kernel - */ -// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES -#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES - { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, - { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) }, - { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) }, -#endif - { } /* Terminating entry */ + dibusb_remote_t remote_type; /* does this device have a ir-receiver */ + + struct dibusb_demod *demod; /* which demodulator is mount */ + struct dibusb_tuner *tuner; /* which tuner can be found here */ }; -MODULE_DEVICE_TABLE (usb, dibusb_table); +#define DIBUSB_ID_MAX_NUM 15 +struct dibusb_usb_device { + const char *name; /* real name of the box */ + struct dibusb_device_class *dev_cl; /* which dibusb_device_class is this device part of */ + + struct usb_device_id *cold_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at pre firmware state */ + struct usb_device_id *warm_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at post firmware state */ +}; -#define DIBUSB_I2C_TIMEOUT HZ*5 +/* a PID for the pid_filter list, when in use */ +struct dibusb_pid +{ + int index; + u16 pid; + int active; +}; struct usb_dibusb { /* usb */ struct usb_device * udev; - struct dibusb_device * dibdev; + struct dibusb_usb_device * dibdev; + +#define DIBUSB_STATE_INIT 0x000 +#define DIBUSB_STATE_URB_LIST 0x001 +#define DIBUSB_STATE_URB_BUF 0x002 +#define DIBUSB_STATE_URB_SUBMIT 0x004 +#define DIBUSB_STATE_DVB 0x008 +#define DIBUSB_STATE_I2C 0x010 +#define DIBUSB_STATE_REMOTE 0x020 +#define DIBUSB_STATE_PIDLIST 0x040 + int init_state; int feedcount; int pid_parse; - struct dib3000_xfer_ops xfer_ops; + struct dib_fe_xfer_ops xfer_ops; + + struct dibusb_tuner *tuner; struct urb **urb_list; u8 *buffer; @@ -295,49 +173,137 @@ /* I2C */ struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; /* locking */ struct semaphore usb_sem; struct semaphore i2c_sem; + /* pid filtering */ + spinlock_t pid_list_lock; + struct dibusb_pid *pid_list; + /* dvb */ - int dvb_is_ready; struct dvb_adapter *adapter; struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; struct dvb_frontend* fe; + int (*fe_sleep) (struct dvb_frontend *); + int (*fe_init) (struct dvb_frontend *); + /* remote control */ struct input_dev rc_input_dev; struct work_struct rc_query_work; int rc_input_event; }; +/* commonly used functions in the separated files */ + +/* dvb-dibusb-firmware.c */ +int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev); + +/* dvb-dibusb-remote.c */ +int dibusb_remote_exit(struct usb_dibusb *dib); +int dibusb_remote_init(struct usb_dibusb *dib); + +/* dvb-dibusb-fe-i2c.c */ +int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen); +int dibusb_fe_init(struct usb_dibusb* dib); +int dibusb_fe_exit(struct usb_dibusb *dib); +int dibusb_i2c_init(struct usb_dibusb *dib); +int dibusb_i2c_exit(struct usb_dibusb *dib); + +/* dvb-dibusb-dvb.c */ +void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs); +int dibusb_dvb_init(struct usb_dibusb *dib); +int dibusb_dvb_exit(struct usb_dibusb *dib); + +/* dvb-dibusb-usb.c */ +int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf, + u16 rlen); + +int dibusb_hw_wakeup(struct dvb_frontend *); +int dibusb_hw_sleep(struct dvb_frontend *); +int dibusb_set_streaming_mode(struct usb_dibusb *,u8); +int dibusb_streaming(struct usb_dibusb *,int); + +int dibusb_urb_init(struct usb_dibusb *); +int dibusb_urb_exit(struct usb_dibusb *); + +/* dvb-dibusb-pid.c */ +int dibusb_pid_list_init(struct usb_dibusb *dib); +void dibusb_pid_list_exit(struct usb_dibusb *dib); +int dibusb_ctrl_pid(struct usb_dibusb *dib, struct dvb_demux_feed *dvbdmxfeed , int onoff); + +/* i2c and transfer stuff */ +#define DIBUSB_I2C_TIMEOUT HZ*5 + +/* + * protocol of all dibusb related devices + */ -/* types of first byte of each buffer */ +/* + * bulk msg to/from endpoint 0x01 + * + * general structure: + * request_byte parameter_bytes + */ #define DIBUSB_REQ_START_READ 0x00 #define DIBUSB_REQ_START_DEMOD 0x01 + +/* + * i2c read + * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word + * bulk read: byte_buffer (length_word bytes) + */ #define DIBUSB_REQ_I2C_READ 0x02 + +/* + * i2c write + * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes + */ #define DIBUSB_REQ_I2C_WRITE 0x03 -/* prefix for reading the current RC key */ +/* + * polling the value of the remote control + * bulk write: 0x04 + * bulk read: byte_buffer (5 bytes) + * + * first byte of byte_buffer shows the status (0x00, 0x01, 0x02) + */ #define DIBUSB_REQ_POLL_REMOTE 0x04 #define DIBUSB_RC_NEC_EMPTY 0x00 #define DIBUSB_RC_NEC_KEY_PRESSED 0x01 #define DIBUSB_RC_NEC_KEY_REPEATED 0x02 -/* 0x05 0xXX */ +/* streaming mode: + * bulk write: 0x05 mode_byte + * + * mode_byte is mostly 0x00 + */ #define DIBUSB_REQ_SET_STREAMING_MODE 0x05 /* interrupt the internal read loop, when blocking */ #define DIBUSB_REQ_INTR_READ 0x06 -/* IO control - * 0x07 +/* io control + * 0x07 cmd_byte param_bytes + * + * param_bytes can be up to 32 bytes + * + * cmd_byte function parameter name + * 0x00 power mode + * 0x00 sleep + * 0x01 wakeup + * + * 0x01 enable streaming + * 0x02 disable streaming + * + * */ #define DIBUSB_REQ_SET_IOCTL 0x07 @@ -347,5 +313,9 @@ #define DIBUSB_IOCTL_CMD_POWER_MODE 0x00 #define DIBUSB_IOCTL_POWER_SLEEP 0x00 #define DIBUSB_IOCTL_POWER_WAKEUP 0x01 + +/* modify streaming of the FX2 */ +#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01 +#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02 #endif 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_demux.c 2005-01-23 21:02:28 -08:00 @@ -247,7 +247,22 @@ } /* -** Losless Section Demux 1.4 by Emard +** Losless Section Demux 1.4.1 by Emard +** Valsecchi Patrick: +** - middle of section A (no PUSI) +** - end of section A and start of section B +** (with PUSI pointing to the start of the second section) +** +** In this case, without feed->pusi_seen you'll receive a garbage section +** consisting of the end of section A. Basically because tsfeedp +** is incemented and the use=0 condition is not raised +** when the second packet arrives. +** +** Fix: +** when demux is started, let feed->pusi_seen = 0 to +** prevent initial feeding of garbage from the end of +** previous section. When you for the first time see PUSI=1 +** then set feed->pusi_seen = 1 */ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len) { @@ -293,7 +308,12 @@ sec->seclen = seclen; sec->crc_val = ~0; /* dump [secbuf .. secbuf+seclen) */ + if(feed->pusi_seen) dvb_dmx_swfilter_section_feed(feed); +#ifdef DVB_DEMUX_SECTION_LOSS_LOG + else + printk("dvb_demux.c pusi not seen, discarding section data\n"); +#endif sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbuf += seclen; /* redundand but saves pointer arithmetic */ } @@ -305,7 +325,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) { u8 p, count; - int ccok; + int ccok, dc_i = 0; u8 cc; count = payload(buf); @@ -316,31 +336,41 @@ p = 188-count; /* payload start */ cc = buf[3] & 0x0f; - ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0; + ccok = ((feed->cc + 1) & 0x0f) == cc; feed->cc = cc; - if(ccok == 0) - { + + if (buf[3] & 0x20) { + /* adaption field present, check for discontinuity_indicator */ + if ((buf[4] > 0) && (buf[5] & 0x80)) + dc_i = 1; + } + + if (!ccok || dc_i) { #ifdef DVB_DEMUX_SECTION_LOSS_LOG printk("dvb_demux.c discontinuity detected %d bytes lost\n", count); /* those bytes under sume circumstances will again be reported ** in the following dvb_dmx_swfilter_section_new */ #endif + /* Discontinuity detected. Reset pusi_seen = 0 to + ** stop feeding of suspicious data until next PUSI=1 arrives + */ + feed->pusi_seen = 0; dvb_dmx_swfilter_section_new(feed); return 0; } - if(buf[1] & 0x40) - { + if (buf[1] & 0x40) { // PUSI=1 (is set), section boundary is here - if(count > 1 && buf[p] < count) - { + if (count > 1 && buf[p] < count) { const u8 *before = buf+p+1; u8 before_len = buf[p]; const u8 *after = before+before_len; u8 after_len = count-1-before_len; dvb_dmx_swfilter_section_copy_dump(feed, before, before_len); + /* before start of new section, set pusi_seen = 1 */ + feed->pusi_seen = 1; dvb_dmx_swfilter_section_new(feed); dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); } @@ -349,9 +379,7 @@ if(count > 0) printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); #endif - } - else - { + } else { // PUSI=0 (is not set), no section boundary const u8 *entire = buf+p; u8 entire_len = count; @@ -784,10 +812,8 @@ } #ifndef NOBUFS - if (feed->buffer) { vfree(feed->buffer); feed->buffer=0; - } #endif feed->state = DMX_STATE_FREE; @@ -1055,10 +1081,8 @@ return -EINVAL; } #ifndef NOBUFS - if (dvbdmxfeed->buffer) { vfree(dvbdmxfeed->buffer); dvbdmxfeed->buffer=0; - } #endif dvbdmxfeed->state=DMX_STATE_FREE; @@ -1269,9 +1293,7 @@ struct dmx_demux *dmx = &dvbdemux->dmx; dmx_unregister_demux(dmx); - if (dvbdemux->filter) vfree(dvbdemux->filter); - if (dvbdemux->feed) vfree(dvbdemux->feed); return 0; } diff -Nru a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h --- a/drivers/media/dvb/dvb-core/dvb_demux.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_demux.h 2005-01-23 21:02:28 -08:00 @@ -93,6 +93,7 @@ enum dmx_ts_pes pes_type; int cc; + int pusi_seen; /* prevents feeding of garbage from previous section */ u16 peslen; 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c 2005-01-23 21:02:28 -08:00 @@ -89,9 +89,36 @@ static DECLARE_MUTEX(frontend_mutex); +struct dvb_frontend_private { + + struct dvb_device *dvbdev; + struct dvb_frontend_parameters parameters; + struct dvb_fe_events events; + struct semaphore sem; + struct list_head list_head; + wait_queue_head_t wait_queue; + pid_t thread_pid; + unsigned long release_jiffies; + int state; + int bending; + int lnb_drift; + int inversion; + int auto_step; + int auto_sub_step; + int started_auto_step; + int min_delay; + int max_drift; + int step_size; + int exit; + int wakeup; + fe_status_t status; +}; + + static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { - struct dvb_fe_events *events = &fe->events; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_fe_events *events = &fepriv->events; struct dvb_frontend_event *e; int wp; @@ -109,7 +136,7 @@ e = &events->events[events->eventw]; - memcpy (&e->parameters, &fe->parameters, + memcpy (&e->parameters, &fepriv->parameters, sizeof (struct dvb_frontend_parameters)); if (status & FE_HAS_LOCK) @@ -128,7 +155,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, struct dvb_frontend_event *event, int flags) { - struct dvb_fe_events *events = &fe->events; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + struct dvb_fe_events *events = &fepriv->events; dprintk ("%s\n", __FUNCTION__); @@ -143,12 +171,12 @@ if (flags & O_NONBLOCK) return -EWOULDBLOCK; - up(&fe->sem); + up(&fepriv->sem); ret = wait_event_interruptible (events->wait_queue, events->eventw != events->eventr); - if (down_interruptible (&fe->sem)) + if (down_interruptible (&fepriv->sem)) return -ERESTARTSYS; if (ret < 0) @@ -206,27 +234,28 @@ { int autoinversion; int ready = 0; - int original_inversion = fe->parameters.inversion; - u32 original_frequency = fe->parameters.frequency; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + int original_inversion = fepriv->parameters.inversion; + u32 original_frequency = fepriv->parameters.frequency; /* are we using autoinversion? */ autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && - (fe->parameters.inversion == INVERSION_AUTO)); + (fepriv->parameters.inversion == INVERSION_AUTO)); /* setup parameters correctly */ while(!ready) { /* calculate the lnb_drift */ - fe->lnb_drift = fe->auto_step * fe->step_size; + fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size; /* wrap the auto_step if we've exceeded the maximum drift */ - if (fe->lnb_drift > fe->max_drift) { - fe->auto_step = 0; - fe->auto_sub_step = 0; - fe->lnb_drift = 0; + if (fepriv->lnb_drift > fepriv->max_drift) { + fepriv->auto_step = 0; + fepriv->auto_sub_step = 0; + fepriv->lnb_drift = 0; } /* perform inversion and +/- zigzag */ - switch(fe->auto_sub_step) { + switch(fepriv->auto_sub_step) { case 0: /* try with the current inversion and current drift setting */ ready = 1; @@ -235,68 +264,70 @@ case 1: if (!autoinversion) break; - fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; + fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; ready = 1; break; case 2: - if (fe->lnb_drift == 0) break; + if (fepriv->lnb_drift == 0) break; - fe->lnb_drift = -fe->lnb_drift; + fepriv->lnb_drift = -fepriv->lnb_drift; ready = 1; break; case 3: - if (fe->lnb_drift == 0) break; + if (fepriv->lnb_drift == 0) break; if (!autoinversion) break; - fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; - fe->lnb_drift = -fe->lnb_drift; + fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; + fepriv->lnb_drift = -fepriv->lnb_drift; ready = 1; break; default: - fe->auto_step++; - fe->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */ + fepriv->auto_step++; + fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */ break; } - if (!ready) fe->auto_sub_step++; + if (!ready) fepriv->auto_sub_step++; } /* if this attempt would hit where we started, indicate a complete * iteration has occurred */ - if ((fe->auto_step == fe->started_auto_step) && - (fe->auto_sub_step == 0) && check_wrapped) { + if ((fepriv->auto_step == fepriv->started_auto_step) && + (fepriv->auto_sub_step == 0) && check_wrapped) { return 1; } dprintk("%s: drift:%i inversion:%i auto_step:%i " "auto_sub_step:%i started_auto_step:%i\n", - __FUNCTION__, fe->lnb_drift, fe->inversion, - fe->auto_step, fe->auto_sub_step, fe->started_auto_step); + __FUNCTION__, fepriv->lnb_drift, fepriv->inversion, + fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); /* set the frontend itself */ - fe->parameters.frequency += fe->lnb_drift; + fepriv->parameters.frequency += fepriv->lnb_drift; if (autoinversion) - fe->parameters.inversion = fe->inversion; + fepriv->parameters.inversion = fepriv->inversion; if (fe->ops->set_frontend) - fe->ops->set_frontend(fe, &fe->parameters); + fe->ops->set_frontend(fe, &fepriv->parameters); - fe->parameters.frequency = original_frequency; - fe->parameters.inversion = original_inversion; + fepriv->parameters.frequency = original_frequency; + fepriv->parameters.inversion = original_inversion; - fe->auto_sub_step++; + fepriv->auto_sub_step++; return 0; } static int dvb_frontend_is_exiting(struct dvb_frontend *fe) { - if (fe->exit) + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + + if (fepriv->exit) return 1; - if (fe->dvbdev->writers == 1) - if (jiffies - fe->release_jiffies > dvb_shutdown_timeout * HZ) + if (fepriv->dvbdev->writers == 1) + if (jiffies - fepriv->release_jiffies > dvb_shutdown_timeout * HZ) return 1; return 0; @@ -304,8 +335,10 @@ static int dvb_frontend_should_wakeup(struct dvb_frontend *fe) { - if (fe->wakeup) { - fe->wakeup = 0; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + + if (fepriv->wakeup) { + fepriv->wakeup = 0; return 1; } return dvb_frontend_is_exiting(fe); @@ -313,8 +346,10 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe) { - fe->wakeup = 1; - wake_up_interruptible(&fe->wait_queue); + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + + fepriv->wakeup = 1; + wake_up_interruptible(&fepriv->wait_queue); } /* @@ -323,6 +358,7 @@ static int dvb_frontend_thread (void *data) { struct dvb_frontend *fe = (struct dvb_frontend *) data; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; unsigned long timeout; char name [15]; int quality = 0, delay = 3*HZ; @@ -338,14 +374,14 @@ sigfillset (¤t->blocked); unlock_kernel (); - fe->status = 0; + fepriv->status = 0; dvb_frontend_init (fe); - fe->wakeup = 0; + fepriv->wakeup = 0; while (1) { - up (&fe->sem); /* is locked when we enter the thread... */ + up(&fepriv->sem); /* is locked when we enter the thread... */ - timeout = wait_event_interruptible_timeout(fe->wait_queue, + timeout = wait_event_interruptible_timeout(fepriv->wait_queue, dvb_frontend_should_wakeup(fe), delay); if (0 != dvb_frontend_is_exiting (fe)) { @@ -356,44 +392,43 @@ if (current->flags & PF_FREEZE) refrigerator(PF_FREEZE); - if (down_interruptible (&fe->sem)) + if (down_interruptible(&fepriv->sem)) break; /* if we've got no parameters, just keep idling */ - if (fe->state & FESTATE_IDLE) { + if (fepriv->state & FESTATE_IDLE) { delay = 3*HZ; quality = 0; continue; } -retune: /* get the frontend status */ - if (fe->state & FESTATE_RETUNE) { + if (fepriv->state & FESTATE_RETUNE) { s = 0; } else { if (fe->ops->read_status) fe->ops->read_status(fe, &s); - if (s != fe->status) { + if (s != fepriv->status) { dvb_frontend_add_event (fe, s); - fe->status = s; + fepriv->status = s; } } /* if we're not tuned, and we have a lock, move to the TUNED state */ - if ((fe->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { - update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); - fe->state = FESTATE_TUNED; + if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { + update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); + fepriv->state = FESTATE_TUNED; /* if we're tuned, then we have determined the correct inversion */ if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && - (fe->parameters.inversion == INVERSION_AUTO)) { - fe->parameters.inversion = fe->inversion; + (fepriv->parameters.inversion == INVERSION_AUTO)) { + fepriv->parameters.inversion = fepriv->inversion; } continue; } /* if we are tuned already, check we're still locked */ - if (fe->state & FESTATE_TUNED) { - update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); + if (fepriv->state & FESTATE_TUNED) { + update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); /* we're tuned, and the lock is still good... */ if (s & FE_HAS_LOCK) @@ -401,49 +436,49 @@ else { /* if we _WERE_ tuned, but now don't have a lock, * need to zigzag */ - fe->state = FESTATE_ZIGZAG_FAST; - fe->started_auto_step = fe->auto_step; + fepriv->state = FESTATE_ZIGZAG_FAST; + fepriv->started_auto_step = fepriv->auto_step; check_wrapped = 0; } } /* 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->ops->info.caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) { - update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); + if ((fepriv->state & FESTATE_LOSTLOCK) && + (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { + update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); continue; } /* don't do anything if we're in the DISEQC state, since this * might be someone with a motorized dish controlled by DISEQC. * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ - if (fe->state & FESTATE_DISEQC) { - update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); + if (fepriv->state & FESTATE_DISEQC) { + update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); continue; } /* if we're in the RETUNE state, set everything up for a brand * new scan, keeping the current inversion setting, as the next * tune is _very_ likely to require the same */ - if (fe->state & FESTATE_RETUNE) { - fe->lnb_drift = 0; - fe->auto_step = 0; - fe->auto_sub_step = 0; - fe->started_auto_step = 0; + if (fepriv->state & FESTATE_RETUNE) { + fepriv->lnb_drift = 0; + fepriv->auto_step = 0; + fepriv->auto_sub_step = 0; + fepriv->started_auto_step = 0; check_wrapped = 0; } /* fast zigzag. */ - if ((fe->state & FESTATE_SEARCHING_FAST) || (fe->state & FESTATE_RETUNE)) { - delay = fe->min_delay; + if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { + delay = fepriv->min_delay; /* peform a tune */ if (dvb_frontend_autotune(fe, check_wrapped)) { /* OK, if we've run out of trials at the fast speed. * Drop back to slow for the _next_ attempt */ - fe->state = FESTATE_SEARCHING_SLOW; - fe->started_auto_step = fe->auto_step; + fepriv->state = FESTATE_SEARCHING_SLOW; + fepriv->started_auto_step = fepriv->auto_step; continue; } check_wrapped = 1; @@ -452,15 +487,14 @@ * This ensures we cannot return from an * FE_SET_FRONTEND ioctl before the first frontend tune * occurs */ - if (fe->state & FESTATE_RETUNE) { - fe->state = FESTATE_TUNING_FAST; - goto retune; + if (fepriv->state & FESTATE_RETUNE) { + fepriv->state = FESTATE_TUNING_FAST; } } /* slow zigzag */ - if (fe->state & FESTATE_SEARCHING_SLOW) { - update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK); + if (fepriv->state & FESTATE_SEARCHING_SLOW) { + update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); /* Note: don't bother checking for wrapping; we stay in this * state until we get a lock */ @@ -476,7 +510,7 @@ fe->ops->sleep(fe); } - fe->thread_pid = 0; + fepriv->thread_pid = 0; mb(); dvb_frontend_wakeup(fe); @@ -486,21 +520,22 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) { unsigned long ret; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); - fe->exit = 1; + fepriv->exit = 1; mb(); - if (!fe->thread_pid) + if (!fepriv->thread_pid) return; /* check if the thread is really alive */ - if (kill_proc(fe->thread_pid, 0, 1) == -ESRCH) { + if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) { printk("dvb_frontend_stop: thread PID %d already died\n", - fe->thread_pid); + fepriv->thread_pid); /* make sure the mutex was not held by the thread */ - init_MUTEX (&fe->sem); + init_MUTEX (&fepriv->sem); return; } @@ -508,27 +543,28 @@ dvb_frontend_wakeup(fe); /* wait until the frontend thread has exited */ - ret = wait_event_interruptible(fe->wait_queue,0 == fe->thread_pid); + ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid); if (-ERESTARTSYS != ret) { - fe->state = FESTATE_IDLE; + fepriv->state = FESTATE_IDLE; return; } - fe->state = FESTATE_IDLE; + fepriv->state = FESTATE_IDLE; /* paranoia check in case a signal arrived */ - if (fe->thread_pid) + if (fepriv->thread_pid) printk("dvb_frontend_stop: warning: thread PID %d won't exit\n", - fe->thread_pid); + fepriv->thread_pid); } static int dvb_frontend_start(struct dvb_frontend *fe) { int ret; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); - if (fe->thread_pid) { - if (!fe->exit) + if (fepriv->thread_pid) { + if (!fepriv->exit) return 0; else dvb_frontend_stop (fe); @@ -536,21 +572,22 @@ if (signal_pending(current)) return -EINTR; - if (down_interruptible (&fe->sem)) + if (down_interruptible (&fepriv->sem)) return -EINTR; - fe->state = FESTATE_IDLE; - fe->exit = 0; - fe->thread_pid = 0; + fepriv->state = FESTATE_IDLE; + fepriv->exit = 0; + fepriv->thread_pid = 0; mb(); ret = kernel_thread (dvb_frontend_thread, fe, 0); + if (ret < 0) { printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret); - up(&fe->sem); + up(&fepriv->sem); return ret; } - fe->thread_pid = ret; + fepriv->thread_pid = ret; return 0; } @@ -561,11 +598,12 @@ { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; int err = -EOPNOTSUPP; dprintk ("%s\n", __FUNCTION__); - if (!fe || fe->exit) + if (!fe || fepriv->exit) return -ENODEV; if ((file->f_flags & O_ACCMODE) == O_RDONLY && @@ -573,7 +611,7 @@ cmd == FE_DISEQC_RECV_SLAVE_REPLY)) return -EPERM; - if (down_interruptible (&fe->sem)) + if (down_interruptible (&fepriv->sem)) return -ERESTARTSYS; switch (cmd) { @@ -617,48 +655,48 @@ case FE_DISEQC_RESET_OVERLOAD: if (fe->ops->diseqc_reset_overload) { err = fe->ops->diseqc_reset_overload(fe); - fe->state = FESTATE_DISEQC; - fe->status = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; } break; case FE_DISEQC_SEND_MASTER_CMD: if (fe->ops->diseqc_send_master_cmd) { err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); - fe->state = FESTATE_DISEQC; - fe->status = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; } break; case FE_DISEQC_SEND_BURST: if (fe->ops->diseqc_send_burst) { err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); - fe->state = FESTATE_DISEQC; - fe->status = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; } break; case FE_SET_TONE: if (fe->ops->set_tone) { err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); - fe->state = FESTATE_DISEQC; - fe->status = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; } break; case FE_SET_VOLTAGE: if (fe->ops->set_voltage) { err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg); - fe->state = FESTATE_DISEQC; - fe->status = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; } break; case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops->dishnetwork_send_legacy_command) { err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg); - fe->state = FESTATE_DISEQC; - fe->status = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; } break; @@ -668,14 +706,14 @@ break; case FE_ENABLE_HIGH_LNB_VOLTAGE: - if (fe->ops->enable_high_lnb_voltage); + if (fe->ops->enable_high_lnb_voltage) err = fe->ops->enable_high_lnb_voltage(fe, (int) parg); break; case FE_SET_FRONTEND: { struct dvb_frontend_tune_settings fetunesettings; - memcpy (&fe->parameters, parg, + memcpy (&fepriv->parameters, parg, sizeof (struct dvb_frontend_parameters)); memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); @@ -684,41 +722,41 @@ /* force auto frequency inversion if requested */ if (dvb_force_auto_inversion) { - fe->parameters.inversion = INVERSION_AUTO; + fepriv->parameters.inversion = INVERSION_AUTO; fetunesettings.parameters.inversion = INVERSION_AUTO; } if (fe->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 && - fe->parameters.u.ofdm.code_rate_LP == FEC_NONE) - fe->parameters.u.ofdm.code_rate_LP = FEC_AUTO; + if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE && + fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE) + fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO; } /* get frontend-specific tuning settings */ if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) { - fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; - fe->max_drift = fetunesettings.max_drift; - fe->step_size = fetunesettings.step_size; + fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; + fepriv->max_drift = fetunesettings.max_drift; + fepriv->step_size = fetunesettings.step_size; } else { /* default values */ switch(fe->ops->info.type) { case FE_QPSK: - fe->min_delay = HZ/20; - fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000; - fe->max_drift = fe->parameters.u.qpsk.symbol_rate / 2000; + fepriv->min_delay = HZ/20; + fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000; + fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000; break; case FE_QAM: - fe->min_delay = HZ/20; - fe->step_size = 0; /* no zigzag */ - fe->max_drift = 0; + fepriv->min_delay = HZ/20; + fepriv->step_size = 0; /* no zigzag */ + fepriv->max_drift = 0; break; case FE_OFDM: - fe->min_delay = HZ/20; - fe->step_size = fe->ops->info.frequency_stepsize * 2; - fe->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1; + fepriv->min_delay = HZ/20; + fepriv->step_size = fe->ops->info.frequency_stepsize * 2; + fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1; break; case FE_ATSC: printk("dvb-core: FE_ATSC not handled yet.\n"); @@ -726,12 +764,12 @@ } } if (dvb_override_tune_delay > 0) - fe->min_delay = (dvb_override_tune_delay * HZ) / 1000; + fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; - fe->state = FESTATE_RETUNE; + fepriv->state = FESTATE_RETUNE; dvb_frontend_wakeup(fe); dvb_frontend_add_event (fe, 0); - fe->status = 0; + fepriv->status = 0; err = 0; break; } @@ -742,13 +780,13 @@ case FE_GET_FRONTEND: if (fe->ops->get_frontend) { - memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters)); + memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters)); err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg); } break; }; - up (&fe->sem); + up (&fepriv->sem); return err; } @@ -757,12 +795,13 @@ { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); - poll_wait (file, &fe->events.wait_queue, wait); + poll_wait (file, &fepriv->events.wait_queue, wait); - if (fe->events.eventw != fe->events.eventr) + if (fepriv->events.eventw != fepriv->events.eventr) return (POLLIN | POLLRDNORM | POLLPRI); return 0; @@ -773,6 +812,7 @@ { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; int ret; dprintk ("%s\n", __FUNCTION__); @@ -786,7 +826,7 @@ dvb_generic_release (inode, file); /* empty event queue */ - fe->events.eventr = fe->events.eventw = 0; + fepriv->events.eventr = fepriv->events.eventw = 0; } return ret; @@ -797,11 +837,12 @@ { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); if ((file->f_flags & O_ACCMODE) != O_RDONLY) - fe->release_jiffies = jiffies; + fepriv->release_jiffies = jiffies; return dvb_generic_release (inode, file); } @@ -818,6 +859,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, struct dvb_frontend* fe) { + struct dvb_frontend_private *fepriv; static const struct dvb_device dvbdev_template = { .users = ~0, .writers = 1, @@ -831,20 +873,26 @@ if (down_interruptible (&frontend_mutex)) return -ERESTARTSYS; - init_MUTEX (&fe->sem); - init_waitqueue_head (&fe->wait_queue); - init_waitqueue_head (&fe->events.wait_queue); - init_MUTEX (&fe->events.sem); - fe->events.eventw = fe->events.eventr = 0; - fe->events.overflow = 0; + fe->frontend_priv = kmalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); + if (fe->frontend_priv == NULL) { + up(&frontend_mutex); + return -ENOMEM; + } + fepriv = (struct dvb_frontend_private*) fe->frontend_priv; + memset(fe->frontend_priv, 0, sizeof(struct dvb_frontend_private)); + + init_MUTEX (&fepriv->sem); + init_waitqueue_head (&fepriv->wait_queue); + init_waitqueue_head (&fepriv->events.wait_queue); + init_MUTEX (&fepriv->events.sem); fe->dvb = dvb; - fe->inversion = INVERSION_OFF; + fepriv->inversion = INVERSION_OFF; printk ("DVB: registering frontend %i (%s)...\n", fe->dvb->num, fe->ops->info.name); - dvb_register_device (fe->dvb, &fe->dvbdev, &dvbdev_template, + dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND); up (&frontend_mutex); @@ -854,15 +902,18 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) { + struct dvb_frontend_private *fepriv = (struct dvb_frontend_private*) fe->frontend_priv; dprintk ("%s\n", __FUNCTION__); down (&frontend_mutex); - dvb_unregister_device (fe->dvbdev); + dvb_unregister_device (fepriv->dvbdev); dvb_frontend_stop (fe); if (fe->ops->release) fe->ops->release(fe); else printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name); + if (fe->frontend_priv) + kfree(fe->frontend_priv); up (&frontend_mutex); return 0; } 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h 2005-01-23 21:02:28 -08:00 @@ -115,28 +115,7 @@ struct dvb_frontend_ops* ops; struct dvb_adapter *dvb; void* demodulator_priv; - - struct dvb_device *dvbdev; - struct dvb_frontend_parameters parameters; - struct dvb_fe_events events; - struct semaphore sem; - struct list_head list_head; - wait_queue_head_t wait_queue; - pid_t thread_pid; - unsigned long release_jiffies; - int state; - int bending; - int lnb_drift; - int inversion; - int auto_step; - int auto_sub_step; - int started_auto_step; - int min_delay; - int max_drift; - int step_size; - int exit; - int wakeup; - fe_status_t status; + void* frontend_priv; }; extern int dvb_register_frontend(struct dvb_adapter* dvb, 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/dvb-core/dvb_net.c 2005-01-23 21:02:28 -08:00 @@ -123,7 +123,6 @@ struct dvb_net_priv { int in_use; struct net_device_stats stats; - char name[6]; u16 pid; struct dvb_net *host; struct dmx_demux *demux; @@ -1165,12 +1164,17 @@ if ((if_num = get_if(dvbnet)) < 0) return -EINVAL; - net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", - dvb_net_setup); + net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup); if (!net) return -ENOMEM; - sprintf(net->name, "dvb%d_%d", dvbnet->dvbdev->adapter->num, if_num); + if (dvbnet->dvbdev->id) + snprintf(net->name, IFNAMSIZ, "dvb%d%u%d", + dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num); + else + /* compatibility fix to keep dvb0_0 format */ + snprintf(net->name, IFNAMSIZ, "dvb%d_%d", + dvbnet->dvbdev->adapter->num, if_num); net->addr_len = 6; memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6); @@ -1196,6 +1200,7 @@ free_netdev(net); return result; } + printk("dvb_net: created network interface %s\n", net->name); return if_num; } @@ -1214,6 +1219,7 @@ dvb_net_stop(net); flush_scheduled_work(); + printk("dvb_net: removed network interface %s\n", net->name); unregister_netdev(net); dvbnet->state[num]=0; dvbnet->device[num] = NULL; diff -Nru a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig --- a/drivers/media/dvb/frontends/Kconfig 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/Kconfig 2005-01-23 21:02:28 -08:00 @@ -46,6 +46,7 @@ config DVB_SP8870 tristate "Spase sp8870 based" depends on DVB_CORE + select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -56,6 +57,7 @@ config DVB_SP887X tristate "Spase sp887x based" depends on DVB_CORE + select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -84,6 +86,7 @@ config DVB_TDA1004X tristate "Philips TDA10045H/TDA10046H based" depends on DVB_CORE + select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -144,5 +147,14 @@ depends on DVB_CORE help A DVB-C tuner module. Say Y when you want to support this frontend. + +comment "ATSC (North American/Korean Terresterial DTV) frontends" + depends on DVB_CORE + +config DVB_NXT2002 + tristate "Nxt2002 based" + depends on DVB_CORE + help + An ATSC 8VSB 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/Makefile 2005-01-23 21:02:28 -08:00 @@ -24,3 +24,5 @@ obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o obj-$(CONFIG_DVB_TDA10021) += tda10021.o obj-$(CONFIG_DVB_STV0297) += stv0297.o +obj-$(CONFIG_DVB_NXT2002) += nxt2002.o + diff -Nru a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c --- a/drivers/media/dvb/frontends/dib3000-common.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/dib3000-common.c 2005-01-23 21:02:28 -08:00 @@ -2,7 +2,7 @@ #ifdef CONFIG_DVB_DIBCOM_DEBUG static int debug; -module_param(debug, int, 0x644); +module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able))."); #endif #define deb_info(args...) dprintk(0x01,args) @@ -42,65 +42,6 @@ return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0; } -int dib3000_init_pid_list(struct dib3000_state *state, int num) -{ - int i; - if (state != NULL) { - state->pid_list = kmalloc(sizeof(struct dib3000_pid) * num,GFP_KERNEL); - if (state->pid_list == NULL) - return -ENOMEM; - - deb_info("initializing %d pids for the pid_list.\n",num); - spin_lock_init(&state->pid_list_lock); - memset(state->pid_list,0,num*(sizeof(struct dib3000_pid))); - for (i=0; i < num; i++) { - state->pid_list[i].pid = 0; - state->pid_list[i].active = 0; - } - state->feedcount = 0; - } else - return -EINVAL; - - return 0; -} - -void dib3000_dealloc_pid_list(struct dib3000_state *state) -{ - if (state != NULL && state->pid_list != NULL) - kfree(state->pid_list); -} - -/* fetch a pid from pid_list */ -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; - } - } else { - if (pid_list[i].active && pid_list[i].pid == pid) { - pid_list[i].pid = 0; - pid_list[i].active = 0; - ret = i; - break; - } - } - - deb_info("setting pid: %5d %04x at index %d '%s'\n",pid,pid,ret,onoff ? "on" : "off"); - - spin_unlock_irqrestore(pid_list_lock,flags); - return ret; -} - int dib3000_search_status(u16 irq,u16 lock) { if (irq & 0x02) { @@ -139,7 +80,4 @@ EXPORT_SYMBOL(dib3000_read_reg); EXPORT_SYMBOL(dib3000_write_reg); -EXPORT_SYMBOL(dib3000_init_pid_list); -EXPORT_SYMBOL(dib3000_dealloc_pid_list); -EXPORT_SYMBOL(dib3000_get_pid_index); EXPORT_SYMBOL(dib3000_search_status); diff -Nru a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h --- a/drivers/media/dvb/frontends/dib3000-common.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/dib3000-common.h 2005-01-23 21:02:28 -08:00 @@ -4,7 +4,7 @@ * * DiBcom (http://www.dibcom.fr/) * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * based on GPL code from DibCom, which has * @@ -29,19 +29,10 @@ #include "dvb_frontend.h" #include "dib3000.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; -}; +/* info and err, taken from usb.h, if there is anything available like by default. */ +#define err(format, arg...) printk(KERN_ERR "dib3000mX: " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO "dib3000mX: " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "dib3000mX: " format "\n" , ## arg) /* frontend state */ struct dib3000_state { @@ -52,25 +43,18 @@ /* configuration settings */ struct dib3000_config config; - spinlock_t pid_list_lock; - struct dib3000_pid *pid_list; - - int feedcount; - struct dvb_frontend frontend; int timing_offset; int timing_offset_comp_done; + + fe_bandwidth_t last_tuned_bw; + u32 last_tuned_freq; }; /* commonly used methods by the dib3000mb/mc/p frontend */ extern int dib3000_read_reg(struct dib3000_state *state, u16 reg); extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val); -extern int dib3000_init_pid_list(struct dib3000_state *state, int num); -extern void dib3000_dealloc_pid_list(struct dib3000_state *state); -extern int dib3000_get_pid_index(struct dib3000_pid pid_list[], int num_pids, - int pid, spinlock_t *pid_list_lock,int onoff); - extern int dib3000_search_status(u16 irq,u16 lock); /* handy shortcuts */ @@ -81,7 +65,7 @@ #define wr_foreach(a,v) { int i; \ if (sizeof(a) != sizeof(v)) \ - err("sizeof: %zd %zd is different",sizeof(a),sizeof(v));\ + err("sizeof: %d %d is different",sizeof(a),sizeof(v));\ for (i=0; i < sizeof(a)/sizeof(u16); i++) \ wr(a[i],v[i]); \ } @@ -136,8 +120,8 @@ #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))) +#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8)) +#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7))) /* for auto search */ extern u16 dib3000_seq[2][2][2]; diff -Nru a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h --- a/drivers/media/dvb/frontends/dib3000.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/dib3000.h 2005-01-23 21:02:28 -08:00 @@ -2,7 +2,7 @@ * 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) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * based on GPL code from DibCom, which has * @@ -31,25 +31,24 @@ /* 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); + /* PLL maintenance and the i2c address of the PLL */ + u8 (*pll_addr)(struct dvb_frontend *fe); + int (*pll_init)(struct dvb_frontend *fe, u8 pll_buf[5]); + int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params, u8 pll_buf[5]); }; -struct dib3000_xfer_ops +struct dib_fe_xfer_ops { /* pid and transfer handling is done in the demodulator */ int (*pid_parse)(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); + int (*pid_ctrl)(struct dvb_frontend *fe, int index, int pid, int onoff); + int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); }; extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, - struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops); + struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, - struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops); + struct i2c_adapter* i2c, struct dib_fe_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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/dib3000mb.c 2005-01-23 21:02:28 -08:00 @@ -2,7 +2,7 @@ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MB * DiBcom (http://www.dibcom.fr/) * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * * based on GPL code from DibCom, which has * @@ -29,7 +29,6 @@ #include #include -#include "dvb_frontend.h" #include "dib3000-common.h" #include "dib3000mb_priv.h" #include "dib3000.h" @@ -41,7 +40,7 @@ #ifdef CONFIG_DVB_DIBCOM_DEBUG static int debug; -module_param(debug, int, 0x644); +module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."); #endif #define deb_info(args...) dprintk(0x01,args) @@ -49,6 +48,8 @@ #define deb_setf(args...) dprintk(0x04,args) #define deb_getf(args...) dprintk(0x08,args) +static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr); + static int dib3000mb_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep); @@ -61,11 +62,9 @@ int search_state,seq; if (tuner) { - wr(DIB3000MB_REG_TUNER, - DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr)); - state->config.pll_set(fe, fep); - wr(DIB3000MB_REG_TUNER, - DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr)); + dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); + state->config.pll_set(fe, fep, NULL); + dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); deb_setf("bandwidth: "); switch (ofdm->bandwidth) { @@ -390,11 +389,9 @@ 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)); + dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); + state->config.pll_init(fe,NULL); + dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); } return 0; @@ -414,6 +411,7 @@ return 0; dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB); + deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB)); if (dds_val < threshold) inv_test1 = 0; else if (dds_val == threshold) @@ -422,6 +420,7 @@ inv_test1 = 2; dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB); + deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB)); if (dds_val < threshold) inv_test2 = 0; else if (dds_val == threshold) @@ -714,18 +713,11 @@ } /* pid filter and transfer stuff */ -static int dib3000mb_pid_control(struct dvb_frontend *fe,int pid,int onoff) +static int dib3000mb_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) { struct dib3000_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); - - if (index >= 0) { wr(index+DIB3000MB_REG_FIRST_PID,pid); - } else { - err("no more pids for filtering."); - return -ENOMEM; - } return 0; } @@ -749,10 +741,21 @@ return 0; } +static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) +{ + struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + if (onoff) { + wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); + } else { + wr(DIB3000MB_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); + } + return 0; +} + static struct dvb_frontend_ops dib3000mb_ops; struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, - struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops) + struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) { struct dib3000_state* state = NULL; @@ -773,9 +776,6 @@ if (rd(DIB3000_REG_DEVICE_ID) != DIB3000MB_DEVICE_ID) goto error; - if (dib3000_init_pid_list(state,DIB3000MB_NUM_PIDS)) - goto error; - /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; @@ -784,6 +784,7 @@ xfer_ops->pid_parse = dib3000mb_pid_parse; xfer_ops->fifo_ctrl = dib3000mb_fifo_control; xfer_ops->pid_ctrl = dib3000mb_pid_control; + xfer_ops->tuner_pass_ctrl = dib3000mb_tuner_pass_ctrl; return &state->frontend; @@ -807,6 +808,7 @@ 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_RECOVER | FE_CAN_HIERARCHY_AUTO, }, diff -Nru a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c --- a/drivers/media/dvb/frontends/dib3000mc.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/dib3000mc.c 2005-01-23 21:02:28 -08:00 @@ -2,9 +2,9 @@ * Frontend driver for mobile DVB-T demodulator DiBcom 3000-MC/P * DiBcom (http://www.dibcom.fr/) * - * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.de) + * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) * - * based on GPL code from DibCom, which has + * based on GPL code from DiBCom, which has * * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr) * @@ -28,7 +28,6 @@ #include #include -#include "dvb_frontend.h" #include "dib3000-common.h" #include "dib3000mc_priv.h" #include "dib3000.h" @@ -40,14 +39,16 @@ #ifdef CONFIG_DVB_DIBCOM_DEBUG static int debug; -module_param(debug, int, 0x644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able))."); #endif #define deb_info(args...) dprintk(0x01,args) #define deb_xfer(args...) dprintk(0x02,args) #define deb_setf(args...) dprintk(0x04,args) #define deb_getf(args...) dprintk(0x08,args) +#define deb_stat(args...) dprintk(0x10,args) +static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr); static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode, fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth) @@ -185,46 +186,33 @@ return 0; } -static int dib3000mc_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep); +static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con) +{ + switch (con) { + case QAM_64: + wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]); + break; + case QAM_16: + wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]); + break; + case QPSK: + wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]); + break; + case QAM_AUTO: + break; + default: + warn("unkown constellation."); + break; + } + return 0; +} -static int dib3000mc_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep, int tuner) +static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val) { - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; fe_code_rate_t fe_cr = FEC_NONE; - int search_state, seq; - u16 val; u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0; - - if (tuner) { - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_ENABLE(state->config.pll_addr)); - state->config.pll_set(fe, fep); - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_DISABLE(state->config.pll_addr)); - } - - dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth); - dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0); - - wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC); - wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); - -/* Default cfg isi offset adp */ - wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]); - - wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT); - wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]); - wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133); - - wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); - if (ofdm->bandwidth == BANDWIDTH_8_MHZ) { - wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]); - } else { - wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]); - } + int seq; switch (ofdm->transmission_mode) { case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break; @@ -282,8 +270,7 @@ case INVERSION_OFF: wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); break; - case INVERSION_AUTO: - break; + case INVERSION_AUTO: /* fall through */ case INVERSION_ON: wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON); break; @@ -298,168 +285,12 @@ deb_setf("seq? %d\n", seq); wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1)); - - dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); - - val = rd(DIB3000MC_REG_DEMOD_PARM); - wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON); - wr(DIB3000MC_REG_DEMOD_PARM,val); - - msleep(70); - - wr_foreach(dib3000mc_reg_agc_bandwidth, dib3000mc_agc_bandwidth); - - /* something has to be auto searched */ - if (ofdm->constellation == QAM_AUTO || + *auto_val = ofdm->constellation == QAM_AUTO || ofdm->hierarchy_information == HIERARCHY_AUTO || ofdm->guard_interval == GUARD_INTERVAL_AUTO || ofdm->transmission_mode == TRANSMISSION_MODE_AUTO || fe_cr == FEC_AUTO || - fep->inversion == INVERSION_AUTO - ) { - int as_count=0; - - deb_setf("autosearch enabled.\n"); - - val = rd(DIB3000MC_REG_DEMOD_PARM); - wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); - wr(DIB3000MC_REG_DEMOD_PARM,val); - - while ((search_state = dib3000_search_status( - rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100) - msleep(10); - - deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count); - - if (search_state == 1) { - struct dvb_frontend_parameters feps; - feps.u.ofdm.bandwidth = ofdm->bandwidth; /* bw is not auto searched */; - if (dib3000mc_get_frontend(fe, &feps) == 0) { - deb_setf("reading tuning data from frontend succeeded.\n"); - return dib3000mc_set_frontend(fe, &feps, 0); - } - } - } else { - wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); - wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[qam]); - /* set_offset_cfg */ - wr_foreach(dib3000mc_reg_offset, - dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); - -// dib3000mc_set_timing(1,ofdm->transmission_mode,ofdm->bandwidth); - -// wr(DIB3000MC_REG_LOCK_MASK,DIB3000MC_ACTIVATE_LOCK_MASK); /* activates some locks if needed */ - -/* set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); - set_or(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF); - wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_ON); - wr(DIB3000MC_REG_RESTART_VIT,DIB3000MC_RESTART_VIT_OFF);*/ - } - - return 0; -} - - -static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) -{ - struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; - - state->timing_offset = 0; - state->timing_offset_comp_done = 0; - - wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); - wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK); - wr(DIB3000MC_REG_RST_I2C_ADDR, - DIB3000MC_DEMOD_ADDR(state->config.demod_address) | - DIB3000MC_DEMOD_ADDR_ON); - - wr(DIB3000MC_REG_RST_I2C_ADDR, - DIB3000MC_DEMOD_ADDR(state->config.demod_address)); - - wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG); - wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); - - wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP); - wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE); - wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP); - wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT); - - wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF); - wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19); - - wr(33,5); - wr(36,81); - wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88); - - wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99); - wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */ - - /* mobile mode - portable reception */ - wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]); - -/* TUNER_PANASONIC_ENV57H12D5: */ - wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); - wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general); - wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]); - - wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110); - wr(26,0x6680); - wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1); - wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2); - wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3); - wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT); - - wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); - wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); - - wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4); - - wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); - wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB); - - dib3000mc_set_timing(state,0,TRANSMISSION_MODE_2K,BANDWIDTH_8_MHZ); -// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]); - - wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120); - wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134); - wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG); - - dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); - -/* output mode control, just the MPEG2_SLAVE */ - set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); - wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE); - wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE); - wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE); - -/* MPEG2_PARALLEL_CONTINUOUS_CLOCK - wr(DIB3000MC_REG_OUTMODE, - DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK, - rd(DIB3000MC_REG_OUTMODE))); - - wr(DIB3000MC_REG_SMO_MODE, - DIB3000MC_SMO_MODE_DEFAULT | - DIB3000MC_SMO_MODE_188); - - wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT); - wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); -*/ -/* diversity */ - wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT); - wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT); - - wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); - - set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF); - - -/* if (state->config->pll_init) { - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_ENABLE(state->config->pll_addr)); - state->config->pll_init(fe); - wr(DIB3000MC_REG_TUNER, - DIB3000_TUNER_WRITE_DISABLE(state->config->pll_addr)); - }*/ + fep->inversion == INVERSION_AUTO; return 0; } @@ -476,7 +307,8 @@ if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507)) return 0; - dds_val = ((rd(DIB3000MC_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB); + dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB); + deb_getf("DDS_FREQ: %6x\n",dds_val); if (dds_val < threshold) inv_test1 = 0; else if (dds_val == threshold) @@ -484,7 +316,8 @@ else inv_test1 = 2; - dds_val = ((rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB); + dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB); + deb_getf("DDS_SET_FREQ: %6x\n",dds_val); if (dds_val < threshold) inv_test2 = 0; else if (dds_val == threshold) @@ -499,6 +332,9 @@ deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion); + fep->frequency = state->last_tuned_freq; + fep->u.ofdm.bandwidth= state->last_tuned_bw; + tps_val = rd(DIB3000MC_REG_TUNING_PARM); switch (DIB3000MC_TP_QAM(tps_val)) { @@ -614,9 +450,211 @@ err("unexpected transmission mode return by TPS (%d)", tps_val); break; } + deb_getf("\n"); + + return 0; +} + +static int dib3000mc_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep, int tuner) +{ + struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm; + int search_state,auto_val; + u16 val; + + if (tuner) { /* initial call from dvb */ + dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); + state->config.pll_set(fe,fep,NULL); + dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); + + state->last_tuned_freq = fep->frequency; + // if (!scanboost) { + dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth); + dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0); + state->last_tuned_bw = ofdm->bandwidth; + + wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); + wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC); + wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); + + /* Default cfg isi offset adp */ + wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]); + + wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT); + dib3000mc_set_adp_cfg(state,ofdm->constellation); + wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133); + + wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); + /* power smoothing */ + if (ofdm->bandwidth != BANDWIDTH_8_MHZ) { + wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]); + } else { + wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]); + } + auto_val = 0; + dib3000mc_set_general_cfg(state,fep,&auto_val); + dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); + + val = rd(DIB3000MC_REG_DEMOD_PARM); + wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON); + wr(DIB3000MC_REG_DEMOD_PARM,val); + // } + msleep(70); + + /* something has to be auto searched */ + if (auto_val) { + int as_count=0; + + deb_setf("autosearch enabled.\n"); + + val = rd(DIB3000MC_REG_DEMOD_PARM); + wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); + wr(DIB3000MC_REG_DEMOD_PARM,val); + + while ((search_state = dib3000_search_status( + rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100) + msleep(10); + + deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count); + + if (search_state == 1) { + struct dvb_frontend_parameters feps; + if (dib3000mc_get_frontend(fe, &feps) == 0) { + deb_setf("reading tuning data from frontend succeeded.\n"); + return dib3000mc_set_frontend(fe, &feps, 0); + } + } + } else { + dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth); + wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); + dib3000mc_set_adp_cfg(state,ofdm->constellation); + + /* set_offset_cfg */ + wr_foreach(dib3000mc_reg_offset, + dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); + } + } else { /* second call, after autosearch (fka: set_WithKnownParams) */ +// dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth); + + auto_val = 0; + dib3000mc_set_general_cfg(state,fep,&auto_val); + if (auto_val) + deb_info("auto_val is true, even though an auto search was already performed.\n"); + + dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth); + + val = rd(DIB3000MC_REG_DEMOD_PARM); + wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON); + wr(DIB3000MC_REG_DEMOD_PARM,val); + + msleep(30); + + wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE); + dib3000mc_set_adp_cfg(state,ofdm->constellation); + wr_foreach(dib3000mc_reg_offset, + dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]); + + + } return 0; } +static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) +{ + deb_info("init start\n"); + struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; + + state->timing_offset = 0; + state->timing_offset_comp_done = 0; + + wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG); + wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF); + wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP); + wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE); + wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP); + wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT); + + wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF); + wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19); + + wr(33,5); + wr(36,81); + wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88); + + wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99); + wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */ + + /* mobile mode - portable reception */ + wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]); + +/* TUNER_PANASONIC_ENV57H12D5: */ + wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth); + wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general); + wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]); + + wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110); + wr(26,0x6680); + wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1); + wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2); + wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3); + wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT); + + wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz); + wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general); + + wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4); + + wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF); + wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB); + + dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); +// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]); + + wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120); + wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134); + wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG); + + wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); + + dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ); + +/* output mode control, just the MPEG2_SLAVE */ +// set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); + wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE); + wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE); + wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE); + wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE); + +/* MPEG2_PARALLEL_CONTINUOUS_CLOCK + wr(DIB3000MC_REG_OUTMODE, + DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK, + rd(DIB3000MC_REG_OUTMODE))); + + wr(DIB3000MC_REG_SMO_MODE, + DIB3000MC_SMO_MODE_DEFAULT | + DIB3000MC_SMO_MODE_188); + + wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT); + wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); +*/ + +/* diversity */ + wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT); + wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT); + + set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF); + + set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF); + +/* if (state->config->pll_init) { + dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe)); + state->config->pll_init(fe,NULL); + dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe)); + }*/ + deb_info("init end\n"); + return 0; +} static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat) { struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; @@ -627,12 +665,12 @@ *stat |= FE_HAS_SIGNAL; if (DIB3000MC_CARRIER_LOCK(lock)) *stat |= FE_HAS_CARRIER; - if (DIB3000MC_TPS_LOCK(lock)) /* VIT_LOCK ? */ + if (DIB3000MC_TPS_LOCK(lock)) *stat |= FE_HAS_VITERBI; if (DIB3000MC_MPEG_SYNC_LOCK(lock)) *stat |= (FE_HAS_SYNC | FE_HAS_LOCK); - deb_info("actual status is %2x\n",*stat); + deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040)); return 0; } @@ -659,7 +697,7 @@ u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f); - deb_info("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff); + deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff); return 0; } @@ -667,9 +705,8 @@ static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr) { struct dib3000_state* state = (struct dib3000_state*) fe->demodulator_priv; - - u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB), - val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB); + u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB), + val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB); u16 sig,noise; sig = (((val >> 6) & 0xff) << 8) + (val & 0x3f); @@ -679,9 +716,9 @@ else *snr = (u16) sig/noise; - deb_info("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff); - deb_info("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff); - deb_info("snr: %d\n",*snr); + deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff); + deb_stat("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff); + deb_stat("snr: %d\n",*snr); return 0; } @@ -698,7 +735,7 @@ static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) { - tune->min_delay_ms = 800; + tune->min_delay_ms = 2000; tune->step_size = 166667; tune->max_drift = 166667 * 2; @@ -718,23 +755,15 @@ static void dib3000mc_release(struct dvb_frontend* fe) { struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; - dib3000_dealloc_pid_list(state); kfree(state); } /* pid filter and transfer stuff */ -static int dib3000mc_pid_control(struct dvb_frontend *fe,int pid,int onoff) +static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff) { struct dib3000_state *state = fe->demodulator_priv; - int index = dib3000_get_pid_index(state->pid_list, DIB3000MC_NUM_PIDS, pid, &state->pid_list_lock,onoff); pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0); - - if (index >= 0) { wr(index+DIB3000MC_REG_FIRST_PID,pid); - } else { - err("no more pids for filtering."); - return -ENOMEM; - } return 0; } @@ -742,10 +771,14 @@ { struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; u16 tmp = rd(DIB3000MC_REG_SMO_MODE); - deb_xfer("%s fifo",onoff ? "enabling" : "disabling"); + + deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling"); + if (onoff) { + deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH); } else { + deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH); } return 0; @@ -755,19 +788,57 @@ { struct dib3000_state *state = fe->demodulator_priv; u16 tmp = rd(DIB3000MC_REG_SMO_MODE); - deb_xfer("%s pid parsing",onoff ? "enabling" : "disabling"); + + deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling"); + if (onoff) { + deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_PID_PARSE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE); } else { + deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE); wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE); } return 0; } +static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr) +{ + struct dib3000_state *state = (struct dib3000_state*) fe->demodulator_priv; + if (onoff) { + wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr)); + } else { + wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr)); + } + return 0; +} + +static int dib3000mc_demod_init(struct dib3000_state *state) +{ + u16 default_addr = 0x0a; + /* first init */ + if (state->config.demod_address != default_addr) { + deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr); + wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON); + wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK); + + wr(DIB3000MC_REG_RST_I2C_ADDR, + DIB3000MC_DEMOD_ADDR(default_addr) | + DIB3000MC_DEMOD_ADDR_ON); + + state->config.demod_address = default_addr; + + wr(DIB3000MC_REG_RST_I2C_ADDR, + DIB3000MC_DEMOD_ADDR(default_addr)); + } else + deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address); + return 0; +} + + static struct dvb_frontend_ops dib3000mc_ops; struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, - struct i2c_adapter* i2c, struct dib3000_xfer_ops *xfer_ops) + struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) { struct dib3000_state* state = NULL; u16 devid; @@ -790,19 +861,15 @@ if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID) goto error; - switch (devid) { case DIB3000MC_DEVICE_ID: - info("Found a DiBcom 3000-MC."); + info("Found a DiBcom 3000-MC, interesting..."); break; case DIB3000P_DEVICE_ID: info("Found a DiBcom 3000-P."); break; } - if (dib3000_init_pid_list(state,DIB3000MC_NUM_PIDS)) - goto error; - /* create dvb_frontend */ state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; @@ -811,6 +878,9 @@ xfer_ops->pid_parse = dib3000mc_pid_parse; xfer_ops->fifo_ctrl = dib3000mc_fifo_control; xfer_ops->pid_ctrl = dib3000mc_pid_control; + xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl; + + dib3000mc_demod_init(state); return &state->frontend; @@ -834,6 +904,7 @@ 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_RECOVER | FE_CAN_HIERARCHY_AUTO, }, diff -Nru a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h --- a/drivers/media/dvb/frontends/dib3000mc_priv.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/dib3000mc_priv.h 2005-01-23 21:02:28 -08:00 @@ -13,31 +13,6 @@ #ifndef __DIB3000MC_PRIV_H__ #define __DIB3000MC_PRIV_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) - -// defines the phase noise algorithm to be used (O:Inhib, 1:CPE on) -#define DEF_PHASE_NOISE_MODE 0 - -// define Mobille algorithms -#define DEF_MOBILE_MODE Auto_Reception - -// defines the tuner type -#define DEF_TUNER_TYPE TUNER_PANASONIC_ENV57H13D5 - -// defines the impule noise algorithm to be used -#define DEF_IMPULSE_NOISE_MODE 0 - -// defines the MPEG2 data output format -#define DEF_MPEG2_OUTPUT_188 0 - -// defines the MPEG2 data output format -#define DEF_OUTPUT_MODE MPEG2_PARALLEL_CONTINUOUS_CLOCK - /* * Demodulator parameters * reg: 0 1 1 1 11 11 111 @@ -115,7 +90,7 @@ { 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 }; static u16 dib3000mc_bandwidth_8mhz[] = - { 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0b0 }; + { 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0d0 }; static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 }; static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 }; @@ -173,11 +148,11 @@ static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 }; static u16 dib3000mc_imp_noise_ctl[][2] = { - { 0x1294, 0xfff8 }, /* mode 0 */ - { 0x1294, 0xfff8 }, /* mode 1 */ - { 0x1294, 0xfff8 }, /* mode 2 */ - { 0x1294, 0xfff8 }, /* mode 3 */ - { 0x1294, 0xfff8 }, /* mode 4 */ + { 0x1294, 0x1ff8 }, /* mode 0 */ + { 0x1294, 0x1ff8 }, /* mode 1 */ + { 0x1294, 0x1ff8 }, /* mode 2 */ + { 0x1294, 0x1ff8 }, /* mode 3 */ + { 0x1294, 0x1ff8 }, /* mode 4 */ }; /* AGC registers */ @@ -314,12 +289,26 @@ #define DIB3000MC_REG_FEC_CFG ( 195) #define DIB3000MC_FEC_CFG ( 0x10) +/* + * reg 206, output mode + * 1111 1111 + * |||| |||| + * |||| |||+- unk + * |||| ||+-- unk + * |||| |+--- unk (on by default) + * |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed)) + * |||+------ pid_parse (1 = enabled, 0 = disabled) + * ||+------- outp_188 (1 = TS packet size 188, 0 = packet size 204) + * |+-------- unk + * +--------- unk + */ + #define DIB3000MC_REG_SMO_MODE ( 206) #define DIB3000MC_SMO_MODE_DEFAULT (1 << 2) #define DIB3000MC_SMO_MODE_FIFO_FLUSH (1 << 3) -#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH ~DIB3000MC_SMO_MODE_FIFO_FLUSH +#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH (0xfff7) #define DIB3000MC_SMO_MODE_PID_PARSE (1 << 4) -#define DIB3000MC_SMO_MODE_NO_PID_PARSE ~DIB3000MC_SMO_MODE_PID_PARSE +#define DIB3000MC_SMO_MODE_NO_PID_PARSE (0xffef) #define DIB3000MC_SMO_MODE_188 (1 << 5) #define DIB3000MC_SMO_MODE_SLAVE (DIB3000MC_SMO_MODE_DEFAULT | \ DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1)) @@ -392,7 +381,7 @@ #define DIB3000MC_REG_RST_I2C_ADDR ( 1024) #define DIB3000MC_DEMOD_ADDR_ON ( 1) -#define DIB3000MC_DEMOD_ADDR(a) ((a << 3) & 0x03F0) +#define DIB3000MC_DEMOD_ADDR(a) ((a << 4) & 0x03F0) #define DIB3000MC_REG_RESTART ( 1027) #define DIB3000MC_RESTART_OFF (0x0000) diff -Nru a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c --- a/drivers/media/dvb/frontends/mt352.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/mt352.c 2005-01-23 21:02:28 -08:00 @@ -58,16 +58,26 @@ if (debug) printk(KERN_DEBUG "mt352: " args); \ } while (0) -int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen) +static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val) { struct mt352_state* state = (struct mt352_state*) fe->demodulator_priv; + u8 buf[2] = { reg, val }; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, - .buf = ibuf, .len = ilen }; + .buf = buf, .len = 2 }; int err = i2c_transfer(state->i2c, &msg, 1); if (err != 1) { - dprintk("mt352_write() failed (err = %d)!\n", err); + dprintk("mt352_write() to reg %x failed (err = %d)!\n", reg, err); return err; } + return 0; +} + +int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen) +{ + int err,i; + for (i=0; i < ilen-1; i++) + if ((err = mt352_single_write(fe,ibuf[0]+i,ibuf[i+1]))) + return err; return 0; } @@ -92,9 +102,10 @@ return b1[0]; } - - - +u8 mt352_read(struct dvb_frontend *fe, u8 reg) +{ + return mt352_read_register(fe->demodulator_priv,reg); +} @@ -556,3 +567,4 @@ EXPORT_SYMBOL(mt352_attach); EXPORT_SYMBOL(mt352_write); +EXPORT_SYMBOL(mt352_read); diff -Nru a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h --- a/drivers/media/dvb/frontends/mt352.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/mt352.h 2005-01-23 21:02:28 -08:00 @@ -54,5 +54,6 @@ struct i2c_adapter* i2c); extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen); +extern u8 mt352_read(struct dvb_frontend *fe, u8 reg); #endif // MT352_H diff -Nru a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/nxt2002.c 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,670 @@ +/* + Support for B2C2/BBTI Technisat Air2PC - ATSC + + Copyright (C) 2004 Taylor Jacob + + 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 nxt2002" to + * download/extract it, and then copy it to /usr/lib/hotplug/firmware. + */ +#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" +#define CRC_CCIT_MASK 0x1021 + +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "nxt2002.h" + +struct nxt2002_state { + + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + const struct nxt2002_config* config; + struct dvb_frontend frontend; + + /* demodulator private data */ + u8 initialised:1; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "nxt2002: " args); \ + } while (0) + +static int i2c_writebytes (struct nxt2002_state* state, u8 reg, u8 *buf, u8 len) +{ + /* probbably a much better way or doing this */ + u8 buf2 [256],x; + int err; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; + + buf2[0] = reg; + for (x = 0 ; x < len ; x++) + buf2[x+1] = buf[x]; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk ("%s: i2c write error (addr %02x, err == %i)\n", + __FUNCTION__, state->config->demod_address, err); + return -EREMOTEIO; + } + + return 0; +} + +static u8 i2c_readbytes (struct nxt2002_state* state, u8 reg, u8* buf, u8 len) +{ + u8 reg2 [] = { reg }; + + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; + + int err; + + if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { + printk ("%s: i2c read error (addr %02x, err == %i)\n", + __FUNCTION__, state->config->demod_address, err); + return -EREMOTEIO; + } + + return 0; +} + +static u16 nxt2002_crc(u16 crc, u8 c) +{ + + u8 i; + u16 input = (u16) c & 0xFF; + + input<<=8; + for(i=0 ;i<8 ;i++) { + if((crc ^ input) & 0x8000) + crc=(crc<<1)^CRC_CCIT_MASK; + else + crc<<=1; + input<<=1; + } + return crc; +} + +static int nxt2002_writereg_multibyte (struct nxt2002_state* state, u8 reg, u8* data, u8 len) +{ + u8 buf; + dprintk("%s\n", __FUNCTION__); + + /* set multi register length */ + i2c_writebytes(state,0x34,&len,1); + + /* set mutli register register */ + i2c_writebytes(state,0x35,®,1); + + /* send the actual data */ + i2c_writebytes(state,0x36,data,len); + + /* toggle the multireg write bit*/ + buf = 0x02; + i2c_writebytes(state,0x21,&buf,1); + + i2c_readbytes(state,0x21,&buf,1); + + if ((buf & 0x02) == 0) + return 0; + + dprintk("Error writing multireg register %02X\n",reg); + + return 0; +} + +static int nxt2002_readreg_multibyte (struct nxt2002_state* state, u8 reg, u8* data, u8 len) +{ + u8 len2; + dprintk("%s\n", __FUNCTION__); + + /* set multi register length */ + len2 = len & 0x80; + i2c_writebytes(state,0x34,&len2,1); + + /* set mutli register register */ + i2c_writebytes(state,0x35,®,1); + + /* send the actual data */ + i2c_readbytes(state,reg,data,len); + + return 0; +} + +static void nxt2002_microcontroller_stop (struct nxt2002_state* state) +{ + u8 buf[2],counter = 0; + dprintk("%s\n", __FUNCTION__); + + buf[0] = 0x80; + i2c_writebytes(state,0x22,buf,1); + + while (counter < 20) { + i2c_readbytes(state,0x31,buf,1); + if (buf[0] & 0x40) + return; + msleep(10); + counter++; + } + + dprintk("Timeout waiting for micro to stop.. This is ok after firmware upload\n"); + return; +} + +static void nxt2002_microcontroller_start (struct nxt2002_state* state) +{ + u8 buf; + dprintk("%s\n", __FUNCTION__); + + buf = 0x00; + i2c_writebytes(state,0x22,&buf,1); +} + +static int nxt2002_writetuner (struct nxt2002_state* state, u8* data) +{ + u8 buf,count = 0; + + dprintk("Tuner Bytes: %02X %02X %02X %02X\n",data[0],data[1],data[2],data[3]); + + dprintk("%s\n", __FUNCTION__); + /* stop the micro first */ + nxt2002_microcontroller_stop(state); + + /* set the i2c transfer speed to the tuner */ + buf = 0x03; + i2c_writebytes(state,0x20,&buf,1); + + /* setup to transfer 4 bytes via i2c */ + buf = 0x04; + i2c_writebytes(state,0x34,&buf,1); + + /* write actual tuner bytes */ + i2c_writebytes(state,0x36,data,4); + + /* set tuner i2c address */ + buf = 0xC2; + i2c_writebytes(state,0x35,&buf,1); + + /* write UC Opmode to begin transfer */ + buf = 0x80; + i2c_writebytes(state,0x21,&buf,1); + + while (count < 20) { + i2c_readbytes(state,0x21,&buf,1); + if ((buf & 0x80)== 0x00) + return 0; + msleep(100); + count++; + } + + printk("nxt2002: timeout error writing tuner\n"); + return 0; +} + +static void nxt2002_agc_reset(struct nxt2002_state* state) +{ + u8 buf; + dprintk("%s\n", __FUNCTION__); + + buf = 0x08; + i2c_writebytes(state,0x08,&buf,1); + + buf = 0x00; + i2c_writebytes(state,0x08,&buf,1); + + return; +} + +static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + u8 buf[256],written = 0,chunkpos = 0; + u16 rambase,position,crc = 0; + + dprintk("%s\n", __FUNCTION__); + dprintk("Firmware is %d bytes\n",fw->size); + + /* Get the RAM base for this nxt2002 */ + i2c_readbytes(state,0x10,buf,1); + + + if (buf[0] & 0x10) + rambase = 0x1000; + else + rambase = 0x0000; + + dprintk("rambase on this nxt2002 is %04X\n",rambase); + + /* Hold the micro in reset while loading firmware */ + buf[0] = 0x80; + i2c_writebytes(state,0x2B,buf,1); + + + for (position = 0; position < fw->size ; position++) { + if (written == 0) { + crc = 0; + chunkpos = 0x28; + buf[0] = ((rambase + position) >> 8); + buf[1] = (rambase + position) & 0xFF; + buf[2] = 0x81; + /* write starting address */ + i2c_writebytes(state,0x29,buf,3); + } + written++; + chunkpos++; + + if ((written % 4) == 0) + i2c_writebytes(state,chunkpos,&fw->data[position-3],4); + + crc = nxt2002_crc(crc,fw->data[position]); + + + if ((written == 255) || (position+1 == fw->size)) { + /* write remaining bytes of firmware */ + i2c_writebytes(state, chunkpos+4-(written %4), + &fw->data[position-(written %4) + 1], + written %4); + buf[0] = crc << 8; + buf[1] = crc & 0xFF; + + /* write crc */ + i2c_writebytes(state,0x2C,buf,2); + + /* do a read to stop things */ + i2c_readbytes(state,0x2A,buf,1); + + /* set transfer mode to complete */ + buf[0] = 0x80; + i2c_writebytes(state,0x2B,buf,1); + + written = 0; + } + } + + printk ("done.\n"); + return 0; +}; + + +static int nxt2002_setup_frontend_parameters (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + u32 freq = 0; + u16 tunerfreq = 0; + u8 buf[4]; + + freq = 44000 + ( p->frequency / 1000 ); + + dprintk("freq = %d p->frequency = %d\n",freq,p->frequency); + + tunerfreq = freq * 24/4000; + + buf[0] = (tunerfreq >> 8) & 0x7F; + buf[1] = (tunerfreq & 0xFF); + + if (p->frequency <= 214000000) { + buf[2] = 0x84 + (0x06 << 3); + buf[3] = (p->frequency <= 172000000) ? 0x01 : 0x02; + } else if (p->frequency <= 721000000) { + buf[2] = 0x84 + (0x07 << 3); + buf[3] = (p->frequency <= 467000000) ? 0x02 : 0x08; + } else if (p->frequency <= 841000000) { + buf[2] = 0x84 + (0x0E << 3); + buf[3] = 0x08; + } else { + buf[2] = 0x84 + (0x0F << 3); + buf[3] = 0x02; + } + + /* write frequency information */ + nxt2002_writetuner(state,buf); + + /* reset the agc now that tuning has been completed */ + nxt2002_agc_reset(state); + + /* set target power level */ + buf[0] = 0x70; + i2c_writebytes(state,0x42,buf,1); + + /* configure sdm */ + buf[0] = 0x87; + i2c_writebytes(state,0x57,buf,1); + + /* write sdm1 input */ + buf[0] = 0x10; + buf[1] = 0x00; + nxt2002_writereg_multibyte(state,0x58,buf,2); + + /* write sdmx input */ + buf[0] = 0x60; + buf[1] = 0x00; + nxt2002_writereg_multibyte(state,0x5C,buf,2); + + /* write adc power lpf fc */ + buf[0] = 0x05; + i2c_writebytes(state,0x43,buf,1); + + /* write adc power lpf fc */ + buf[0] = 0x05; + i2c_writebytes(state,0x43,buf,1); + + /* write accumulator2 input */ + buf[0] = 0x80; + buf[1] = 0x00; + nxt2002_writereg_multibyte(state,0x4B,buf,2); + + /* write kg1 */ + buf[0] = 0x00; + i2c_writebytes(state,0x4D,buf,1); + + /* write sdm12 lpf fc */ + buf[0] = 0x44; + i2c_writebytes(state,0x55,buf,1); + + /* write agc control reg */ + buf[0] = 0x04; + i2c_writebytes(state,0x41,buf,1); + + /* write agc ucgp0 */ + buf[0] = 0x00; + i2c_writebytes(state,0x30,buf,1); + + /* write agc control reg */ + buf[0] = 0x00; + i2c_writebytes(state,0x41,buf,1); + + /* write accumulator2 input */ + buf[0] = 0x80; + buf[1] = 0x00; + nxt2002_writereg_multibyte(state,0x49,buf,2); + nxt2002_writereg_multibyte(state,0x4B,buf,2); + + /* write agc control reg */ + buf[0] = 0x04; + i2c_writebytes(state,0x41,buf,1); + + nxt2002_microcontroller_start(state); + + /* adjacent channel detection should be done here, but I don't + have any stations with this need so I cannot test it */ + + return 0; +} + +static int nxt2002_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + u8 lock; + i2c_readbytes(state,0x31,&lock,1); + + *status = 0; + if (lock & 0x20) { + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_LOCK; + } + return 0; +} + +static int nxt2002_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + u8 b[3]; + + nxt2002_readreg_multibyte(state,0xE6,b,3); + + *ber = ((b[0] << 8) + b[1]) * 8; + + return 0; +} + +static int nxt2002_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + u8 b[2]; + u16 temp = 0; + + /* setup to read cluster variance */ + b[0] = 0x00; + i2c_writebytes(state,0xA1,b,1); + + /* get multreg val */ + nxt2002_readreg_multibyte(state,0xA6,b,2); + + temp = (b[0] << 8) | b[1]; + *strength = ((0x7FFF - temp) & 0x0FFF) * 16; + + return 0; +} + +static int nxt2002_read_snr(struct dvb_frontend* fe, u16* snr) +{ + + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + u8 b[2]; + u16 temp = 0, temp2; + u32 snrdb = 0; + + /* setup to read cluster variance */ + b[0] = 0x00; + i2c_writebytes(state,0xA1,b,1); + + /* get multreg val from 0xA6 */ + nxt2002_readreg_multibyte(state,0xA6,b,2); + + temp = (b[0] << 8) | b[1]; + temp2 = 0x7FFF - temp; + + /* snr will be in db */ + if (temp2 > 0x7F00) + snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) ); + else if (temp2 > 0x7EC0) + snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) ); + else if (temp2 > 0x7C00) + snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) ); + else + snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) ); + + /* the value reported back from the frontend will be FFFF=32db 0000=0db */ + + *snr = snrdb * (0xFFFF/32000); + + return 0; +} + +static int nxt2002_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + u8 b[3]; + + nxt2002_readreg_multibyte(state,0xE6,b,3); + + *ucblocks = b[2]; + + return 0; +} + +static int nxt2002_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int nxt2002_init(struct dvb_frontend* fe) +{ + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + const struct firmware *fw; + int ret; + u8 buf[2]; + + if (!state->initialised) { + /* request the firmware, this will block until someone uploads it */ + printk("nxt2002: Waiting for firmware upload...\n"); + ret = state->config->request_firmware(fe, &fw, NXT2002_DEFAULT_FIRMWARE); + printk("nxt2002: Waiting for firmware upload(2)...\n"); + if (ret) { + printk("nxt2002: no firmware upload (timeout or file not found?)\n"); + return ret; + } + + ret = nxt2002_load_firmware(fe, fw); + if (ret) { + printk("nxt2002: writing firmware to device failed\n"); + release_firmware(fw); + return ret; + } + + /* Put the micro into reset */ + nxt2002_microcontroller_stop(state); + + /* ensure transfer is complete */ + buf[0]=0; + i2c_writebytes(state,0x2B,buf,1); + + /* Put the micro into reset for real this time */ + nxt2002_microcontroller_stop(state); + + /* soft reset everything (agc,frontend,eq,fec)*/ + buf[0] = 0x0F; + i2c_writebytes(state,0x08,buf,1); + buf[0] = 0x00; + i2c_writebytes(state,0x08,buf,1); + + /* write agc sdm configure */ + buf[0] = 0xF1; + i2c_writebytes(state,0x57,buf,1); + + /* write mod output format */ + buf[0] = 0x20; + i2c_writebytes(state,0x09,buf,1); + + /* write fec mpeg mode */ + buf[0] = 0x7E; + buf[1] = 0x00; + i2c_writebytes(state,0xE9,buf,2); + + /* write mux selection */ + buf[0] = 0x00; + i2c_writebytes(state,0xCC,buf,1); + + state->initialised = 1; + } + + return 0; +} + +static int nxt2002_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 500; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void nxt2002_release(struct dvb_frontend* fe) +{ + struct nxt2002_state* state = (struct nxt2002_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops nxt2002_ops; + +struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config, + struct i2c_adapter* i2c) +{ + struct nxt2002_state* state = NULL; + u8 buf [] = {0,0,0,0,0}; + + /* allocate memory for the internal state */ + state = (struct nxt2002_state*) kmalloc(sizeof(struct nxt2002_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &nxt2002_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + + /* Check the first 5 registers to ensure this a revision we can handle */ + + i2c_readbytes(state, 0x00, buf, 5); + if (buf[0] != 0x04) goto error; /* device id */ + if (buf[1] != 0x02) goto error; /* fab id */ + if (buf[2] != 0x11) goto error; /* month */ + if (buf[3] != 0x20) goto error; /* year msb */ + if (buf[4] != 0x00) goto error; /* year lsb */ + + /* 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 nxt2002_ops = { + + .info = { + .name = "Nextwave nxt2002 VSB/QAM frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 803000000, + /* stepsize is just a guess */ + .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_8VSB + }, + + .release = nxt2002_release, + + .init = nxt2002_init, + .sleep = nxt2002_sleep, + + .set_frontend = nxt2002_setup_frontend_parameters, + .get_tune_settings = nxt2002_get_tune_settings, + + .read_status = nxt2002_read_status, + .read_ber = nxt2002_read_ber, + .read_signal_strength = nxt2002_read_signal_strength, + .read_snr = nxt2002_read_snr, + .read_ucblocks = nxt2002_read_ucblocks, + +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("NXT2002 ATSC (8VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver"); +MODULE_AUTHOR("Taylor Jacob"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(nxt2002_attach); diff -Nru a/drivers/media/dvb/frontends/nxt2002.h b/drivers/media/dvb/frontends/nxt2002.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/dvb/frontends/nxt2002.h 2005-01-23 21:02:28 -08:00 @@ -0,0 +1,23 @@ +/* + Driver for the Nxt2002 demodulator +*/ + +#ifndef NXT2002_H +#define NXT2002_H + +#include +#include + +struct nxt2002_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* request firmware for device */ + int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); +}; + +extern struct dvb_frontend* nxt2002_attach(const struct nxt2002_config* config, + struct i2c_adapter* i2c); + +#endif // NXT2002_H diff -Nru a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c --- a/drivers/media/dvb/frontends/stv0297.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/stv0297.c 2005-01-23 21:02:28 -08:00 @@ -38,10 +38,7 @@ struct dvb_frontend frontend; - int freq_off; - unsigned long base_freq; - u8 pwm; }; @@ -162,8 +159,10 @@ 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 } }; + 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) { @@ -193,8 +192,10 @@ 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 } }; + 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) { @@ -209,6 +210,21 @@ 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, 0x58) << 24; + + tmp *= STV0297_CLOCK_KHZ; + tmp >>= 32; + + return (u32) tmp; +} + static void stv0297_set_symbolrate(struct stv0297_state *state, u32 srate) { long tmp; @@ -259,39 +275,40 @@ stv0297_writereg_mask(state, 0x69, 0x0F, (tmp >> 24) & 0x0f); } +/* static long stv0297_get_carrieroffset(struct stv0297_state* state) { - s32 raw; - long tmp; + s64 tmp; stv0297_writereg(state,0x6B, 0x00); - raw = stv0297_readreg(state,0x66); - raw |= (stv0297_readreg(state,0x67) << 8); - raw |= (stv0297_readreg(state,0x68) << 16); - raw |= (stv0297_readreg(state,0x69) & 0x0F) << 24; + tmp = stv0297_readreg(state, 0x66); + tmp |= (stv0297_readreg(state, 0x67) << 8); + tmp |= (stv0297_readreg(state, 0x68) << 16); + tmp |= (stv0297_readreg(state, 0x69) & 0x0F) << 24; - tmp = raw; - tmp /= 26844L; + tmp *= stv0297_get_symbolrate(state); + tmp >>= 28; - return tmp; + return (s32) tmp; } +*/ static void stv0297_set_initialdemodfreq(struct stv0297_state* state, long freq) { -/* - s64 tmp; + s32 tmp; - if (freq > 10000) freq -= STV0297_CLOCK_KHZ; + if (freq > 10000) + freq -= STV0297_CLOCK_KHZ; - tmp = freq << 16; - do_div(tmp, STV0297_CLOCK_KHZ); - if (tmp > 0xffff) tmp = 0xffff; // check this calculation + tmp = (STV0297_CLOCK_KHZ * 1000) / (1 << 16); + tmp = (freq * 1000) / tmp; + 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) @@ -413,6 +430,15 @@ return 0; } +static int stv0297_sleep(struct dvb_frontend *fe) +{ + struct stv0297_state *state = (struct stv0297_state *) fe->demodulator_priv; + + stv0297_writereg_mask(state, 0x80, 1, 1); + + 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; @@ -484,6 +510,7 @@ int carrieroffset; unsigned long starttime; unsigned long timeout; + fe_spectral_inversion_t inversion; switch(p->u.qam.modulation) { case QAM_16: @@ -508,8 +535,11 @@ } // determine inversion dependant parameters + inversion = p->inversion; + if (state->config->invert) + inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; carrieroffset = -330; - switch(p->inversion) { + switch (inversion) { case INVERSION_OFF: break; @@ -522,13 +552,14 @@ return -EINVAL; } + stv0297_init(fe); state->config->pll_set(fe, p); /* clear software interrupts */ stv0297_writereg(state, 0x82, 0x0); /* set initial demodulation frequency */ - stv0297_set_initialdemodfreq(state, state->freq_off + 7250); + stv0297_set_initialdemodfreq(state, 7250); /* setup AGC */ stv0297_writereg_mask(state, 0x43, 0x10, 0x00); @@ -588,7 +619,7 @@ stv0297_set_symbolrate(state, p->u.qam.symbol_rate/1000); stv0297_set_sweeprate(state, sweeprate, p->u.qam.symbol_rate / 1000); stv0297_set_carrieroffset(state, carrieroffset); - stv0297_set_inversion(state, p->inversion); + stv0297_set_inversion(state, inversion); /* kick off lock */ stv0297_writereg_mask(state, 0x88, 0x08, 0x08); @@ -664,7 +695,6 @@ /* success!! */ stv0297_writereg_mask(state, 0x5a, 0x40, 0x00); - state->freq_off = stv0297_get_carrieroffset(state); state->base_freq = p->frequency; return 0; @@ -681,10 +711,12 @@ reg_00 = stv0297_readreg(state, 0x00); reg_83 = stv0297_readreg(state, 0x83); - p->frequency = state->base_freq + state->freq_off; + p->frequency = state->base_freq; p->inversion = (reg_83 & 0x08) ? INVERSION_ON : INVERSION_OFF; - p->u.qam.symbol_rate = 0; - p->u.qam.fec_inner = 0; + if (state->config->invert) + p->inversion = (p->inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; + p->u.qam.symbol_rate = stv0297_get_symbolrate(state) * 1000; + p->u.qam.fec_inner = FEC_NONE; switch((reg_00 >> 4) & 0x7) { case 0: @@ -729,7 +761,6 @@ 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; @@ -764,6 +795,7 @@ .release = stv0297_release, .init = stv0297_init, + .sleep = stv0297_sleep, .set_frontend = stv0297_set_frontend, .get_frontend = stv0297_get_frontend, diff -Nru a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h --- a/drivers/media/dvb/frontends/stv0297.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/stv0297.h 2005-01-23 21:02:28 -08:00 @@ -29,6 +29,9 @@ /* 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); diff -Nru a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c --- a/drivers/media/dvb/frontends/tda10021.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/tda10021.c 2005-01-23 21:02:28 -08:00 @@ -4,7 +4,7 @@ Copyright (C) 1999 Convergence Integrated Media GmbH Copyright (C) 2004 Markus Schulz - Suppport for TDA10021 + Support 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 diff -Nru a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h --- a/drivers/media/dvb/frontends/tda10021.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/tda10021.h 2005-01-23 21:02:28 -08:00 @@ -4,7 +4,7 @@ Copyright (C) 1999 Convergence Integrated Media GmbH Copyright (C) 2004 Markus Schulz - Suppport for TDA10021 + Support 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 diff -Nru a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c --- a/drivers/media/dvb/frontends/tda80xx.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/frontends/tda80xx.c 2005-01-23 21:02:28 -08:00 @@ -27,10 +27,10 @@ #include #include #include +#include #include #include #include -#include #include #include "dvb_frontend.h" diff -Nru a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c --- a/drivers/media/dvb/ttpci/av7110.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttpci/av7110.c 2005-01-23 21:02:28 -08:00 @@ -67,6 +67,12 @@ #include "av7110_ca.h" #include "av7110_ipack.h" +#define TS_WIDTH 376 +#define TS_HEIGHT 512 +#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) +#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) + + int av7110_debug; static int vidmode=CVBS_RGB_OUT; @@ -75,6 +81,7 @@ static int hw_sections; static int rgb_on; static int volume = 255; +static int budgetpatch = 0; module_param_named(debug, av7110_debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); @@ -91,6 +98,8 @@ " signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); module_param(volume, int, 0444); MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); +module_param(budgetpatch, int, 0444); +MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); static void restart_feeds(struct av7110 *av7110); @@ -349,27 +358,42 @@ #endif } +#define DEBI_READ 0 +#define DEBI_WRITE 1 +static inline void start_debi_dma(struct av7110 *av7110, int dir, + unsigned long addr, unsigned int len) +{ + dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len); + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__); + return; + } + + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); /* for good measure */ + SAA7146_IER_ENABLE(av7110->dev, MASK_19); + if (len < 5) + len = 5; /* we want a real DEBI DMA */ + if (dir == DEBI_WRITE) + iwdebi(av7110, DEBISWAB, addr, 0, (len + 3) & ~3); + else + irdebi(av7110, DEBISWAB, addr, 0, len); +} + static void debiirq (unsigned long data) { struct av7110 *av7110 = (struct av7110*) data; int type=av7110->debitype; int handle=(type>>8)&0x1f; - -// dprintk(4, "%p\n",av7110); + unsigned int xfer = 0; print_time("debi"); - SAA7146_IER_DISABLE(av7110->dev, MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); + dprintk(4, "type 0x%04x\n", type); if (type==-1) { printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", jiffies, saa7146_read(av7110->dev, PSR), saa7146_read(av7110->dev, SSR)); - spin_lock(&av7110->debilock); - ARM_ClearMailBox(av7110); - ARM_ClearIrq(av7110); - spin_unlock(&av7110->debilock); - return; + goto debi_done; } av7110->debitype=-1; @@ -379,22 +403,16 @@ dvb_dmx_swfilter_packets(&av7110->demux, (const u8 *)av7110->debi_virt, av7110->debilen/188); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_PES_RECORD: if (av7110->demux.recording) av7110_record_cb(&av7110->p2t[handle], (u8 *)av7110->debi_virt, av7110->debilen); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_IPMPE: case DATA_FSECTION: @@ -404,11 +422,8 @@ av7110->debilen, NULL, 0, av7110->handle2filter[handle], DMX_OK, av7110); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_CI_GET: { @@ -425,11 +440,8 @@ ci_get_data(&av7110->ci_rbuffer, av7110->debi_virt, av7110->debilen); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; } case DATA_COMMON_INTERFACE: @@ -449,37 +461,35 @@ printk("\n"); } #endif - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_DEBUG_MESSAGE: ((s8*)av7110->debi_virt)[Reserved_SIZE-1]=0; printk("%s\n", (s8 *)av7110->debi_virt); - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + xfer = RX_BUFF; + break; case DATA_CI_PUT: + dprintk(4, "debi DATA_CI_PUT\n"); case DATA_MPEG_PLAY: + dprintk(4, "debi DATA_MPEG_PLAY\n"); case DATA_BMP_LOAD: - spin_lock(&av7110->debilock); - iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); - ARM_ClearMailBox(av7110); - spin_unlock(&av7110->debilock); - return; + dprintk(4, "debi DATA_BMP_LOAD\n"); + xfer = TX_BUFF; + break; default: break; } +debi_done: spin_lock(&av7110->debilock); + if (xfer) + iwdebi(av7110, DEBINOSWAP, xfer, 0, 2); ARM_ClearMailBox(av7110); spin_unlock(&av7110->debilock); } +/* irq from av7110 firmware writing the mailbox register in the DPRAM */ static void gpioirq (unsigned long data) { struct av7110 *av7110 = (struct av7110*) data; @@ -487,27 +497,29 @@ int len; if (av7110->debitype !=-1) + /* we shouldn't get any irq while a debi xfer is running */ printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", jiffies, saa7146_read(av7110->dev, PSR), saa7146_read(av7110->dev, SSR)); - spin_lock(&av7110->debilock); + if (saa7146_wait_for_debi_done(av7110->dev, 0)) { + printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __FUNCTION__); + BUG(); /* maybe we should try resetting the debi? */ + } + spin_lock(&av7110->debilock); ARM_ClearIrq(av7110); - SAA7146_IER_DISABLE(av7110->dev, MASK_19); - SAA7146_ISR_CLEAR(av7110->dev, MASK_19); - + /* see what the av7110 wants */ av7110->debitype = irdebi(av7110, DEBINOSWAP, IRQ_STATE, 0, 2); av7110->debilen = irdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); rxbuf=irdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); txbuf=irdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); len = (av7110->debilen + 3) & ~3; -// dprintk(8, "GPIO0 irq %d %d\n", av7110->debitype, av7110->debilen); print_time("gpio"); + dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen); -// dprintk(8, "GPIO0 irq %02x\n", av7110->debitype&0xff); switch (av7110->debitype&0xff) { case DATA_TS_PLAY: @@ -579,16 +591,12 @@ dvb_ringbuffer_read(cibuf,av7110->debi_virt,len,0); - 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, 0); - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19 ); - if (len < 5) - len = 5; /* we want a real DEBI DMA */ - iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len+3)&~3); + dprintk(8, "DMA: CI\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); spin_unlock(&av7110->debilock); + wake_up(&cibuf->queue); return; } @@ -620,22 +628,21 @@ 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, 0); - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19 ); - - iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len+3)&~3); + dprintk(8, "DMA: MPEG_PLAY\n"); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len); spin_unlock(&av7110->debilock); return; case DATA_BMP_LOAD: len=av7110->debilen; + dprintk(8, "gpio DATA_BMP_LOAD len %d\n", len); if (!len) { av7110->bmp_state=BMP_LOADED; iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, 0, 2); iwdebi(av7110, DEBINOSWAP, TX_LEN, 0, 2); iwdebi(av7110, DEBINOSWAP, TX_BUFF, 0, 2); wake_up(&av7110->bmpq); + dprintk(8, "gpio DATA_BMP_LOAD done\n"); break; } if (len>av7110->bmplen) @@ -647,12 +654,8 @@ memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len); av7110->bmpp+=len; av7110->bmplen-=len; - saa7146_wait_for_debi_done(av7110->dev, 0); - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19 ); - if (len < 5) - len = 5; /* we want a real DEBI DMA */ - iwdebi(av7110, DEBISWAB, DPRAM_BASE+txbuf, 0, (len+3)&~3); + dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len); + start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len); spin_unlock(&av7110->debilock); return; @@ -669,22 +672,17 @@ case DATA_TS_RECORD: case DATA_PES_RECORD: - 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); + dprintk(8, "DMA: TS_REC etc.\n"); + start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len); spin_unlock(&av7110->debilock); return; case DATA_DEBUG_MESSAGE: - saa7146_wait_for_debi_done(av7110->dev, 0); if (!len || len>0xff) { iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; } - saa7146_write(av7110->dev, IER, - saa7146_read(av7110->dev, IER) | MASK_19); - irdebi(av7110, DEBISWAB, Reserved, 0, len); + start_debi_dma(av7110, DEBI_READ, Reserved, len); spin_unlock(&av7110->debilock); return; @@ -699,8 +697,8 @@ av7110->debitype, av7110->debilen); break; } - ARM_ClearMailBox(av7110); av7110->debitype=-1; + ARM_ClearMailBox(av7110); spin_unlock(&av7110->debilock); } @@ -1145,11 +1143,107 @@ return 0; } +/* simplified code from budget-core.c */ +static int stop_ts_capture(struct av7110 *budget) +{ + dprintk(2, "budget: %p\n", budget); + + if (--budget->feeding1) + return budget->feeding1; + saa7146_write(budget->dev, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(budget->dev, MASK_10); + SAA7146_ISR_CLEAR(budget->dev, MASK_10); + return 0; +} + +static int start_ts_capture(struct av7110 *budget) +{ + dprintk(2, "budget: %p\n", budget); + + if (budget->feeding1) + return ++budget->feeding1; + memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); + budget->tsf = 0xff; + budget->ttbp = 0; + SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ + saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ + return ++budget->feeding1; +} + +static int budget_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = (struct av7110 *) demux->priv; + int status; + + dprintk(2, "av7110: %p\n", budget); + + spin_lock(&budget->feedlock1); + feed->pusi_seen = 0; /* have a clean section start */ + status = start_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static int budget_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct av7110 *budget = (struct av7110 *) demux->priv; + int status; + + dprintk(2, "budget: %p\n", budget); + + spin_lock(&budget->feedlock1); + status = stop_ts_capture(budget); + spin_unlock(&budget->feedlock1); + return status; +} + +static void vpeirq(unsigned long data) +{ + struct av7110 *budget = (struct av7110 *) data; + u8 *mem = (u8 *) (budget->grabbing); + u32 olddma = budget->ttbp; + u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + + if (!budgetpatch) { + printk("av7110.c: vpeirq() called while budgetpatch disabled!" + " check saa7146 IER register\n"); + BUG(); + } + /* nearest lower position divisible by 188 */ + newdma -= newdma % 188; + + if (newdma >= TS_BUFLEN) + return; + + budget->ttbp = newdma; + + if (!budget->feeding1 || (newdma == olddma)) + return; + +#if 0 + /* track rps1 activity */ + printk("vpeirq: %02x Event Counter 1 0x%04x\n", + mem[olddma], + saa7146_read(budget->dev, EC1R) & 0x3fff); +#endif + + if (newdma > olddma) + /* no wraparound, dump olddma..newdma */ + dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188); + else { + /* wraparound, dump olddma..buflen and 0..newdma */ + dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188); + dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188); + } +} static int av7110_register(struct av7110 *av7110) { int ret, i; struct dvb_demux *dvbdemux=&av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; dprintk(4, "%p\n", av7110); @@ -1209,6 +1303,32 @@ dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net, &dvbdemux->dmx); + if (budgetpatch) { + /* initialize software demux1 without its own frontend + * demux1 hardware is connected to frontend0 of demux0 + */ + dvbdemux1->priv = (void *) av7110; + + dvbdemux1->filternum = 256; + dvbdemux1->feednum = 256; + dvbdemux1->start_feed = budget_start_feed; + dvbdemux1->stop_feed = budget_stop_feed; + dvbdemux1->write_to_decoder = NULL; + + dvbdemux1->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING); + + dvb_dmx_init(&av7110->demux1); + + av7110->dmxdev1.filternum = 256; + av7110->dmxdev1.demux = &dvbdemux1->dmx; + av7110->dmxdev1.capabilities = 0; + + dvb_dmxdev_init(&av7110->dmxdev1, av7110->dvb_adapter); + + dvb_net_init(av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx); + printk("dvb-ttpci: additional demux1 for budget-patch registered\n"); + } return 0; } @@ -1216,12 +1336,20 @@ static void dvb_unregister(struct av7110 *av7110) { struct dvb_demux *dvbdemux=&av7110->demux; + struct dvb_demux *dvbdemux1 = &av7110->demux1; dprintk(4, "%p\n", av7110); if (!av7110->registered) return; + if (budgetpatch) { + dvb_net_release(&av7110->dvb_net1); + dvbdemux->dmx.close(&dvbdemux1->dmx); + dvb_dmxdev_release(&av7110->dmxdev1); + dvb_dmx_release(&av7110->demux1); + } + dvb_net_release(&av7110->dvb_net); dvbdemux->dmx.close(&dvbdemux->dmx); @@ -1700,6 +1828,7 @@ static struct stv0297_config nexusca_stv0297_config = { .demod_address = 0x1C, + .invert = 1, .pll_set = nexusca_stv0297_pll_set, }; @@ -1899,12 +2028,22 @@ av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); break; + case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */ + /* 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; + case 0x000A: // Hauppauge/TT Nexus-CA rev1.X av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap, 0x7b); if (av7110->fe) { /* set TDA9819 into DVB mode */ - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF) /* tuner on this needs a slower i2c bus speed */ @@ -1940,13 +2079,169 @@ } } +/* Budgetpatch note: + * Original hardware design by Roberto Deza: + * There is a DVB_Wiki at + * http://212.227.36.83/linuxtv/wiki/index.php/Main_Page + * where is described this 'DVB TT Budget Patch', on Card Modding: + * http://212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch + * On the short description there is also a link to a external file, + * with more details: + * http://perso.wanadoo.es/jesussolano/Ttf_tsc1.zip + * + * New software triggering design by Emard that works on + * original Roberto Deza's hardware: + * + * rps1 code for budgetpatch will copy internal HS event to GPIO3 pin. + * GPIO3 is in budget-patch hardware connectd to port B VSYNC + * HS is an internal event of 7146, accessible with RPS + * and temporarily raised high every n lines + * (n in defined in the RPS_THRESH1 counter threshold) + * I think HS is raised high on the beginning of the n-th line + * and remains high until this n-th line that triggered + * it is completely received. When the receiption of n-th line + * ends, HS is lowered. + * + * To transmit data over DMA, 7146 needs changing state at + * port B VSYNC pin. Any changing of port B VSYNC will + * cause some DMA data transfer, with more or less packets loss. + * It depends on the phase and frequency of VSYNC and + * the way of 7146 is instructed to trigger on port B (defined + * in DD1_INIT register, 3rd nibble from the right valid + * numbers are 0-7, see datasheet) + * + * The correct triggering can minimize packet loss, + * dvbtraffic should give this stable bandwidths: + * 22k transponder = 33814 kbit/s + * 27.5k transponder = 38045 kbit/s + * by experiment it is found that the best results + * (stable bandwidths and almost no packet loss) + * are obtained using DD1_INIT triggering number 2 + * (Va at rising edge of VS Fa = HS x VS-failing forced toggle) + * and a VSYNC phase that occurs in the middle of DMA transfer + * (about byte 188*512=96256 in the DMA window). + * + * Phase of HS is still not clear to me how to control, + * It just happens to be so. It can be seen if one enables + * RPS_IRQ and print Event Counter 1 in vpeirq(). Every + * time RPS_INTERRUPT is called, the Event Counter 1 will + * increment. That's how the 7146 is programmed to do event + * counting in this budget-patch.c + * I *think* HPS setting has something to do with the phase + * of HS but I cant be 100% sure in that. + * + * hardware debug note: a working budget card (including budget patch) + * with vpeirq() interrupt setup in mode "0x90" (every 64K) will + * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes + * and that means 3*25=75 Hz of interrupt freqency, as seen by + * watch cat /proc/interrupts + * + * If this frequency is 3x lower (and data received in the DMA + * buffer don't start with 0x47, but in the middle of packets, + * whose lengths appear to be like 188 292 188 104 etc. + * this means VSYNC line is not connected in the hardware. + * (check soldering pcb and pins) + * The same behaviour of missing VSYNC can be duplicated on budget + * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. + */ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext) { struct av7110 *av7110 = NULL; + int length = TS_WIDTH * TS_HEIGHT; int ret = 0; + int count = 0; dprintk(4, "dev: %p\n", dev); + /* Set RPS_IRQ to 1 to track rps1 activity. + * Enabling this won't send any interrupt to PC CPU. + */ +#define RPS_IRQ 0 + + if (budgetpatch == 1) { + budgetpatch = 0; + /* autodetect the presence of budget patch + * this only works if saa7146 has been recently + * reset with with MASK_31 to MC1 + * + * will wait for VBI_B event (vertical blank at port B) + * and will reset GPIO3 after VBI_B is detected. + * (GPIO3 should be raised high by CPU to + * test if GPIO3 will generate vertical blank signal + * in budget patch GPIO3 is connected to VSYNC_B + */ + + /* RESET SAA7146 */ + saa7146_write(dev, MC1, MASK_31); + /* autodetection success seems to be time-dependend after reset */ + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* set vsync_b triggering */ + saa7146_write(dev, DD1_STREAM_B, 0); + /* port B VSYNC at rising edge */ + saa7146_write(dev, DD1_INIT, 0x00000200); + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + saa7146_write(dev, MC2, + 1 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 1 * (MASK_10 | MASK_26) | // b + 0 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 0 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); + + /* start writing RPS1 code from beginning */ + count = 0; + /* Disable RPS1 */ + saa7146_write(dev, MC1, MASK_29); + /* RPS1 timeout disable */ + saa7146_write(dev, RPS_TOV1, 0); + WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B)); + WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); + WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); + WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); +#if RPS_IRQ + /* issue RPS1 interrupt to increment counter */ + WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); +#endif + WRITE_RPS1(cpu_to_le32(CMD_STOP)); + /* Jump to begin of RPS program as safety measure (p37) */ + WRITE_RPS1(cpu_to_le32(CMD_JUMP)); + WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle)); + +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 treshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Enable RPS1, (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); + + mdelay(10); + /* now send VSYNC_B to rps1 by rising GPIO3 */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(10); + /* if rps1 responded by lowering the GPIO3, + * then we have budgetpatch hardware + */ + if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) { + budgetpatch = 1; + printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n"); + } + /* Disable RPS1 */ + saa7146_write(dev, MC1, ( MASK_29 )); +#if RPS_IRQ + printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + } + /* prepare the av7110 device struct */ if (!(av7110 = kmalloc (sizeof (struct av7110), GFP_KERNEL))) { dprintk(1, "out of memory\n"); @@ -1980,6 +2275,7 @@ saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */ if (i2c_add_adapter(&av7110->i2c_adap) < 0) { +err_no_mem: dvb_unregister_adapter (av7110->dvb_adapter); kfree(av7110); return -ENOMEM; @@ -1987,6 +2283,86 @@ ttpci_eeprom_parse_mac(&av7110->i2c_adap, av7110->dvb_adapter->proposed_mac); + if (budgetpatch) { + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable( + dev->pci, length, &av7110->pt); + if (!av7110->grabbing) + goto err_no_mem; + saa7146_write(dev, PCI_BT_V1, 0x1c1f101f); + saa7146_write(dev, BCS_CTRL, 0x80400040); + /* set dd1 stream a & b */ + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_INIT, 0x03000200); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + + /* upload all */ + saa7146_write(dev, MC2, 0x077c077c); + saa7146_write(dev, GPIO_CTRL, 0x000000); +#if RPS_IRQ + /* set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + * use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + * use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + */ + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + /* set event counter 1 treshold to maximum allowed value (rEC p55) */ + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + /* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */ + count = 0; + + /* Wait Source Line Counter Threshold (p36) */ + WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS)); + /* Set GPIO3=1 (p42) */ + WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); + WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); + WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24)); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); +#endif + /* Wait reset Source Line Counter Threshold (p36) */ + WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS)); + /* Set GPIO3=0 (p42) */ + WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); + WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); + WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); +#if RPS_IRQ + /* issue RPS1 interrupt */ + WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); +#endif + /* Jump to begin of RPS program (p37) */ + WRITE_RPS1(cpu_to_le32(CMD_JUMP)); + WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle)); + + /* Fix VSYNC level */ + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + /* Set RPS1 Address register to point to RPS code (r108 p42) */ + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + /* Set Source Line Counter Threshold, using BRS (rCC p43) + * It generates HS event every TS_HEIGHT lines + * this is related to TS_WIDTH set in register + * NUM_LINE_BYTE3. If NUM_LINE_BYTE low 16 bits + * are set to TS_WIDTH bytes (TS_WIDTH=2*188), + * then RPS_THRESH1 should be set to trigger + * every TS_HEIGHT (512) lines. + */ + saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); + + /* Enable RPS1 (rFC p33) */ + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + /* end of budgetpatch register initialization */ + tasklet_init (&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); + } else { saa7146_write(dev, PCI_BT_V1, 0x1c00101f); saa7146_write(dev, BCS_CTRL, 0x80400040); @@ -1998,6 +2374,7 @@ /* upload all */ saa7146_write(dev, MC2, 0x077c077c); saa7146_write(dev, GPIO_CTRL, 0x000000); + } tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110); tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110); @@ -2109,10 +2486,21 @@ struct av7110 *av7110 = (struct av7110*)saa->ext_priv; dprintk(4, "%p\n", av7110); - if( 0 == av7110->device_initialized ) { + if (!av7110->device_initialized ) return 0; - } + if (budgetpatch) { + /* Disable RPS1 */ + saa7146_write(saa, MC1, MASK_29); + /* VSYNC LOW (inactive) */ + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ + SAA7146_IER_DISABLE(saa, MASK_10); + SAA7146_ISR_CLEAR(saa, MASK_10); + msleep(50); + tasklet_kill(&av7110->vpe_tasklet); + saa7146_pgtable_free(saa->pci, &av7110->pt); + } av7110_exit_v4l(av7110); av7110->arm_rmmod=1; @@ -2121,6 +2509,9 @@ while (av7110->arm_thread) msleep(1); + tasklet_kill(&av7110->debi_tasklet); + tasklet_kill(&av7110->gpio_tasklet); + dvb_unregister(av7110); SAA7146_IER_DISABLE(saa, MASK_19 | MASK_03); @@ -2153,13 +2544,43 @@ { struct av7110 *av7110 = dev->ext_priv; - if (*isr & MASK_19) + //print_time("av7110_irq"); + + /* Note: Don't try to handle the DEBI error irq (MASK_18), in + * intel mode the timeout is asserted all the time... + */ + + if (*isr & MASK_19) { + //printk("av7110_irq: DEBI\n"); + /* Note 1: The DEBI irq is level triggered: We must enable it + * only after we started a DMA xfer, and disable it here + * immediately, or it will be signalled all the time while + * DEBI is idle. + * Note 2: You would think that an irq which is masked is + * not signalled by the hardware. Not so for the SAA7146: + * An irq is signalled as long as the corresponding bit + * in the ISR is set, and disabling irqs just prevents the + * hardware from setting the ISR bit. This means a) that we + * must clear the ISR *after* disabling the irq (which is why + * we must do it here even though saa7146_core did it already), + * and b) that if we were to disable an edge triggered irq + * (like the gpio irqs sadly are) temporarily we would likely + * loose some. This sucks :-( + */ + SAA7146_IER_DISABLE(av7110->dev, MASK_19); + SAA7146_ISR_CLEAR(av7110->dev, MASK_19); tasklet_schedule (&av7110->debi_tasklet); + } - if (*isr & MASK_03) + if (*isr & MASK_03) { + //printk("av7110_irq: GPIO\n"); tasklet_schedule (&av7110->gpio_tasklet); } + if ((*isr & MASK_10) && budgetpatch) + tasklet_schedule(&av7110->vpe_tasklet); +} + static struct saa7146_extension av7110_extension; @@ -2173,8 +2594,9 @@ 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(tts_1_3se, "Technotrend/Hauppauge WinTV DVB-S rev1.3 SE"); MAKE_AV7110_INFO(fsc, "Fujitsu Siemens DVB-C"); +MAKE_AV7110_INFO(fss, "Fujitsu Siemens DVB-S rev1.6"); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(tts_1_X, 0x13c2, 0x0000), @@ -2184,10 +2606,10 @@ 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(fss, 0x13c2, 0x0006), /* 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???? @@ -2208,7 +2630,7 @@ .attach = av7110_attach, .detach = av7110_detach, - .irq_mask = MASK_19|MASK_03, + .irq_mask = MASK_19 | MASK_03 | MASK_10, .irq_func = av7110_irq, }; diff -Nru a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h --- a/drivers/media/dvb/ttpci/av7110.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttpci/av7110.h 2005-01-23 21:02:28 -08:00 @@ -115,7 +115,7 @@ int bmpp; int bmplen; - int bmp_state; + volatile int bmp_state; #define BMP_NONE 0 #define BMP_LOADING 1 #define BMP_LOADINGS 2 @@ -157,6 +157,18 @@ struct dmx_frontend hw_frontend; struct dmx_frontend mem_frontend; + + /* for budget mode demux1 */ + struct dmxdev dmxdev1; + struct dvb_demux demux1; + struct dvb_net dvb_net1; + spinlock_t feedlock1; + int feeding1; + u8 tsf; + u32 ttbp; + unsigned char *grabbing; + struct saa7146_pgtable pt; + struct tasklet_struct vpe_tasklet; int fe_synced; struct semaphore pid_mutex; 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttpci/av7110_hw.c 2005-01-23 21:02:28 -08:00 @@ -153,8 +153,10 @@ base = DRAM_START_CODE; for (i = 0; i < blocks; i++) { - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) + if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i); return -1; + } dprintk(4, "writing DRAM block %d\n", i); mwdebi(av7110, DEBISWAB, bootblock, ((char*)data) + i * BOOT_MAX_SIZE, BOOT_MAX_SIZE); @@ -166,8 +168,10 @@ } if (rest > 0) { - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) + if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n"); return -1; + } if (rest > 4) mwdebi(av7110, DEBISWAB, bootblock, ((char*)data) + i * BOOT_MAX_SIZE, rest); @@ -179,12 +183,16 @@ iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, rest, 2); iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); } - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) + if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n"); return -1; + } iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2); iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); - if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) + if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) { + printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n"); return -1; + } return 0; } @@ -261,8 +269,11 @@ mdelay(1); dprintk(1, "load dram code\n"); - if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) + if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " + "load_dram() failed\n"); return -1; + } saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTLO); mdelay(1); @@ -336,7 +347,7 @@ if (!av7110->arm_ready) { dprintk(1, "arm not ready.\n"); - return -1; + return -ENXIO; } start = jiffies; @@ -344,7 +355,7 @@ msleep(1); if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__); - return -1; + return -ETIMEDOUT; } } @@ -356,7 +367,7 @@ msleep(1); if (time_after(jiffies, start + ARM_WAIT_SHAKE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__); - return -1; + return -ETIMEDOUT; } } #endif @@ -375,6 +386,13 @@ flags[0] = OSDQOver; flags[1] = OSDQFull; break; + case COMTYPE_MISC: + if (FW_VERSION(av7110->arm_app) >= 0x261d) { + type = "MSG"; + flags[0] = GPMQOver; + flags[1] = GPMQBusy; + } + break; default: break; } @@ -419,18 +437,18 @@ if (time_after(jiffies, start + ARM_WAIT_FREE)) { printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n", __FUNCTION__); - return -1; + return -ETIMEDOUT; } } stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2); if (stat & GPMQOver) { printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __FUNCTION__); - return -1; + return -ENOSPC; } else if (stat & OSDQOver) { printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __FUNCTION__); - return -1; + return -ENOSPC; } #endif @@ -453,7 +471,8 @@ ret = __av7110_send_fw_cmd(av7110, buf, length); up(&av7110->dcomlock); if (ret) - printk("dvb-ttpci: %s(): av7110_send_fw_cmd error\n", __FUNCTION__); + printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n", + __FUNCTION__, ret); return ret; } @@ -477,7 +496,7 @@ ret = av7110_send_fw_cmd(av7110, buf, num + 2); if (ret) - printk("dvb-ttpci: av7110_fw_cmd error\n"); + printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret); return ret; } @@ -499,7 +518,7 @@ ret = av7110_send_fw_cmd(av7110, cmd, 18); if (ret) - printk("dvb-ttpci: av7110_send_ci_cmd error\n"); + printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret); return ret; } @@ -525,7 +544,7 @@ if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) { up(&av7110->dcomlock); - printk("dvb-ttpci: av7110_fw_request error\n"); + printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err); return err; } @@ -579,7 +598,7 @@ int ret; ret = av7110_fw_request(av7110, &tag, 0, buf, length); if (ret) - printk("dvb-ttpci: av7110_fw_query error\n"); + printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret); return ret; } @@ -626,7 +645,7 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst) { - int i; + int i, ret; u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) + SendDiSEqC), 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -646,8 +665,8 @@ for (i = 0; i < len; i++) buf[i + 4] = msg[i]; - if (av7110_send_fw_cmd(av7110, buf, 18)) - printk("dvb-ttpci: av7110_diseqc_send error\n"); + if ((ret = av7110_send_fw_cmd(av7110, buf, 18))) + printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret); return 0; } @@ -741,7 +760,7 @@ ret = __av7110_send_fw_cmd(av7110, cbuf, 5); up(&av7110->dcomlock); if (ret) - printk("dvb-ttpci: WriteText error\n"); + printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret); return ret; } @@ -808,7 +827,8 @@ ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ); if (ret == -ERESTARTSYS || ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in %s()\n", __FUNCTION__); + printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n", + ret, av7110->bmp_state); av7110->bmp_state = BMP_NONE; return -1; } @@ -850,6 +870,7 @@ } } av7110->bmplen += 1024; + dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen); return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy); } @@ -861,11 +882,13 @@ BUG_ON (av7110->bmp_state == BMP_NONE); - ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ); + ret = wait_event_interruptible_timeout(av7110->bmpq, + av7110->bmp_state != BMP_LOADING, 10*HZ); if (ret == -ERESTARTSYS || ret == 0) { - printk("dvb-ttpci: warning: timeout waiting in %s()\n", __FUNCTION__); + printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n", + ret, av7110->bmp_state); av7110->bmp_state = BMP_NONE; - return -1; + return (ret == 0) ? -ETIMEDOUT : ret; } BUG_ON (av7110->bmp_state != BMP_LOADED); @@ -943,6 +966,7 @@ { uint w, h, bpp, bpl, size, lpb, bnum, brest; int i; + int rc; w = x1 - x0 + 1; h = y1 - y0 + 1; @@ -958,15 +982,23 @@ brest = size - bnum * lpb * bpl; for (i = 0; i < bnum; i++) { - LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], + rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], w, lpb, inc, data); - BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0); + if (rc) + return rc; + rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0); + if (rc) + return rc; data += lpb * inc; } if (brest) { - LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], + rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]], w, brest / bpl, inc, data); - BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0); + if (rc) + return rc; + rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0); + if (rc) + return rc; } ReleaseBitmap(av7110); return 0; @@ -1019,7 +1051,7 @@ goto out; } else { int i, len = dc->x0-dc->color+1; - u8 __user *colors = (u8 __user *)dc->data; + u8 __user *colors = (u8 *)dc->data; u8 r, g, b, blend; for (i = 0; iy1 = dc->y0; /* fall through */ case OSD_SetBlock: - OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); + ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data); goto out; case OSD_FillRow: DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0, 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttpci/av7110_v4l.c 2005-01-23 21:02:28 -08:00 @@ -250,7 +250,7 @@ if (ves1820_writereg(dev, 0x09, 0x0f, 0x20)) dprintk(1, "setting band in demodulator failed.\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) + saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF) } } @@ -591,7 +591,7 @@ if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20)) dprintk(1, "setting band in demodulator failed.\n"); } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { - saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD) + saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF) } 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttpci/budget-core.c 2005-01-23 21:02:28 -08:00 @@ -89,11 +89,18 @@ * Pitch: 188, NumBytes3: 188, NumLines3: 1024 */ - if (budget->card->type == BUDGET_FS_ACTIVY) { + switch(budget->card->type) { + case BUDGET_FS_ACTIVY: saa7146_write(dev, DD1_INIT, 0x04000000); saa7146_write(dev, MC2, (MASK_09 | MASK_25)); saa7146_write(dev, BRS_CTRL, 0x00000000); - } else { + break; + case BUDGET_PATCH: + saa7146_write(dev, DD1_INIT, 0x00000200); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + saa7146_write(dev, BRS_CTRL, 0x60000000); + break; + default: if (budget->video_port == BUDGET_VIDEO_PORTA) { saa7146_write(dev, DD1_INIT, 0x06000200); saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); @@ -122,9 +129,10 @@ } saa7146_write(dev, MC2, (MASK_04 | MASK_20)); - saa7146_write(dev, MC1, (MASK_04 | MASK_20)); // DMA3 on - SAA7146_IER_ENABLE(budget->dev, MASK_10); // VPE + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ + SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ + saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ return ++budget->feeding; } @@ -249,6 +257,7 @@ return -EINVAL; spin_lock(&budget->feedlock); + feed->pusi_seen = 0; /* have a clean section start */ status = start_ts_capture (budget); spin_unlock(&budget->feedlock); return status; 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttpci/budget-patch.c 2005-01-23 21:02:28 -08:00 @@ -41,34 +41,127 @@ static struct saa7146_extension budget_extension; -MAKE_BUDGET_INFO(fs_1_3,"Siemens/Technotrend/Hauppauge PCI rev1.3+Budget_Patch", BUDGET_PATCH); +MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); +//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); static struct pci_device_id pci_tbl[] = { - MAKE_EXTENSION_PCI(fs_1_3,0x13c2, 0x0000), + MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), +// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), { .vendor = 0, } }; -static int budget_wdebi(struct budget_patch *budget, u32 config, int addr, u32 val, int count) +/* those lines are for budget-patch to be tried +** on a true budget card and observe the +** behaviour of VSYNC generated by rps1. +** this code was shamelessly copy/pasted from budget.c +*/ +static void gpio_Set22K (struct budget *budget, int state) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); +} + +/* Diseqc functions only for TT Budget card */ +/* taken from the Skyvision DVB driver by + Ralph Metzler */ + +static void DiseqcSendBit (struct budget *budget, int data) +{ + struct saa7146_dev *dev=budget->dev; + dprintk(2, "budget: %p\n", budget); + + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + udelay(data ? 500 : 1000); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + udelay(data ? 1000 : 500); +} + +static void DiseqcSendByte (struct budget *budget, int data) +{ + int i, par=1, d; + + dprintk(2, "budget: %p\n", budget); + + for (i=7; i>=0; i--) { + d = (data>>i)&1; + par ^= d; + DiseqcSendBit(budget, d); + } + + DiseqcSendBit(budget, par); +} + +static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) { struct saa7146_dev *dev=budget->dev; + int i; dprintk(2, "budget: %p\n", budget); - if (count <= 0 || count > 4) - return -1; + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + mdelay(16); + + for (i=0; idvb->priv; + + switch (tone) { + case SEC_TONE_ON: + gpio_Set22K (budget, 1); + break; + + case SEC_TONE_OFF: + gpio_Set22K (budget, 0); + break; + + default: + return -EINVAL; + } + + return 0; +} - saa7146_write(dev, DEBI_CONFIG, config); +static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct budget* budget = (struct budget*) fe->dvb->priv; - saa7146_write(dev, DEBI_AD, val ); - saa7146_write(dev, DEBI_COMMAND, (count << 17) | (addr & 0xffff)); - saa7146_write(dev, MC2, (2 << 16) | 2); - mdelay(5); + SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); return 0; } +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 budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length) { @@ -77,14 +170,17 @@ dprintk(2, "budget: %p\n", budget); for (i = 2; i < length; i++) - budget_wdebi(budget, DEBINOSWAP, COMMAND + 2*i, (u32) buf[i], 2); - + { + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0); + msleep(5); + } if (length) - budget_wdebi(budget, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2); + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0); else - budget_wdebi(budget, DEBINOSWAP, COMMAND + 2, 0, 2); - - budget_wdebi(budget, DEBINOSWAP, COMMAND, (u32) buf[0], 2); + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0); + msleep(5); + ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0); + msleep(5); return 0; } @@ -319,6 +415,7 @@ { switch(budget->dev->pci->subsystem_device) { case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X + case 0x1013: // SATELCO Multimedia PCI // try the ALPS BSRV2 first of all budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap); @@ -332,18 +429,18 @@ // 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; + 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 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; + 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; @@ -365,23 +462,120 @@ } } +/* written by Emard */ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) { struct budget_patch *budget; int err; int count = 0; + int detected = 0; - if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) - return -ENOMEM; +#define PATCH_RESET 0 +#define RPS_IRQ 0 +#define HPS_SETUP 0 +#if PATCH_RESET + saa7146_write(dev, MC1, MASK_31); + msleep(40); +#endif +#if HPS_SETUP + // initialize registers. Better to have it like this + // than leaving something unconfigured + saa7146_write(dev, DD1_STREAM_B, 0); + // port B VSYNC at rising edge + saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too! + saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI + + // debi config + // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18); + + // zero all HPS registers + saa7146_write(dev, HPS_H_PRESCALE, 0); // r68 + saa7146_write(dev, HPS_H_SCALE, 0); // r6c + saa7146_write(dev, BCS_CTRL, 0); // r70 + saa7146_write(dev, HPS_V_SCALE, 0); // r60 + saa7146_write(dev, HPS_V_GAIN, 0); // r64 + saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74 + saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78 + // Set HPS prescaler for port B input + saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) ); + saa7146_write(dev, MC2, + 0 * (MASK_08 | MASK_24) | // BRS control + 0 * (MASK_09 | MASK_25) | // a + 0 * (MASK_10 | MASK_26) | // b + 1 * (MASK_06 | MASK_22) | // HPS_CTRL1 + 1 * (MASK_05 | MASK_21) | // HPS_CTRL2 + 0 * (MASK_01 | MASK_15) // DEBI + ); +#endif + // Disable RPS1 and RPS0 + saa7146_write(dev, MC1, ( MASK_29 | MASK_28)); + // RPS1 timeout disable + saa7146_write(dev, RPS_TOV1, 0); + + // code for autodetection + // will wait for VBI_B event (vertical blank at port B) + // and will reset GPIO3 after VBI_B is detected. + // (GPIO3 should be raised high by CPU to + // test if GPIO3 will generate vertical blank signal + // in budget patch GPIO3 is connected to VSYNC_B + count = 0; +#if 0 + WRITE_RPS1(cpu_to_le32(CMD_UPLOAD | + MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 )); +#endif + WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_VBI_B)); + WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); + WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); + WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); +#if RPS_IRQ + // issue RPS1 interrupt to increment counter + WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); + // at least a NOP is neede between two interrupts + WRITE_RPS1(cpu_to_le32(CMD_NOP)); + // interrupt again + WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); +#endif + WRITE_RPS1(cpu_to_le32(CMD_STOP)); + +#if RPS_IRQ + // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) + // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled + // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called + saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); + // set event counter 1 treshold to maximum allowed value (rEC p55) + saa7146_write(dev, ECT1R, 0x3fff ); +#endif + // Fix VSYNC level + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); + // Set RPS1 Address register to point to RPS code (r108 p42) + saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); + // Enable RPS1, (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); - dprintk(2, "budget: %p\n", budget); - if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { - kfree (budget); - return err; - } + mdelay(50); + saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); + mdelay(150); + + + if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) + detected = 1; + +#if RPS_IRQ + printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); +#endif + // Disable RPS1 + saa7146_write(dev, MC1, ( MASK_29 )); + + if(detected == 0) + printk("budget-patch not detected or saa7146 in non-default state.\n" + "try enabling ressetting of 7146 with MASK_31 in MC1 register\n"); + + else + printk("BUDGET-PATCH DETECTED.\n"); + -/* +/* OLD (Original design by Roberto Deza): ** This code will setup the SAA7146_RPS1 to generate a square ** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of ** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; @@ -393,24 +587,85 @@ ** which seems that can be done perfectly without this :-)). */ +/* New design (By Emard) +** this rps1 code will copy internal HS event to GPIO3 pin. +** GPIO3 is in budget-patch hardware connectd to port B VSYNC + +** HS is an internal event of 7146, accessible with RPS +** and temporarily raised high every n lines +** (n in defined in the RPS_THRESH1 counter threshold) +** I think HS is raised high on the beginning of the n-th line +** and remains high until this n-th line that triggered +** it is completely received. When the receiption of n-th line +** ends, HS is lowered. + +** To transmit data over DMA, 7146 needs changing state at +** port B VSYNC pin. Any changing of port B VSYNC will +** cause some DMA data transfer, with more or less packets loss. +** It depends on the phase and frequency of VSYNC and +** the way of 7146 is instructed to trigger on port B (defined +** in DD1_INIT register, 3rd nibble from the right valid +** numbers are 0-7, see datasheet) +** +** The correct triggering can minimize packet loss, +** dvbtraffic should give this stable bandwidths: +** 22k transponder = 33814 kbit/s +** 27.5k transponder = 38045 kbit/s +** by experiment it is found that the best results +** (stable bandwidths and almost no packet loss) +** are obtained using DD1_INIT triggering number 2 +** (Va at rising edge of VS Fa = HS x VS-failing forced toggle) +** and a VSYNC phase that occurs in the middle of DMA transfer +** (about byte 188*512=96256 in the DMA window). +** +** Phase of HS is still not clear to me how to control, +** It just happens to be so. It can be seen if one enables +** RPS_IRQ and print Event Counter 1 in vpeirq(). Every +** time RPS_INTERRUPT is called, the Event Counter 1 will +** increment. That's how the 7146 is programmed to do event +** counting in this budget-patch.c +** I *think* HPS setting has something to do with the phase +** of HS but I cant be 100% sure in that. + +** hardware debug note: a working budget card (including budget patch) +** with vpeirq() interrupt setup in mode "0x90" (every 64K) will +** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes +** and that means 3*25=75 Hz of interrupt freqency, as seen by +** watch cat /proc/interrupts +** +** If this frequency is 3x lower (and data received in the DMA +** buffer don't start with 0x47, but in the middle of packets, +** whose lengths appear to be like 188 292 188 104 etc. +** this means VSYNC line is not connected in the hardware. +** (check soldering pcb and pins) +** The same behaviour of missing VSYNC can be duplicated on budget +** cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. +*/ + // Setup RPS1 "program" (p35) + count = 0; + - // Wait reset Source Line Counter Threshold (p36) - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS)); // Wait Source Line Counter Threshold (p36) WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS)); // Set GPIO3=1 (p42) WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTHI<<24)); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); +#endif // Wait reset Source Line Counter Threshold (p36) WRITE_RPS1(cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS)); - // Wait Source Line Counter Threshold - WRITE_RPS1(cpu_to_le32(CMD_PAUSE | EVT_HS)); // Set GPIO3=0 (p42) WRITE_RPS1(cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2))); WRITE_RPS1(cpu_to_le32(GPIO3_MSK)); WRITE_RPS1(cpu_to_le32(SAA7146_GPIO_OUTLO<<24)); +#if RPS_IRQ + // issue RPS1 interrupt + WRITE_RPS1(cpu_to_le32(CMD_INTERRUPT)); +#endif // Jump to begin of RPS program (p37) WRITE_RPS1(cpu_to_le32(CMD_JUMP)); WRITE_RPS1(cpu_to_le32(dev->d_rps1.dma_handle)); @@ -420,9 +675,30 @@ // Set RPS1 Address register to point to RPS code (r108 p42) saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); // Set Source Line Counter Threshold, using BRS (rCC p43) - saa7146_write(dev, RPS_THRESH1, ((TS_HEIGHT/2) | MASK_12)); + // It generates HS event every TS_HEIGHT lines + // this is related to TS_WIDTH set in register + // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE + // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 + //,then RPS_THRESH1 + // should be set to trigger every TS_HEIGHT (512) lines. + // + saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); + + // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); // Enable RPS1 (rFC p33) saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + + + if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) + return -ENOMEM; + + dprintk(2, "budget: %p\n", budget); + + if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) { + kfree (budget); + return err; + } + dev->ext_priv = budget; diff -Nru a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c --- a/drivers/media/dvb/ttpci/budget.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttpci/budget.c 2005-01-23 21:02:28 -08:00 @@ -414,7 +414,7 @@ { switch(budget->dev->pci->subsystem_device) { case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) - + case 0x1013: // try the ALPS BSRV2 first of all budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap); if (budget->dvb_frontend) { @@ -522,14 +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); UNDEFINED HARDWARE - mail linuxtv.org list */ +MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); MAKE_BUDGET_INFO(fsacs, "Fujitsu Siemens Activy Budget-S PCI", BUDGET_FS_ACTIVY); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), -/* MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), UNDEFINED HARDWARE */ + MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), MAKE_EXTENSION_PCI(fsacs, 0x1131, 0x4f61), { .vendor = 0, 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 2005-01-23 21:02:28 -08:00 +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c 2005-01-23 21:02:28 -08:00 @@ -756,7 +756,7 @@ if (!dec->iso_stream_count) { for (i = 0; i < ISO_BUF_COUNT; i++) - usb_unlink_urb(dec->iso_urb[i]); + usb_kill_urb(dec->iso_urb[i]); } up(&dec->iso_sem); @@ -821,7 +821,7 @@ "error %d\n", __FUNCTION__, i, result); while (i) { - usb_unlink_urb(dec->iso_urb[i - 1]); + usb_kill_urb(dec->iso_urb[i - 1]); i--; } @@ -1379,7 +1379,7 @@ dec->iso_stream_count = 0; for (i = 0; i < ISO_BUF_COUNT; i++) - usb_unlink_urb(dec->iso_urb[i]); + usb_kill_urb(dec->iso_urb[i]); ttusb_dec_free_iso_urbs(dec); } diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h --- a/drivers/net/e1000/e1000.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/net/e1000/e1000.h 2005-01-23 21:02:28 -08:00 @@ -209,6 +209,7 @@ /* TX */ struct e1000_desc_ring tx_ring; + spinlock_t tx_lock; uint32_t txd_cmd; uint32_t tx_int_delay; uint32_t tx_abs_int_delay; diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/net/e1000/e1000_main.c 2005-01-23 21:02:28 -08:00 @@ -291,9 +291,7 @@ e1000_phy_reset(&adapter->hw); } - spin_lock_irq(&netdev->xmit_lock); e1000_set_multi(netdev); - spin_unlock_irq(&netdev->xmit_lock); e1000_restore_vlan(adapter); @@ -522,6 +520,9 @@ if(pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; + /* hard_start_xmit is safe against parallel locking */ + netdev->features |= NETIF_F_LLTX; + /* before reading the EEPROM, reset the controller to * put the device in a known good starting state */ @@ -731,6 +732,7 @@ atomic_set(&adapter->irq_sem, 1); spin_lock_init(&adapter->stats_lock); + spin_lock_init(&adapter->tx_lock); return 0; } @@ -1291,8 +1293,6 @@ * list or the network interface flags are updated. This routine is * responsible for configuring the hardware for proper multicast, * promiscuous mode, and all-multi behavior. - * - * Called with netdev->xmit_lock held and IRQs disabled. **/ static void @@ -1304,9 +1304,12 @@ uint32_t rctl; uint32_t hash_value; int i; + unsigned long flags; /* Check for Promiscuous and All Multicast modes */ + spin_lock_irqsave(&adapter->tx_lock, flags); + rctl = E1000_READ_REG(hw, RCTL); if(netdev->flags & IFF_PROMISC) { @@ -1355,6 +1358,8 @@ if(hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); + + spin_unlock_irqrestore(&adapter->tx_lock, flags); } /* Need to wait a few seconds after link up to get diagnostic information from @@ -1781,8 +1786,6 @@ } #define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) - -/* Called with dev->xmit_lock held and interrupts disabled. */ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { @@ -1791,6 +1794,7 @@ unsigned int max_txd_pwr = E1000_MAX_TXD_PWR; unsigned int tx_flags = 0; unsigned int len = skb->len; + unsigned long flags; unsigned int nr_frags = 0; unsigned int mss = 0; int count = 0; @@ -1834,10 +1838,18 @@ if(adapter->pcix_82544) count += nr_frags; + local_irq_save(flags); + if (!spin_trylock(&adapter->tx_lock)) { + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + /* need: count + 2 desc gap to keep tail from touching * head, otherwise try next time */ if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) { netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_BUSY; } @@ -1845,6 +1857,7 @@ if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); + spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_BUSY; } } @@ -1871,6 +1884,7 @@ if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < MAX_SKB_FRAGS + 2)) netif_stop_queue(netdev); + spin_unlock_irqrestore(&adapter->tx_lock, flags); return NETDEV_TX_OK; } @@ -2220,13 +2234,13 @@ tx_ring->next_to_clean = i; - spin_lock(&netdev->xmit_lock); + spin_lock(&adapter->tx_lock); if(unlikely(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))) netif_wake_queue(netdev); - spin_unlock(&netdev->xmit_lock); + spin_unlock(&adapter->tx_lock); return cleaned; } @@ -2805,10 +2819,7 @@ if(wufc) { e1000_setup_rctl(adapter); - - spin_lock_irq(&netdev->xmit_lock); e1000_set_multi(netdev); - spin_unlock_irq(&netdev->xmit_lock); /* turn on all-multi mode if wake on multicast is enabled */ if(adapter->wol & E1000_WUFC_MC) { diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c --- a/drivers/net/sungem.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/net/sungem.c 2005-01-23 21:02:28 -08:00 @@ -835,9 +835,9 @@ } /* Run TX completion thread */ - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_tx(dev, gp, gp->status); - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); @@ -932,12 +932,12 @@ readl(gp->regs + MAC_RXCFG)); spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); gp->reset_task_pending = 2; schedule_work(&gp->reset_task); - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } @@ -955,6 +955,7 @@ struct gem *gp = dev->priv; int entry; u64 ctrl; + unsigned long flags; ctrl = 0; if (skb->ip_summed == CHECKSUM_HW) { @@ -968,9 +969,17 @@ (csum_stuff_off << 21)); } + local_irq_save(flags); + if (!spin_trylock(&gp->tx_lock)) { + /* Tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + /* This is a hard error, log it. */ if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); + spin_unlock_irqrestore(&gp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); return NETDEV_TX_BUSY; @@ -1057,6 +1066,7 @@ dev->name, entry, skb->len); mb(); writel(gp->tx_new, gp->regs + TXDMA_KICK); + spin_unlock_irqrestore(&gp->tx_lock, flags); dev->trans_start = jiffies; @@ -1087,11 +1097,11 @@ } spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); dev->mtu = new_mtu; gp->reset_task_pending = 1; schedule_work(&gp->reset_task); - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); flush_scheduled_work(); @@ -1101,7 +1111,7 @@ #define STOP_TRIES 32 -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_stop(struct gem *gp) { int limit; @@ -1127,7 +1137,7 @@ printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name); } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_start_dma(struct gem *gp) { unsigned long val; @@ -1152,7 +1162,7 @@ } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ // XXX dbl check what that function should do when called on PCS PHY static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) { @@ -1239,7 +1249,7 @@ /* A link-up condition has occurred, initialize and enable the * rest of the chip. * - * Must be invoked under gp->lock and dev->xmit_lock. + * Must be invoked under gp->lock and gp->tx_lock. */ static int gem_set_link_modes(struct gem *gp) { @@ -1346,7 +1356,7 @@ return 0; } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static int gem_mdio_link_not_up(struct gem *gp) { switch (gp->lstate) { @@ -1404,7 +1414,7 @@ netif_poll_disable(gp->dev); spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); if (gp->hw_running && gp->opened) { netif_stop_queue(gp->dev); @@ -1420,7 +1430,7 @@ } gp->reset_task_pending = 0; - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); netif_poll_enable(gp->dev); } @@ -1434,7 +1444,7 @@ return; spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); /* If the link of task is still pending, we just * reschedule the link timer @@ -1504,11 +1514,11 @@ restart: mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); out_unlock: - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_clean_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1559,7 +1569,7 @@ } } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1609,7 +1619,7 @@ wmb(); } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_phy(struct gem *gp) { u32 mifcfg; @@ -1747,7 +1757,7 @@ } } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_dma(struct gem *gp) { u64 desc_dma = (u64) gp->gblock_dvma; @@ -1785,7 +1795,7 @@ gp->regs + RXDMA_BLANK); } -/* Must be invoked under dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static u32 gem_setup_multicast(struct gem *gp) { @@ -1828,7 +1838,7 @@ return rxcfg; } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_mac(struct gem *gp) { unsigned char *e = &gp->dev->dev_addr[0]; @@ -1906,7 +1916,7 @@ writel(0xffffffff, gp->regs + MAC_MCMASK); } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_pause_thresholds(struct gem *gp) { u32 cfg; @@ -2042,7 +2052,7 @@ return 0; } -/* Must be invoked under gp->lock and dev->xmit_lock. */ +/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_hw(struct gem *gp, int restart_link) { /* On Apple's gmac, I initialize the PHY only after @@ -2140,11 +2150,11 @@ if (!gp->wake_on_lan) { spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_stop(gp); writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); } @@ -2192,9 +2202,9 @@ unsigned long flags; spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_stop(gp); - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irqrestore(&gp->lock, flags); } } @@ -2255,9 +2265,9 @@ /* Reset the chip */ spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_stop(gp); - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); gp->hw_running = 1; @@ -2271,7 +2281,7 @@ printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); #ifdef CONFIG_PPC_PMAC if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerdown(gp); @@ -2280,14 +2290,14 @@ gp->pm_timer.expires = jiffies + 10*HZ; add_timer(&gp->pm_timer); up(&gp->pm_sem); - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return -EAGAIN; } spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); /* Allocate & setup ring buffers */ gem_init_rings(gp); @@ -2297,7 +2307,7 @@ gp->opened = 1; - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); up(&gp->pm_sem); @@ -2318,7 +2328,7 @@ /* Stop traffic, mark us closed */ spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); gp->opened = 0; @@ -2333,7 +2343,7 @@ /* Bye, the pm timer will finish the job */ free_irq(gp->pdev->irq, (void *) dev); - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); /* Fire the PM timer that will shut us down in about 10 seconds */ @@ -2364,7 +2374,7 @@ /* If the driver is opened, we stop the DMA */ if (gp->opened) { spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); /* Stop traffic, mark us closed */ netif_device_detach(dev); @@ -2375,7 +2385,7 @@ /* Get rid of ring buffers */ gem_clean_rings(gp); - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) @@ -2409,14 +2419,14 @@ } #endif /* CONFIG_PPC_PMAC */ spin_lock_irq(&gp->lock); - spin_lock(&gp->dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_stop(gp); gp->hw_running = 1; gem_init_rings(gp); gem_init_hw(gp, 1); - spin_unlock(&gp->dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); netif_device_attach(dev); @@ -2437,7 +2447,7 @@ struct net_device_stats *stats = &gp->net_stats; spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); if (gp->hw_running) { stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR); @@ -2457,13 +2467,12 @@ writel(0, gp->regs + MAC_LCOLL); } - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return &gp->net_stats; } -/* Called with dev->xmit_lock held and IRQs disabled. */ static void gem_set_multicast(struct net_device *dev) { struct gem *gp = dev->priv; @@ -2473,6 +2482,9 @@ if (!gp->hw_running) return; + spin_lock_irq(&gp->lock); + spin_lock(&gp->tx_lock); + netif_stop_queue(dev); rxcfg = readl(gp->regs + MAC_RXCFG); @@ -2495,6 +2507,9 @@ writel(rxcfg, gp->regs + MAC_RXCFG); netif_wake_queue(dev); + + spin_unlock(&gp->tx_lock); + spin_unlock_irq(&gp->lock); } static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) @@ -2525,7 +2540,7 @@ /* Return current PHY settings */ spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); cmd->autoneg = gp->want_autoneg; cmd->speed = gp->phy_mii.speed; cmd->duplex = gp->phy_mii.duplex; @@ -2537,7 +2552,7 @@ */ if (cmd->advertising == 0) cmd->advertising = cmd->supported; - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); } else { // XXX PCS ? cmd->supported = @@ -2577,9 +2592,9 @@ /* Apply settings and restart link process. */ spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, cmd); - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2594,9 +2609,9 @@ /* Restart link process. */ spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_begin_auto_negotiation(gp, NULL); - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); return 0; @@ -2848,6 +2863,7 @@ gp->msg_enable = DEFAULT_MSG; spin_lock_init(&gp->lock); + spin_lock_init(&gp->tx_lock); init_MUTEX(&gp->pm_sem); init_timer(&gp->link_timer); @@ -2883,9 +2899,9 @@ gem_apple_powerup(gp); #endif spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); gem_stop(gp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); /* Fill up the mii_phy structure (even if we won't use it) */ @@ -2951,11 +2967,11 @@ /* Detect & init PHY, start autoneg */ spin_lock_irq(&gp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&gp->tx_lock); gp->hw_running = 1; gem_init_phy(gp); gem_begin_auto_negotiation(gp, NULL); - spin_unlock(&dev->xmit_lock); + spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); if (gp->phy_type == phy_mii_mdio0 || @@ -2966,7 +2982,7 @@ pci_set_drvdata(pdev, dev); /* GEM can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX; if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; diff -Nru a/drivers/net/sungem.h b/drivers/net/sungem.h --- a/drivers/net/sungem.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/net/sungem.h 2005-01-23 21:02:28 -08:00 @@ -953,6 +953,7 @@ struct gem { spinlock_t lock; + spinlock_t tx_lock; void __iomem *regs; int rx_new, rx_old; int tx_new, tx_old; diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/net/tg3.c 2005-01-23 21:02:28 -08:00 @@ -60,8 +60,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.16" -#define DRV_MODULE_RELDATE "January 17, 2005" +#define DRV_MODULE_VERSION "3.17" +#define DRV_MODULE_RELDATE "January 22, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -2816,9 +2816,9 @@ /* run TX completion thread */ if (sblk->idx[0].tx_consumer != tp->tx_cons) { - spin_lock(&netdev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_tx(tp); - spin_unlock(&netdev->xmit_lock); + spin_unlock(&tp->tx_lock); } spin_unlock_irqrestore(&tp->lock, flags); @@ -2939,7 +2939,7 @@ tg3_netif_stop(tp); spin_lock_irq(&tp->lock); - spin_lock(&tp->dev->xmit_lock); + spin_lock(&tp->tx_lock); restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; @@ -2949,7 +2949,7 @@ tg3_netif_start(tp); - spin_unlock(&tp->dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); if (restart_timer) @@ -3048,7 +3048,6 @@ (base + len + 8 < base)); } -/* dev->xmit_lock is held and IRQs are disabled. */ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); @@ -3056,12 +3055,39 @@ unsigned int i; u32 len, entry, base_flags, mss; int would_hit_hwbug; + unsigned long flags; len = skb_headlen(skb); + /* No BH disabling for tx_lock here. We are running in BH disabled + * context and TX reclaim runs via tp->poll inside of a software + * interrupt. Rejoice! + * + * Actually, things are not so simple. If we are to take a hw + * IRQ here, we can deadlock, consider: + * + * CPU1 CPU2 + * tg3_start_xmit + * take tp->tx_lock + * tg3_timer + * take tp->lock + * tg3_interrupt + * spin on tp->lock + * spin on tp->tx_lock + * + * So we really do need to disable interrupts when taking + * tx_lock here. + */ + local_irq_save(flags); + if (!spin_trylock(&tp->tx_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + /* This is a hard error, log it. */ if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { netif_stop_queue(dev); + spin_unlock_irqrestore(&tp->tx_lock, flags); printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n", dev->name); return NETDEV_TX_BUSY; @@ -3198,7 +3224,7 @@ entry, len, last_plus_one, &start, mss)) - goto out; + goto out_unlock; entry = start; } @@ -3210,8 +3236,9 @@ if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) netif_stop_queue(dev); -out: +out_unlock: mmiowb(); + spin_unlock_irqrestore(&tp->tx_lock, flags); dev->trans_start = jiffies; @@ -3246,7 +3273,7 @@ tg3_netif_stop(tp); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_halt(tp); @@ -3256,7 +3283,7 @@ tg3_netif_start(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); return 0; @@ -5547,7 +5574,7 @@ unsigned long flags; spin_lock_irqsave(&tp->lock, flags); - spin_lock(&tp->dev->xmit_lock); + spin_lock(&tp->tx_lock); /* All of this garbage is because when using non-tagged * IRQ status the mailbox/status_block protocol the chip @@ -5563,7 +5590,7 @@ if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER; - spin_unlock(&tp->dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irqrestore(&tp->lock, flags); schedule_work(&tp->reset_task); return; @@ -5632,7 +5659,7 @@ tp->asf_counter = tp->asf_multiplier; } - spin_unlock(&tp->dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irqrestore(&tp->lock, flags); tp->timer.expires = jiffies + tp->timer_offset; @@ -5645,12 +5672,12 @@ int err; spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_disable_ints(tp); tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); /* The placement of this call is tied @@ -5669,7 +5696,7 @@ } spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); err = tg3_init_hw(tp); if (err) { @@ -5689,7 +5716,7 @@ tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; } - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); if (err) { @@ -5699,11 +5726,11 @@ } spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_enable_ints(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); netif_start_queue(dev); @@ -5951,7 +5978,7 @@ del_timer_sync(&tp->timer); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); #if 0 tg3_dump_state(tp); #endif @@ -5965,7 +5992,7 @@ TG3_FLAG_GOT_SERDES_FLOWCTL); netif_carrier_off(tp->dev); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); free_irq(dev->irq, dev); @@ -6264,10 +6291,15 @@ } } -/* Called with dev->xmit_lock held and IRQs disabled. */ static void tg3_set_rx_mode(struct net_device *dev) { + struct tg3 *tp = netdev_priv(dev); + + spin_lock_irq(&tp->lock); + spin_lock(&tp->tx_lock); __tg3_set_rx_mode(dev); + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); } #define TG3_REGDUMP_LEN (32 * 1024) @@ -6290,7 +6322,7 @@ memset(p, 0, TG3_REGDUMP_LEN); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); #define __GET_REG32(reg) (*(p)++ = tr32(reg)) #define GET_REG32_LOOP(base,len) \ @@ -6340,17 +6372,19 @@ #undef GET_REG32_LOOP #undef GET_REG32_1 - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } static int tg3_get_eeprom_len(struct net_device *dev) { - return EEPROM_CHIP_SIZE; + struct tg3 *tp = netdev_priv(dev); + + return tp->nvram_size; } -static int tg3_nvram_read_using_eeprom(struct tg3 *tp, - u32 offset, u32 *val); +static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val); + static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct tg3 *tp = netdev_priv(dev); @@ -6362,10 +6396,7 @@ len = eeprom->len; eeprom->len = 0; - ret = tg3_nvram_read_using_eeprom(tp, 0, &eeprom->magic); - if (ret) - return ret; - eeprom->magic = swab32(eeprom->magic); + eeprom->magic = TG3_EEPROM_MAGIC; if (offset & 3) { /* adjustments to start on required 4 byte boundary */ @@ -6375,9 +6406,10 @@ /* i.e. offset=1 len=2 */ b_count = len; } - ret = tg3_nvram_read_using_eeprom(tp, offset-b_offset, &val); + ret = tg3_nvram_read(tp, offset-b_offset, &val); if (ret) return ret; + val = cpu_to_le32(val); memcpy(data, ((char*)&val) + b_offset, b_count); len -= b_count; offset += b_count; @@ -6387,12 +6419,13 @@ /* read bytes upto the last 4 byte boundary */ pd = &data[eeprom->len]; for (i = 0; i < (len - (len & 3)); i += 4) { - ret = tg3_nvram_read_using_eeprom(tp, offset + i, - (u32*)(pd + i)); + ret = tg3_nvram_read(tp, offset + i, &val); if (ret) { eeprom->len += i; return ret; } + val = cpu_to_le32(val); + memcpy(pd + i, &val, 4); } eeprom->len += i; @@ -6401,15 +6434,72 @@ pd = &data[eeprom->len]; b_count = len & 3; b_offset = offset + len - b_count; - ret = tg3_nvram_read_using_eeprom(tp, b_offset, &val); + ret = tg3_nvram_read(tp, b_offset, &val); if (ret) return ret; + val = cpu_to_le32(val); memcpy(pd, ((char*)&val), b_count); eeprom->len += b_count; } return 0; } +static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf); + +static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) +{ + struct tg3 *tp = netdev_priv(dev); + int ret; + u32 offset, len, b_offset, odd_len, start, end; + u8 *buf; + + if (eeprom->magic != TG3_EEPROM_MAGIC) + return -EINVAL; + + offset = eeprom->offset; + len = eeprom->len; + + if ((b_offset = (offset & 3))) { + /* adjustments to start on required 4 byte boundary */ + ret = tg3_nvram_read(tp, offset-b_offset, &start); + if (ret) + return ret; + start = cpu_to_le32(start); + len += b_offset; + offset &= ~3; + } + + odd_len = 0; + if ((len & 3) && ((len > 4) || (b_offset == 0))) { + /* adjustments to end on required 4 byte boundary */ + odd_len = 1; + len = (len + 3) & ~3; + ret = tg3_nvram_read(tp, offset+len-4, &end); + if (ret) + return ret; + end = cpu_to_le32(end); + } + + buf = data; + if (b_offset || odd_len) { + buf = kmalloc(len, GFP_KERNEL); + if (buf == 0) + return -ENOMEM; + if (b_offset) + memcpy(buf, &start, 4); + if (odd_len) + memcpy(buf+len-4, &end, 4); + memcpy(buf + b_offset, data, eeprom->len); + } + + ret = tg3_nvram_write_block(tp, offset, len, buf); + + if (buf != data) + kfree(buf); + + return ret; +} + static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct tg3 *tp = netdev_priv(dev); @@ -6464,7 +6554,7 @@ } spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tp->link_config.autoneg = cmd->autoneg; if (cmd->autoneg == AUTONEG_ENABLE) { @@ -6478,7 +6568,7 @@ } tg3_setup_phy(tp, 1); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); return 0; @@ -6595,7 +6685,7 @@ tg3_netif_stop(tp); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tp->rx_pending = ering->rx_pending; @@ -6608,7 +6698,7 @@ tg3_halt(tp); tg3_init_hw(tp); tg3_netif_start(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); return 0; @@ -6629,7 +6719,7 @@ tg3_netif_stop(tp); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); if (epause->autoneg) tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; else @@ -6645,7 +6735,7 @@ tg3_halt(tp); tg3_init_hw(tp); tg3_netif_start(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); return 0; @@ -6771,14 +6861,14 @@ struct tg3 *tp = netdev_priv(dev); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tp->vlgrp = grp; /* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */ __tg3_set_rx_mode(dev); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } @@ -6787,10 +6877,10 @@ struct tg3 *tp = netdev_priv(dev); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); if (tp->vlgrp) tp->vlgrp->vlan_devices[vid] = NULL; - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } #endif @@ -6809,6 +6899,7 @@ .get_link = ethtool_op_get_link, .get_eeprom_len = tg3_get_eeprom_len, .get_eeprom = tg3_get_eeprom, + .set_eeprom = tg3_set_eeprom, .get_ringparam = tg3_get_ringparam, .set_ringparam = tg3_set_ringparam, .get_pauseparam = tg3_get_pauseparam, @@ -6828,6 +6919,103 @@ .get_ethtool_stats = tg3_get_ethtool_stats, }; +static void __devinit tg3_get_eeprom_size(struct tg3 *tp) +{ + u32 cursize, val; + + tp->nvram_size = EEPROM_CHIP_SIZE; + + if (tg3_nvram_read(tp, 0, &val) != 0) + return; + + if (swab32(val) != TG3_EEPROM_MAGIC) + return; + + /* + * Size the chip by reading offsets at increasing powers of two. + * When we encounter our validation signature, we know the addressing + * has wrapped around, and thus have our chip size. + */ + cursize = 0x800; + + while (cursize < tp->nvram_size) { + if (tg3_nvram_read(tp, cursize, &val) != 0) + return; + + if (swab32(val) == TG3_EEPROM_MAGIC) + break; + + cursize <<= 1; + } + + tp->nvram_size = cursize; +} + +static void __devinit tg3_get_nvram_size(struct tg3 *tp) +{ + u32 val; + + if (tg3_nvram_read(tp, 0xf0, &val) == 0) { + if (val != 0) { + tp->nvram_size = (val >> 16) * 1024; + return; + } + } + tp->nvram_size = 0x20000; +} + +static void __devinit tg3_get_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) { + tp->tg3_flags2 |= TG3_FLG2_FLASH; + } + else { + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + } + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) { + case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE; + break; + case FLASH_VENDOR_ATMEL_EEPROM: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_ST: + tp->nvram_jedecnum = JEDEC_ST; + tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + break; + case FLASH_VENDOR_SAIFUN: + tp->nvram_jedecnum = JEDEC_SAIFUN; + tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE; + break; + case FLASH_VENDOR_SST_SMALL: + case FLASH_VENDOR_SST_LARGE: + tp->nvram_jedecnum = JEDEC_SST; + tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE; + break; + } + } + else { + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + } +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -6852,32 +7040,27 @@ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { - u32 nvcfg1; + tp->tg3_flags |= TG3_FLAG_NVRAM; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { u32 nvaccess = tr32(NVRAM_ACCESS); - tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); + tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); } - nvcfg1 = tr32(NVRAM_CFG1); - - tp->tg3_flags |= TG3_FLAG_NVRAM; - if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) { - if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE) - tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; - } else { - nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; - tw32(NVRAM_CFG1, nvcfg1); - } + tg3_get_nvram_info(tp); + tg3_get_nvram_size(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { u32 nvaccess = tr32(NVRAM_ACCESS); - tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); + tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); } + } else { tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED); + + tg3_get_eeprom_size(tp); } } @@ -6915,11 +7098,30 @@ return 0; } -static int __devinit tg3_nvram_read(struct tg3 *tp, - u32 offset, u32 *val) +#define NVRAM_CMD_TIMEOUT 10000 + +static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd) { int i; + tw32(NVRAM_CMD, nvram_cmd); + for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) { + udelay(10); + if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) { + udelay(10); + break; + } + } + if (i == NVRAM_CMD_TIMEOUT) { + return -EBUSY; + } + return 0; +} + +static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) +{ + int ret; + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n"); return -EINVAL; @@ -6928,10 +7130,14 @@ if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) return tg3_nvram_read_using_eeprom(tp, offset, val); - if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) - offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) << - NVRAM_BUFFERED_PAGE_POS) + - (offset % NVRAM_BUFFERED_PAGE_SIZE); + if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && + (tp->tg3_flags2 & TG3_FLG2_FLASH) && + (tp->nvram_jedecnum == JEDEC_ATMEL)) { + + offset = ((offset / tp->nvram_pagesize) << + ATMEL_AT45DB0X1B_PAGE_POS) + + (offset % tp->nvram_pagesize); + } if (offset > NVRAM_ADDR_MSK) return -EINVAL; @@ -6945,19 +7151,11 @@ } tw32(NVRAM_ADDR, offset); - tw32(NVRAM_CMD, - NVRAM_CMD_RD | NVRAM_CMD_GO | - NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE); + ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO | + NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE); - /* Wait for done bit to clear. */ - for (i = 0; i < 1000; i++) { - udelay(10); - if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) { - udelay(10); - *val = swab32(tr32(NVRAM_RDDATA)); - break; - } - } + if (ret == 0) + *val = swab32(tr32(NVRAM_RDDATA)); tg3_nvram_unlock(tp); @@ -6967,10 +7165,268 @@ tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); } - if (i >= 1000) - return -EBUSY; + return ret; +} - return 0; +static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp, + u32 offset, u32 len, u8 *buf) +{ + int i, j, rc = 0; + u32 val; + + for (i = 0; i < len; i += 4) { + u32 addr, data; + + addr = offset + i; + + memcpy(&data, buf + i, 4); + + tw32(GRC_EEPROM_DATA, cpu_to_le32(data)); + + val = tr32(GRC_EEPROM_ADDR); + tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE); + + val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK | + EEPROM_ADDR_READ); + tw32(GRC_EEPROM_ADDR, val | + (0 << EEPROM_ADDR_DEVID_SHIFT) | + (addr & EEPROM_ADDR_ADDR_MASK) | + EEPROM_ADDR_START | + EEPROM_ADDR_WRITE); + + for (j = 0; j < 10000; j++) { + val = tr32(GRC_EEPROM_ADDR); + + if (val & EEPROM_ADDR_COMPLETE) + break; + udelay(100); + } + if (!(val & EEPROM_ADDR_COMPLETE)) { + rc = -EBUSY; + break; + } + } + + return rc; +} + +/* offset and length are dword aligned */ +static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len, + u8 *buf) +{ + int ret = 0; + u32 pagesize = tp->nvram_pagesize; + u32 pagemask = pagesize - 1; + u32 nvram_cmd; + u8 *tmp; + + tmp = kmalloc(pagesize, GFP_KERNEL); + if (tmp == NULL) + return -ENOMEM; + + while (len) { + int j; + u32 phy_addr, page_off, size, nvaccess; + + phy_addr = offset & ~pagemask; + + for (j = 0; j < pagesize; j += 4) { + if ((ret = tg3_nvram_read(tp, phy_addr + j, + (u32 *) (tmp + j)))) + break; + } + if (ret) + break; + + page_off = offset & pagemask; + size = pagesize; + if (len < size) + size = len; + + len -= size; + + memcpy(tmp + page_off, buf, size); + + offset = offset + (pagesize - page_off); + + nvaccess = tr32(NVRAM_ACCESS); + tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); + + /* + * Before we can erase the flash page, we need + * to issue a special "write enable" command. + */ + nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE; + + if (tg3_nvram_exec_cmd(tp, nvram_cmd)) + break; + + /* Erase the target page */ + tw32(NVRAM_ADDR, phy_addr); + + nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR | + NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE; + + if (tg3_nvram_exec_cmd(tp, nvram_cmd)) + break; + + /* Issue another write enable to start the write. */ + nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE; + + if (tg3_nvram_exec_cmd(tp, nvram_cmd)) + break; + + for (j = 0; j < pagesize; j += 4) { + u32 data; + + data = *((u32 *) (tmp + j)); + tw32(NVRAM_WRDATA, cpu_to_be32(data)); + + tw32(NVRAM_ADDR, phy_addr + j); + + nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | + NVRAM_CMD_WR; + + if (j == 0) + nvram_cmd |= NVRAM_CMD_FIRST; + else if (j == (pagesize - 4)) + nvram_cmd |= NVRAM_CMD_LAST; + + if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd))) + break; + } + if (ret) + break; + } + + nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE; + tg3_nvram_exec_cmd(tp, nvram_cmd); + + kfree(tmp); + + return ret; +} + +/* offset and length are dword aligned */ +static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, + u8 *buf) +{ + int i, ret = 0; + + for (i = 0; i < len; i += 4, offset += 4) { + u32 data, page_off, phy_addr, nvram_cmd; + + memcpy(&data, buf + i, 4); + tw32(NVRAM_WRDATA, cpu_to_be32(data)); + + page_off = offset % tp->nvram_pagesize; + + if ((tp->tg3_flags2 & TG3_FLG2_FLASH) && + (tp->nvram_jedecnum == JEDEC_ATMEL)) { + + phy_addr = ((offset / tp->nvram_pagesize) << + ATMEL_AT45DB0X1B_PAGE_POS) + page_off; + } + else { + phy_addr = offset; + } + + tw32(NVRAM_ADDR, phy_addr); + + nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR; + + if ((page_off == 0) || (i == 0)) + nvram_cmd |= NVRAM_CMD_FIRST; + else if (page_off == (tp->nvram_pagesize - 4)) + nvram_cmd |= NVRAM_CMD_LAST; + + if (i == (len - 4)) + nvram_cmd |= NVRAM_CMD_LAST; + + if ((tp->nvram_jedecnum == JEDEC_ST) && + (nvram_cmd & NVRAM_CMD_FIRST)) { + + if ((ret = tg3_nvram_exec_cmd(tp, + NVRAM_CMD_WREN | NVRAM_CMD_GO | + NVRAM_CMD_DONE))) + + break; + } + if (!(tp->tg3_flags2 & TG3_FLG2_FLASH)) { + /* We always do complete word writes to eeprom. */ + nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST); + } + + if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd))) + break; + } + return ret; +} + +/* offset and length are dword aligned */ +static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf) +{ + int ret; + + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { + printk(KERN_ERR PFX "Attempt to do nvram_write on Sun 570X\n"); + return -EINVAL; + } + + if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + GRC_LCLCTRL_GPIO_OE1); + udelay(40); + } + + if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) { + ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf); + } + else { + u32 grc_mode; + + tg3_nvram_lock(tp); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + u32 nvaccess = tr32(NVRAM_ACCESS); + + tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); + + tw32(NVRAM_WRITE1, 0x406); + } + + grc_mode = tr32(GRC_MODE); + tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE); + + if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) || + !(tp->tg3_flags2 & TG3_FLG2_FLASH)) { + + ret = tg3_nvram_write_block_buffered(tp, offset, len, + buf); + } + else { + ret = tg3_nvram_write_block_unbuffered(tp, offset, len, + buf); + } + + grc_mode = tr32(GRC_MODE); + tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) { + u32 nvaccess = tr32(NVRAM_ACCESS); + + tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); + } + tg3_nvram_unlock(tp); + } + + if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) { + tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | + GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1); + udelay(40); + } + + return ret; } struct subsys_tbl_ent { @@ -8209,6 +8665,7 @@ if (pci_using_dac) dev->features |= NETIF_F_HIGHDMA; + dev->features |= NETIF_F_LLTX; #if TG3_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; dev->vlan_rx_register = tg3_vlan_rx_register; @@ -8250,6 +8707,7 @@ tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA; #endif spin_lock_init(&tp->lock); + spin_lock_init(&tp->tx_lock); spin_lock_init(&tp->indirect_lock); INIT_WORK(&tp->reset_task, tg3_reset_task, tp); @@ -8462,23 +8920,23 @@ del_timer_sync(&tp->timer); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_disable_ints(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); netif_device_detach(dev); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_halt(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); err = tg3_set_power_state(tp, state); if (err) { spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_init_hw(tp); @@ -8488,7 +8946,7 @@ netif_device_attach(dev); tg3_netif_start(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } @@ -8513,7 +8971,7 @@ netif_device_attach(dev); spin_lock_irq(&tp->lock); - spin_lock(&dev->xmit_lock); + spin_lock(&tp->tx_lock); tg3_init_hw(tp); @@ -8524,7 +8982,7 @@ tg3_netif_start(tp); - spin_unlock(&dev->xmit_lock); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); return 0; diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h --- a/drivers/net/tg3.h 2005-01-23 21:02:28 -08:00 +++ b/drivers/net/tg3.h 2005-01-23 21:02:28 -08:00 @@ -1274,6 +1274,7 @@ #define GRC_MODE_HOST_STACKUP 0x00010000 #define GRC_MODE_HOST_SENDBDS 0x00020000 #define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000 +#define GRC_MODE_NVRAM_WR_ENABLE 0x00200000 #define GRC_MODE_NO_RX_PHDR_CSUM 0x00800000 #define GRC_MODE_IRQ_ON_TX_CPU_ATTN 0x01000000 #define GRC_MODE_IRQ_ON_RX_CPU_ATTN 0x02000000 @@ -1366,6 +1367,8 @@ #define NVRAM_CMD_ERASE 0x00000040 #define NVRAM_CMD_FIRST 0x00000080 #define NVRAM_CMD_LAST 0x00000100 +#define NVRAM_CMD_WREN 0x00010000 +#define NVRAM_CMD_WRDI 0x00020000 #define NVRAM_STAT 0x00007004 #define NVRAM_WRDATA 0x00007008 #define NVRAM_ADDR 0x0000700c @@ -1375,8 +1378,18 @@ #define NVRAM_CFG1_FLASHIF_ENAB 0x00000001 #define NVRAM_CFG1_BUFFERED_MODE 0x00000002 #define NVRAM_CFG1_PASS_THRU 0x00000004 +#define NVRAM_CFG1_STATUS_BITS 0x00000070 #define NVRAM_CFG1_BIT_BANG 0x00000008 +#define NVRAM_CFG1_FLASH_SIZE 0x02000000 #define NVRAM_CFG1_COMPAT_BYPASS 0x80000000 +#define NVRAM_CFG1_VENDOR_MASK 0x03000003 +#define FLASH_VENDOR_ATMEL_EEPROM 0x02000000 +#define FLASH_VENDOR_ATMEL_FLASH_BUFFERED 0x02000003 +#define FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED 0x00000003 +#define FLASH_VENDOR_ST 0x03000001 +#define FLASH_VENDOR_SAIFUN 0x01000003 +#define FLASH_VENDOR_SST_SMALL 0x00000001 +#define FLASH_VENDOR_SST_LARGE 0x02000001 #define NVRAM_CFG2 0x00007018 #define NVRAM_CFG3 0x0000701c #define NVRAM_SWARB 0x00007020 @@ -1396,15 +1409,16 @@ #define SWARB_REQ1 0x00002000 #define SWARB_REQ2 0x00004000 #define SWARB_REQ3 0x00008000 -#define NVRAM_BUFFERED_PAGE_SIZE 264 -#define NVRAM_BUFFERED_PAGE_POS 9 #define NVRAM_ACCESS 0x00007024 #define ACCESS_ENABLE 0x00000001 #define ACCESS_WR_ENABLE 0x00000002 -/* 0x7024 --> 0x7400 unused */ +#define NVRAM_WRITE1 0x00007028 +/* 0x702c --> 0x7400 unused */ /* 0x7400 --> 0x8000 unused */ +#define TG3_EEPROM_MAGIC 0x669955aa + /* 32K Window into NIC internal memory */ #define NIC_SRAM_WIN_BASE 0x00008000 @@ -1980,11 +1994,12 @@ * lock: Held during all operations except TX packet * processing. * - * dev->xmit_lock: Held during tg3_start_xmit and tg3_tx + * tx_lock: Held during tg3_start_xmit{,_4gbug} and tg3_tx * * If you want to shut up all asynchronous processing you must - * acquire both locks, 'lock' taken before 'xmit_lock'. IRQs must - * be disabled to take either lock. + * acquire both locks, 'lock' taken before 'tx_lock'. IRQs must + * be disabled to take 'lock' but only softirq disabling is + * necessary for acquisition of 'tx_lock'. */ spinlock_t lock; spinlock_t indirect_lock; @@ -2003,6 +2018,8 @@ u32 tx_cons; u32 tx_pending; + spinlock_t tx_lock; + struct tg3_tx_buffer_desc *tx_ring; struct tx_ring_info *tx_buffers; dma_addr_t tx_desc_mapping; @@ -2087,6 +2104,7 @@ #define TG3_FLG2_PHY_JUST_INITTED 0x00001000 #define TG3_FLG2_PHY_SERDES 0x00002000 #define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 +#define TG3_FLG2_FLASH 0x00008000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 @@ -2160,6 +2178,34 @@ struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; struct work_struct reset_task; + + u32 nvram_size; + u32 nvram_pagesize; + u32 nvram_jedecnum; + +#define JEDEC_ATMEL 0x1f +#define JEDEC_ST 0x20 +#define JEDEC_SAIFUN 0x4f +#define JEDEC_SST 0xbf + +#define ATMEL_AT24C64_CHIP_SIZE (64 * 1024) +#define ATMEL_AT24C64_PAGE_SIZE (32) + +#define ATMEL_AT24C512_CHIP_SIZE (512 * 1024) +#define ATMEL_AT24C512_PAGE_SIZE (128) + +#define ATMEL_AT45DB0X1B_PAGE_POS 9 +#define ATMEL_AT45DB0X1B_PAGE_SIZE 264 + +#define ATMEL_AT25F512_PAGE_SIZE 256 + +#define ST_M45PEX0_PAGE_SIZE 256 + +#define SAIFUN_SA25F0XX_PAGE_SIZE 256 + +#define SST_25VF0X0_PAGE_SIZE 4098 + + }; #endif /* !(_T3_H) */ diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c --- a/drivers/video/fbmem.c 2005-01-23 21:02:28 -08:00 +++ b/drivers/video/fbmem.c 2005-01-23 21:02:28 -08:00 @@ -35,6 +35,7 @@ #include #include #include +#include #if defined(__mc68000__) || defined(CONFIG_APUS) #include @@ -967,9 +968,13 @@ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #elif defined(__hppa__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; -#elif defined(__ia64__) || defined(__arm__) || defined(__sh__) || \ - defined(__m32r__) +#elif defined(__arm__) || defined(__sh__) || defined(__m32r__) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#elif defined(__ia64__) + if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #else #warning What do we have to do here?? #endif diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c 2005-01-23 21:02:28 -08:00 +++ b/fs/binfmt_elf.c 2005-01-23 21:02:28 -08:00 @@ -110,15 +110,17 @@ be in memory */ -static void padzero(unsigned long elf_bss) +static int padzero(unsigned long elf_bss) { unsigned long nbyte; nbyte = ELF_PAGEOFFSET(elf_bss); if (nbyte) { nbyte = ELF_MIN_ALIGN - nbyte; - clear_user((void __user *) elf_bss, nbyte); + if (clear_user((void __user *) elf_bss, nbyte)) + return -EFAULT; } + return 0; } /* Let's use some macros to make this stack manipulation a litle clearer */ @@ -134,7 +136,7 @@ #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) #endif -static void +static int create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, int interp_aout, unsigned long load_addr, unsigned long interp_load_addr) @@ -179,7 +181,8 @@ STACK_ALLOC(p, ((current->pid % 64) << 7)); #endif u_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); - __copy_to_user(u_platform, k_platform, len); + if (__copy_to_user(u_platform, k_platform, len)) + return -EFAULT; } /* Create the ELF interpreter info */ @@ -241,7 +244,8 @@ #endif /* Now, let's put argc (and argv, envp if appropriate) on the stack */ - __put_user(argc, sp++); + if (__put_user(argc, sp++)) + return -EFAULT; if (interp_aout) { argv = sp + 2; envp = argv + argc + 1; @@ -259,25 +263,29 @@ __put_user((elf_addr_t)p, argv++); len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) - return; + return 0; p += len; } - __put_user(0, argv); + if (__put_user(0, argv)) + return -EFAULT; current->mm->arg_end = current->mm->env_start = p; while (envc-- > 0) { size_t len; __put_user((elf_addr_t)p, envp++); len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES); if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) - return; + return 0; p += len; } - __put_user(0, envp); + if (__put_user(0, envp)) + return -EFAULT; current->mm->env_end = p; /* Put the elf_info on the stack in the right place. */ sp = (elf_addr_t __user *)envp + 1; - copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t)); + if (copy_to_user(sp, elf_info, ei_index * sizeof(elf_addr_t))) + return -EFAULT; + return 0; } #ifndef elf_map @@ -411,7 +419,11 @@ * that there are zero-mapped pages up to and including the * last bss page. */ - padzero(elf_bss); + if (padzero(elf_bss)) { + error = -EFAULT; + goto out_close; + } + elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ @@ -791,7 +803,11 @@ nbyte = ELF_MIN_ALIGN - nbyte; if (nbyte > elf_brk - elf_bss) nbyte = elf_brk - elf_bss; - clear_user((void __user *) elf_bss + load_bias, nbyte); + if (clear_user((void __user *) elf_bss + load_bias, nbyte)) { + retval = -EFAULT; + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } } } @@ -875,7 +891,11 @@ send_sig(SIGKILL, current, 0); goto out_free_dentry; } - padzero(elf_bss); + if (padzero(elf_bss)) { + send_sig(SIGSEGV, current, 0); + retval = -EFAULT; /* Nobody gets to see this, but.. */ + goto out_free_dentry; + } if (elf_interpreter) { if (interpreter_type == INTERPRETER_AOUT) @@ -1039,7 +1059,10 @@ goto out_free_ph; elf_bss = elf_phdata->p_vaddr + elf_phdata->p_filesz; - padzero(elf_bss); + if (padzero(elf_bss)) { + error = -EFAULT; + goto out_free_ph; + } len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1); bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; @@ -1246,8 +1269,8 @@ cputime_to_timeval(p->signal->cstime, &prstatus->pr_cstime); } -static void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, - struct mm_struct *mm) +static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, + struct mm_struct *mm) { int i, len; @@ -1257,8 +1280,9 @@ len = mm->arg_end - mm->arg_start; if (len >= ELF_PRARGSZ) len = ELF_PRARGSZ-1; - copy_from_user(&psinfo->pr_psargs, - (const char __user *)mm->arg_start, len); + if (copy_from_user(&psinfo->pr_psargs, + (const char __user *)mm->arg_start, len)) + return -EFAULT; for(i = 0; i < len; i++) if (psinfo->pr_psargs[i] == 0) psinfo->pr_psargs[i] = ' '; @@ -1279,7 +1303,7 @@ SET_GID(psinfo->pr_gid, p->gid); strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname)); - return; + return 0; } /* Here is the structure in which status of each thread is captured. */ diff -Nru a/fs/compat_ioctl.c b/fs/compat_ioctl.c --- a/fs/compat_ioctl.c 2005-01-23 21:02:28 -08:00 +++ b/fs/compat_ioctl.c 2005-01-23 21:02:28 -08:00 @@ -645,8 +645,11 @@ /* Don't check these user accesses, just let that get trapped * in the ioctl handler instead. */ - copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ); - __put_user(data64, &u_ifreq64->ifr_ifru.ifru_data); + if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], + IFNAMSIZ)) + return -EFAULT; + if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) + return -EFAULT; return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); } @@ -2343,7 +2346,9 @@ __put_user(d->d_ino, &d32->d_ino); __put_user(d->d_off, &d32->d_off); __put_user(d->d_reclen, &d32->d_reclen); - __copy_to_user(d32->d_name, d->d_name, d->d_reclen); + if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen)) + return -EFAULT; + return ret; } @@ -2486,7 +2491,8 @@ if (cmd == TIOCSSERIAL) { if (verify_area(VERIFY_READ, ss32, sizeof(SS32))) return -EFAULT; - __copy_from_user(&ss, ss32, offsetof(SS32, iomem_base)); + if (__copy_from_user(&ss, ss32, offsetof(SS32, iomem_base))) + return -EFAULT; __get_user(udata, &ss32->iomem_base); ss.iomem_base = compat_ptr(udata); __get_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift); @@ -2499,7 +2505,8 @@ if (cmd == TIOCGSERIAL && err >= 0) { if (verify_area(VERIFY_WRITE, ss32, sizeof(SS32))) return -EFAULT; - __copy_to_user(ss32,&ss,offsetof(SS32,iomem_base)); + if (__copy_to_user(ss32,&ss,offsetof(SS32,iomem_base))) + return -EFAULT; __put_user((unsigned long)ss.iomem_base >> 32 ? 0xffffffff : (unsigned)(unsigned long)ss.iomem_base, &ss32->iomem_base); diff -Nru a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h --- a/include/asm-ia64/bitops.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/bitops.h 2005-01-23 21:02:28 -08:00 @@ -359,7 +359,7 @@ #endif /* __KERNEL__ */ -extern int __find_next_zero_bit (void *addr, unsigned long size, +extern int __find_next_zero_bit (const void *addr, unsigned long size, unsigned long offset); extern int __find_next_bit(const void *addr, unsigned long size, unsigned long offset); diff -Nru a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h --- a/include/asm-ia64/hw_irq.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/hw_irq.h 2005-01-23 21:02:28 -08:00 @@ -99,18 +99,6 @@ extern irq_desc_t irq_desc[NR_IRQS]; #ifndef CONFIG_IA64_GENERIC -static inline irq_desc_t * -__ia64_irq_desc (unsigned int irq) -{ - return irq_desc + irq; -} - -static inline ia64_vector -__ia64_irq_to_vector (unsigned int irq) -{ - return (ia64_vector) irq; -} - static inline unsigned int __ia64_local_vector_to_irq (ia64_vector vec) { @@ -132,14 +120,14 @@ static inline irq_desc_t * irq_descp (int irq) { - return platform_irq_desc(irq); + return irq_desc + irq; } /* Extract the IA-64 vector that corresponds to IRQ. */ static inline ia64_vector irq_to_vector (int irq) { - return platform_irq_to_vector(irq); + return (ia64_vector) irq; } /* diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h --- a/include/asm-ia64/machvec.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/machvec.h 2005-01-23 21:02:28 -08:00 @@ -17,7 +17,6 @@ struct device; struct pt_regs; struct scatterlist; -struct irq_desc; struct page; struct mm_struct; struct pci_bus; @@ -29,8 +28,6 @@ typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *); typedef void ia64_mv_global_tlb_purge_t (unsigned long, unsigned long, unsigned long); typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *); -typedef struct irq_desc *ia64_mv_irq_desc (unsigned int); -typedef u8 ia64_mv_irq_to_vector (unsigned int); typedef unsigned int ia64_mv_local_vector_to_irq (u8); typedef char *ia64_mv_pci_get_legacy_mem_t (struct pci_bus *); typedef int ia64_mv_pci_legacy_read_t (struct pci_bus *, u16 port, u32 *val, @@ -130,8 +127,6 @@ # define platform_dma_sync_sg_for_device ia64_mv.dma_sync_sg_for_device # define platform_dma_mapping_error ia64_mv.dma_mapping_error # define platform_dma_supported ia64_mv.dma_supported -# define platform_irq_desc ia64_mv.irq_desc -# define platform_irq_to_vector ia64_mv.irq_to_vector # define platform_local_vector_to_irq ia64_mv.local_vector_to_irq # define platform_pci_get_legacy_mem ia64_mv.pci_get_legacy_mem # define platform_pci_legacy_read ia64_mv.pci_legacy_read @@ -180,8 +175,6 @@ ia64_mv_dma_sync_sg_for_device *dma_sync_sg_for_device; ia64_mv_dma_mapping_error *dma_mapping_error; ia64_mv_dma_supported *dma_supported; - ia64_mv_irq_desc *irq_desc; - ia64_mv_irq_to_vector *irq_to_vector; ia64_mv_local_vector_to_irq *local_vector_to_irq; ia64_mv_pci_get_legacy_mem_t *pci_get_legacy_mem; ia64_mv_pci_legacy_read_t *pci_legacy_read; @@ -226,8 +219,6 @@ platform_dma_sync_sg_for_device, \ platform_dma_mapping_error, \ platform_dma_supported, \ - platform_irq_desc, \ - platform_irq_to_vector, \ platform_local_vector_to_irq, \ platform_pci_get_legacy_mem, \ platform_pci_legacy_read, \ @@ -337,12 +328,6 @@ #endif #ifndef platform_dma_supported # define platform_dma_supported swiotlb_dma_supported -#endif -#ifndef platform_irq_desc -# define platform_irq_desc __ia64_irq_desc -#endif -#ifndef platform_irq_to_vector -# define platform_irq_to_vector __ia64_irq_to_vector #endif #ifndef platform_local_vector_to_irq # define platform_local_vector_to_irq __ia64_local_vector_to_irq diff -Nru a/include/asm-ia64/machvec_init.h b/include/asm-ia64/machvec_init.h --- a/include/asm-ia64/machvec_init.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/machvec_init.h 2005-01-23 21:02:28 -08:00 @@ -2,8 +2,6 @@ extern ia64_mv_send_ipi_t ia64_send_ipi; extern ia64_mv_global_tlb_purge_t ia64_global_tlb_purge; -extern ia64_mv_irq_desc __ia64_irq_desc; -extern ia64_mv_irq_to_vector __ia64_irq_to_vector; extern ia64_mv_local_vector_to_irq __ia64_local_vector_to_irq; extern ia64_mv_pci_get_legacy_mem_t ia64_pci_get_legacy_mem; extern ia64_mv_pci_legacy_read_t ia64_pci_legacy_read; diff -Nru a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h --- a/include/asm-ia64/machvec_sn2.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/machvec_sn2.h 2005-01-23 21:02:28 -08:00 @@ -40,8 +40,6 @@ extern ia64_mv_timer_interrupt_t sn_timer_interrupt; extern ia64_mv_global_tlb_purge_t sn2_global_tlb_purge; extern ia64_mv_tlb_migrate_finish_t sn_tlb_migrate_finish; -extern ia64_mv_irq_desc sn_irq_desc; -extern ia64_mv_irq_to_vector sn_irq_to_vector; extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq; extern ia64_mv_pci_get_legacy_mem_t sn_pci_get_legacy_mem; extern ia64_mv_pci_legacy_read_t sn_pci_legacy_read; @@ -105,8 +103,6 @@ #define platform_readw_relaxed __sn_readw_relaxed #define platform_readl_relaxed __sn_readl_relaxed #define platform_readq_relaxed __sn_readq_relaxed -#define platform_irq_desc sn_irq_desc -#define platform_irq_to_vector sn_irq_to_vector #define platform_local_vector_to_irq sn_local_vector_to_irq #define platform_pci_get_legacy_mem sn_pci_get_legacy_mem #define platform_pci_legacy_read sn_pci_legacy_read diff -Nru a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h --- a/include/asm-ia64/pal.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/pal.h 2005-01-23 21:02:28 -08:00 @@ -66,7 +66,7 @@ #define PAL_CACHE_PROT_INFO 38 /* get i/d cache protection info */ #define PAL_REGISTER_INFO 39 /* return AR and CR register information*/ #define PAL_SHUTDOWN 40 /* enter processor shutdown state */ -#define PAL_PREFETCH_VISIBILITY 41 +#define PAL_PREFETCH_VISIBILITY 41 /* Make Processor Prefetches Visible */ #define PAL_COPY_PAL 256 /* relocate PAL procedures and PAL PMI */ #define PAL_HALT_INFO 257 /* return the low power capabilities of processor */ @@ -1537,11 +1537,25 @@ return iprv.status; } +/* + * PAL_PREFETCH_VISIBILITY transaction types + */ +#define PAL_VISIBILITY_VIRTUAL 0 +#define PAL_VISIBILITY_PHYSICAL 1 + +/* + * PAL_PREFETCH_VISIBILITY return codes + */ +#define PAL_VISIBILITY_OK 1 +#define PAL_VISIBILITY_OK_REMOTE_NEEDED 0 +#define PAL_VISIBILITY_INVAL_ARG -2 +#define PAL_VISIBILITY_ERROR -3 + static inline s64 -ia64_pal_prefetch_visibility (void) +ia64_pal_prefetch_visibility (s64 trans_type) { struct ia64_pal_retval iprv; - PAL_CALL(iprv, PAL_PREFETCH_VISIBILITY, 0, 0, 0); + PAL_CALL(iprv, PAL_PREFETCH_VISIBILITY, trans_type, 0, 0); return iprv.status; } diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h --- a/include/asm-ia64/sal.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/sal.h 2005-01-23 21:02:28 -08:00 @@ -833,6 +833,8 @@ extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64, u64, u64, u64, u64, u64); +extern void ia64_sal_handler_init(void *entry_point, void *gpval); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_IA64_SAL_H */ diff -Nru a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h --- a/include/asm-ia64/sn/sn_cpuid.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/sn/sn_cpuid.h 2005-01-23 21:02:28 -08:00 @@ -82,7 +82,6 @@ */ #ifndef CONFIG_SMP -#define cpu_logical_id(cpu) 0 #define cpu_physical_id(cpuid) ((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff) #endif diff -Nru a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h --- a/include/asm-ia64/uaccess.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/uaccess.h 2005-01-23 21:02:28 -08:00 @@ -132,7 +132,7 @@ #ifdef ASM_SUPPORTED struct __large_struct { unsigned long buf[100]; }; -# define __m(x) (*(struct __large_struct *)(x)) +# define __m(x) (*(struct __large_struct __user *)(x)) /* We need to declare the __ex_table section before we can use it in .xdata. */ asm (".section \"__ex_table\", \"a\"\n\t.previous"); diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h --- a/include/asm-ia64/unistd.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-ia64/unistd.h 2005-01-23 21:02:28 -08:00 @@ -374,7 +374,7 @@ int fd, long pgoff); struct pt_regs; struct sigaction; -asmlinkage long sys_execve(char __user *filename, char __user * __user *argv, +long sys_execve(char __user *filename, char __user * __user *argv, char __user * __user *envp, struct pt_regs *regs); asmlinkage long sys_pipe(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long stack); diff -Nru a/include/asm-x86_64/numnodes.h b/include/asm-x86_64/numnodes.h --- a/include/asm-x86_64/numnodes.h 2005-01-23 21:02:28 -08:00 +++ b/include/asm-x86_64/numnodes.h 2005-01-23 21:02:28 -08:00 @@ -3,6 +3,10 @@ #include +#ifdef CONFIG_NUMA #define NODES_SHIFT 6 +#else +#define NODES_SHIFT 0 +#endif #endif diff -Nru a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h --- a/include/linux/dvb/frontend.h 2005-01-23 21:02:28 -08:00 +++ b/include/linux/dvb/frontend.h 2005-01-23 21:02:28 -08:00 @@ -158,10 +158,11 @@ QAM_64, QAM_128, QAM_256, - QAM_AUTO + QAM_AUTO, + VSB_8, + VSB_16 } fe_modulation_t; - typedef enum fe_transmit_mode { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, @@ -206,6 +207,9 @@ fe_modulation_t modulation; /* modulation type (see above) */ }; +struct dvb_vsb_parameters { + fe_modulation_t modulation; /* modulation type (see above) */ +}; struct dvb_ofdm_parameters { fe_bandwidth_t bandwidth; @@ -219,13 +223,14 @@ struct dvb_frontend_parameters { - __u32 frequency; /* (absolute) frequency in Hz for QAM/OFDM */ + __u32 frequency; /* (absolute) frequency in Hz for QAM/OFDM/ATSC */ /* intermediate frequency in kHz for QPSK */ fe_spectral_inversion_t inversion; union { struct dvb_qpsk_parameters qpsk; struct dvb_qam_parameters qam; struct dvb_ofdm_parameters ofdm; + struct dvb_vsb_parameters vsb; } u; }; diff -Nru a/include/linux/dvb/version.h b/include/linux/dvb/version.h --- a/include/linux/dvb/version.h 2005-01-23 21:02:28 -08:00 +++ b/include/linux/dvb/version.h 2005-01-23 21:02:28 -08:00 @@ -24,6 +24,7 @@ #define _DVBVERSION_H_ #define DVB_API_VERSION 3 +#define DVB_API_VERSION_MINOR 1 #endif /*_DVBVERSION_H_*/ diff -Nru a/include/linux/efi.h b/include/linux/efi.h --- a/include/linux/efi.h 2005-01-23 21:02:28 -08:00 +++ b/include/linux/efi.h 2005-01-23 21:02:28 -08:00 @@ -305,6 +305,27 @@ extern int __init efi_set_rtc_mmss(unsigned long nowtime); extern struct efi_memory_map memmap; +/** + * efi_range_is_wc - check the WC bit on an address range + * @start: starting kvirt address + * @len: length of range + * + * Consult the EFI memory map and make sure it's ok to set this range WC. + * Returns true or false. + */ +static inline int efi_range_is_wc(unsigned long start, unsigned long len) +{ + int i; + + for (i = 0; i < len; i += (1UL << EFI_PAGE_SHIFT)) { + unsigned long paddr = __pa(start + i); + if (!(efi_mem_attributes(paddr) & EFI_MEMORY_WC)) + return 0; + } + /* The range checked out */ + return 1; +} + #ifdef CONFIG_EFI_PCDP extern int __init efi_setup_pcdp_console(char *); #endif diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h 2005-01-23 21:02:28 -08:00 +++ b/include/linux/netdevice.h 2005-01-23 21:02:28 -08:00 @@ -76,6 +76,7 @@ /* Driver transmit return codes */ #define NETDEV_TX_OK 0 /* driver took care of packet */ #define NETDEV_TX_BUSY 1 /* driver tx path was busy*/ +#define NETDEV_TX_LOCKED -1 /* driver tx lock was already taken */ /* * Compute the worst case header length according to the protocols @@ -414,7 +415,7 @@ #define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */ #define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */ #define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */ -#define NETIF_F_LLTX 4096 /* Do not grab xmit_lock during ->hard_start_xmit */ +#define NETIF_F_LLTX 4096 /* LockLess TX */ /* Called after device is detached from network. */ void (*uninit)(struct net_device *dev); @@ -893,11 +894,9 @@ static inline void netif_tx_disable(struct net_device *dev) { - unsigned long flags; - - spin_lock_irqsave(&dev->xmit_lock, flags); + spin_lock_bh(&dev->xmit_lock); netif_stop_queue(dev); - spin_unlock_irqrestore(&dev->xmit_lock, flags); + spin_unlock_bh(&dev->xmit_lock); } /* These functions live elsewhere (drivers/net/net_init.c, but related) */ diff -Nru a/kernel/kallsyms.c b/kernel/kallsyms.c --- a/kernel/kallsyms.c 2005-01-23 21:02:28 -08:00 +++ b/kernel/kallsyms.c 2005-01-23 21:02:28 -08:00 @@ -53,6 +53,13 @@ return in_gate_area_no_task(addr); } +static inline int is_kernel(unsigned long addr) +{ + if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end) + return 1; + return in_gate_area_no_task(addr); +} + /* expand a compressed symbol data into the resulting uncompressed string, given the offset to where the symbol is in the compressed stream */ static unsigned int kallsyms_expand_symbol(unsigned int off, char *result) @@ -153,7 +160,8 @@ namebuf[KSYM_NAME_LEN] = 0; namebuf[0] = 0; - if (all_var || is_kernel_text(addr) || is_kernel_inittext(addr)) { + if ((all_var && is_kernel(addr)) || + (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr)))) { unsigned long symbol_end=0; /* do a binary search on the sorted kallsyms_addresses array */ diff -Nru a/mm/memory.c b/mm/memory.c --- a/mm/memory.c 2005-01-23 21:02:28 -08:00 +++ b/mm/memory.c 2005-01-23 21:02:28 -08:00 @@ -442,17 +442,18 @@ if (next > end || next <= addr) next = end; if (pgd_none(*src_pgd)) - continue; + goto next_pgd; if (pgd_bad(*src_pgd)) { pgd_ERROR(*src_pgd); pgd_clear(src_pgd); - continue; + goto next_pgd; } err = copy_pud_range(dst, src, dst_pgd, src_pgd, vma, addr, next); if (err) break; +next_pgd: src_pgd++; dst_pgd++; addr = next; diff -Nru a/net/atm/clip.c b/net/atm/clip.c --- a/net/atm/clip.c 2005-01-23 21:02:28 -08:00 +++ b/net/atm/clip.c 2005-01-23 21:02:28 -08:00 @@ -97,7 +97,7 @@ printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n",clip_vcc); return; } - spin_lock_irq(&entry->neigh->dev->xmit_lock); /* block clip_start_xmit() */ + spin_lock_bh(&entry->neigh->dev->xmit_lock); /* block clip_start_xmit() */ entry->neigh->used = jiffies; for (walk = &entry->vccs; *walk; walk = &(*walk)->next) if (*walk == clip_vcc) { @@ -121,7 +121,7 @@ printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc " "0x%p)\n",entry,clip_vcc); out: - spin_unlock_irq(&entry->neigh->dev->xmit_lock); + spin_unlock_bh(&entry->neigh->dev->xmit_lock); } /* The neighbour entry n->lock is held. */ diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c 2005-01-23 21:02:28 -08:00 +++ b/net/core/dev.c 2005-01-23 21:02:28 -08:00 @@ -1190,7 +1190,7 @@ #define HARD_TX_LOCK(dev, cpu) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ - spin_lock_irq(&dev->xmit_lock); \ + spin_lock(&dev->xmit_lock); \ dev->xmit_lock_owner = cpu; \ } \ } @@ -1198,7 +1198,7 @@ #define HARD_TX_UNLOCK(dev) { \ if ((dev->features & NETIF_F_LLTX) == 0) { \ dev->xmit_lock_owner = -1; \ - spin_unlock_irq(&dev->xmit_lock); \ + spin_unlock(&dev->xmit_lock); \ } \ } diff -Nru a/net/core/dev_mcast.c b/net/core/dev_mcast.c --- a/net/core/dev_mcast.c 2005-01-23 21:02:28 -08:00 +++ b/net/core/dev_mcast.c 2005-01-23 21:02:28 -08:00 @@ -93,9 +93,9 @@ void dev_mc_upload(struct net_device *dev) { - spin_lock_irq(&dev->xmit_lock); + spin_lock_bh(&dev->xmit_lock); __dev_mc_upload(dev); - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); } /* @@ -107,7 +107,7 @@ int err = 0; struct dev_mc_list *dmi, **dmip; - spin_lock_irq(&dev->xmit_lock); + spin_lock_bh(&dev->xmit_lock); for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) { /* @@ -139,13 +139,13 @@ */ __dev_mc_upload(dev); - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); return 0; } } err = -ENOENT; done: - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); return err; } @@ -160,7 +160,7 @@ dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC); - spin_lock_irq(&dev->xmit_lock); + spin_lock_bh(&dev->xmit_lock); for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 && dmi->dmi_addrlen == alen) { @@ -176,7 +176,7 @@ } if ((dmi = dmi1) == NULL) { - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); return -ENOMEM; } memcpy(dmi->dmi_addr, addr, alen); @@ -189,11 +189,11 @@ __dev_mc_upload(dev); - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); return 0; done: - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); if (dmi1) kfree(dmi1); return err; @@ -205,7 +205,7 @@ void dev_mc_discard(struct net_device *dev) { - spin_lock_irq(&dev->xmit_lock); + spin_lock_bh(&dev->xmit_lock); while (dev->mc_list != NULL) { struct dev_mc_list *tmp = dev->mc_list; @@ -216,7 +216,7 @@ } dev->mc_count = 0; - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); } #ifdef CONFIG_PROC_FS @@ -251,7 +251,7 @@ struct dev_mc_list *m; struct net_device *dev = v; - spin_lock_irq(&dev->xmit_lock); + spin_lock_bh(&dev->xmit_lock); for (m = dev->mc_list; m; m = m->next) { int i; @@ -263,7 +263,7 @@ seq_putc(seq, '\n'); } - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); return 0; } diff -Nru a/net/core/netpoll.c b/net/core/netpoll.c --- a/net/core/netpoll.c 2005-01-23 21:02:28 -08:00 +++ b/net/core/netpoll.c 2005-01-23 21:02:28 -08:00 @@ -188,7 +188,7 @@ return; } - spin_lock_irq(&np->dev->xmit_lock); + spin_lock(&np->dev->xmit_lock); np->dev->xmit_lock_owner = smp_processor_id(); /* @@ -197,7 +197,7 @@ */ if (netif_queue_stopped(np->dev)) { np->dev->xmit_lock_owner = -1; - spin_unlock_irq(&np->dev->xmit_lock); + spin_unlock(&np->dev->xmit_lock); netpoll_poll(np); goto repeat; @@ -205,7 +205,7 @@ status = np->dev->hard_start_xmit(skb, np->dev); np->dev->xmit_lock_owner = -1; - spin_unlock_irq(&np->dev->xmit_lock); + spin_unlock(&np->dev->xmit_lock); /* transmit busy */ if(status) { diff -Nru a/net/core/pktgen.c b/net/core/pktgen.c --- a/net/core/pktgen.c 2005-01-23 21:02:28 -08:00 +++ b/net/core/pktgen.c 2005-01-23 21:02:28 -08:00 @@ -2664,11 +2664,12 @@ } } - spin_lock_irq(&odev->xmit_lock); + spin_lock_bh(&odev->xmit_lock); if (!netif_queue_stopped(odev)) { u64 now; atomic_inc(&(pkt_dev->skb->users)); +retry_now: ret = odev->hard_start_xmit(pkt_dev->skb, odev); if (likely(ret == NETDEV_TX_OK)) { pkt_dev->last_ok = 1; @@ -2676,6 +2677,10 @@ pkt_dev->seq_num++; pkt_dev->tx_bytes += pkt_dev->cur_pkt_size; + } else if (ret == NETDEV_TX_LOCKED + && (odev->features & NETIF_F_LLTX)) { + cpu_relax(); + goto retry_now; } else { /* Retry it next time */ atomic_dec(&(pkt_dev->skb->users)); @@ -2711,7 +2716,7 @@ pkt_dev->next_tx_ns = 0; } - spin_unlock_irq(&odev->xmit_lock); + spin_unlock_bh(&odev->xmit_lock); /* If pkt_dev->count is zero, then run forever */ if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) { diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c --- a/net/netlink/af_netlink.c 2005-01-23 21:02:28 -08:00 +++ b/net/netlink/af_netlink.c 2005-01-23 21:02:28 -08:00 @@ -91,12 +91,12 @@ struct netlink_table { struct nl_pid_hash hash; struct hlist_head mc_list; + unsigned int nl_nonroot; }; static struct netlink_table *nl_table; static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); -static unsigned int nl_nonroot[MAX_LINKS]; static int netlink_dump(struct sock *sk); static void netlink_destroy_callback(struct netlink_callback *cb); @@ -438,7 +438,7 @@ static inline int netlink_capable(struct socket *sock, unsigned int flag) { - return (nl_nonroot[sock->sk->sk_protocol] & flag) || + return (nl_table[sock->sk->sk_protocol].nl_nonroot & flag) || capable(CAP_NET_ADMIN); } @@ -1066,7 +1066,7 @@ void netlink_set_nonroot(int protocol, unsigned int flags) { if ((unsigned int)protocol < MAX_LINKS) - nl_nonroot[protocol] = flags; + nl_table[protocol].nl_nonroot = flags; } static void netlink_destroy_callback(struct netlink_callback *cb) diff -Nru a/net/sched/sch_generic.c b/net/sched/sch_generic.c --- a/net/sched/sch_generic.c 2005-01-23 21:02:28 -08:00 +++ b/net/sched/sch_generic.c 2005-01-23 21:02:28 -08:00 @@ -99,11 +99,17 @@ if ((skb = q->dequeue(q)) != NULL) { unsigned nolock = (dev->features & NETIF_F_LLTX); /* - * When the driver has LLTX set it does not require any - * locking in start_xmit. + * When the driver has LLTX set it does its own locking + * in start_xmit. No need to add additional overhead by + * locking again. These checks are worth it because + * even uncongested locks can be quite expensive. + * The driver can do trylock like here too, in case + * of lock congestion it should return -1 and the packet + * will be requeued. */ if (!nolock) { - if (!spin_trylock_irq(&dev->xmit_lock)) { + if (!spin_trylock(&dev->xmit_lock)) { + collision: /* So, someone grabbed the driver. */ /* It may be transient configuration error, @@ -137,18 +143,22 @@ if (ret == NETDEV_TX_OK) { if (!nolock) { dev->xmit_lock_owner = -1; - spin_unlock_irq(&dev->xmit_lock); + spin_unlock(&dev->xmit_lock); } spin_lock(&dev->queue_lock); return -1; } + if (ret == NETDEV_TX_LOCKED && nolock) { + spin_lock(&dev->queue_lock); + goto collision; + } } /* NETDEV_TX_BUSY - we need to requeue */ /* Release the driver */ if (!nolock) { dev->xmit_lock_owner = -1; - spin_unlock_irq(&dev->xmit_lock); + spin_unlock(&dev->xmit_lock); } spin_lock(&dev->queue_lock); q = dev->qdisc; @@ -176,7 +186,7 @@ { struct net_device *dev = (struct net_device *)arg; - spin_lock_irq(&dev->xmit_lock); + spin_lock(&dev->xmit_lock); if (dev->qdisc != &noop_qdisc) { if (netif_device_present(dev) && netif_running(dev) && @@ -190,7 +200,7 @@ dev_hold(dev); } } - spin_unlock_irq(&dev->xmit_lock); + spin_unlock(&dev->xmit_lock); dev_put(dev); } @@ -214,17 +224,17 @@ static void dev_watchdog_up(struct net_device *dev) { - spin_lock_irq(&dev->xmit_lock); + spin_lock_bh(&dev->xmit_lock); __netdev_watchdog_up(dev); - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); } static void dev_watchdog_down(struct net_device *dev) { - spin_lock_irq(&dev->xmit_lock); + spin_lock_bh(&dev->xmit_lock); if (del_timer(&dev->watchdog_timer)) __dev_put(dev); - spin_unlock_irq(&dev->xmit_lock); + spin_unlock_bh(&dev->xmit_lock); } /* "NOOP" scheduler: the best scheduler, recommended for all interfaces diff -Nru a/net/sched/sch_teql.c b/net/sched/sch_teql.c --- a/net/sched/sch_teql.c 2005-01-23 21:02:28 -08:00 +++ b/net/sched/sch_teql.c 2005-01-23 21:02:28 -08:00 @@ -301,12 +301,12 @@ switch (teql_resolve(skb, skb_res, slave)) { case 0: - if (spin_trylock_irq(&slave->xmit_lock)) { + if (spin_trylock(&slave->xmit_lock)) { slave->xmit_lock_owner = smp_processor_id(); if (!netif_queue_stopped(slave) && slave->hard_start_xmit(skb, slave) == 0) { slave->xmit_lock_owner = -1; - spin_unlock_irq(&slave->xmit_lock); + spin_unlock(&slave->xmit_lock); master->slaves = NEXT_SLAVE(q); netif_wake_queue(dev); master->stats.tx_packets++; @@ -314,7 +314,7 @@ return 0; } slave->xmit_lock_owner = -1; - spin_unlock_irq(&slave->xmit_lock); + spin_unlock(&slave->xmit_lock); } if (netif_queue_stopped(dev)) busy = 1;