From: Linus Torvalds Date: Fri, 23 Nov 2007 20:28:48 +0000 (-0500) Subject: Import 2.3.30pre1 X-Git-Tag: 2.3.30pre1 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=026ae7875bd6529f96224bd1fe570ef8ec973f25;p=history.git Import 2.3.30pre1 --- diff --git a/CREDITS b/CREDITS index 219d23734696..c2de4b2ac235 100644 --- a/CREDITS +++ b/CREDITS @@ -1468,8 +1468,10 @@ S: Victoria 3163 S: Australia N: Pauline Middelink -E: middelin@polyware.iaf.nl +E: middelin@polyware.nl D: General low-level bug fixes, /proc fixes, identd support +D: Author of IP masquerading +D: Zoran ZR36120 Video For Linux driver S: Boterkorfhoek 34 S: 7546 JA Enschede S: Netherlands diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index f29b280e4152..20599cac7ab3 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -69,12 +69,12 @@ isdn/ - directory with info on the Linux ISDN support, and supported cards. java.txt - info on the in-kernel binary support for Java(tm) -joystick.txt - - info on using joystick devices (and driver) with Linux. joystick-api.txt - API specification for applications that will be using the joystick. joystick-parport.txt - info on how to hook joysticks/gamepads to the parallel port. +joystick.txt + - info on using joystick devices (and driver) with Linux. kbuild/ - directory with info about the kernel build process kernel-docs.txt @@ -127,8 +127,6 @@ pcwd-watchdog.txt - info and sample code for using with the PC Watchdog reset card. powerpc/ - directory with info on using Linux with the PowerPC. -proc.txt - - detailed info on Linux's /proc filesystem. proc_usb_info.txt - info on /proc/bus/usb direcory generated for USB devices ramdisk.txt @@ -178,4 +176,3 @@ watchdog.txt xterm-linux.xpm - XPM image of penguin logo (see logo.txt) sitting on an xterm. - diff --git a/Documentation/Configure.help b/Documentation/Configure.help index e79a4e7add17..52aa2370d4f7 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -12447,6 +12447,18 @@ CONFIG_VIDEO_BT848 whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +ZR36120/36125 Video for Linux +CONFIG_VIDEO_ZR36120 + Support for ZR36120/ZR36125 based frame grabber/overlay boards. + This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV, + and Buster boards. Please read the material in + Documentation/video4linux/zr36120.txt for more information. + + This driver is also available as a module called zr36120.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read Documentation/modules.txt. + SAA5249 Teletext processor CONFIG_VIDEO_SAA5249 Support for I2C bus based teletext using the SAA5249 chip. At the diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX index b4ffac0228b8..a5312faaf7e2 100644 --- a/Documentation/filesystems/00-INDEX +++ b/Documentation/filesystems/00-INDEX @@ -18,6 +18,8 @@ ncpfs.txt - info on Novell Netware(tm) filesystem using NCP protocol. ntfs.txt - info and mount options for the NTFS filesystem (Windows NT). +proc.txt + - info on Linux's /proc filesystem. romfs.txt - Description of the ROMFS filesystem. smbfs.txt diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index be39d93e40b8..59de4ac195ca 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -58,8 +58,6 @@ net-modules.txt - info and "insmod" parameters for all network driver modules. policy-routing.txt - IP policy-based routing -ppp.txt - - info on what software you should use to run PPP. pt.txt - the Gracilis Packetwin AX.25 device driver routing.txt diff --git a/Documentation/sound/CMI8338 b/Documentation/sound/CMI8338 index 85dfd1c911ab..70423953c9f2 100644 --- a/Documentation/sound/CMI8338 +++ b/Documentation/sound/CMI8338 @@ -1,5 +1,22 @@ Audio driver for CM8338/CM8738 chips by Chen-Li Tien + +HARDWARE SUPPORTED +================================================================================ +C-Media CMI8338 +C-Media CMI8738 +On-board C-Media chips + + +WHAT'S NEW +================================================================================ + + 1. Support modem interface for 8738. (select in kernel configuration) + 2. Enable S/PDIF-in to S/PDIF-out (S/PDIF loop). + 3. Enable 4 channels analog duplicate mode on 3 jack or 4 jack + configurateion. + + Be aware: C-Media Electronics Inc. is basically an IC design house, and whose development of software drivers is mainly for use by its OEM customers in their products. C-Media Electronics Inc. itself does not @@ -27,6 +44,23 @@ Audio driver for CM8338/CM8738 chips by Chen-Li Tien 7. To install the driver, enter 'modprobe cmpci'. -Bugs: +DRIVER PARAMETERS +================================================================================ + + Some functions for the cm8738 can be configured in Kernel Configuration + or modules parameters. Set these parameters to 1 to enable. + + spdif_loop: Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out + directly. + four_ch: Enable 4 channels mode, rear-out or line-in will output + the same as line-out. + rear_out: Enable this if you have independent rear-out jacket on + your sound card, otherwise line-in will be used as + rear-out. + modem: You will need to set this parameter if you want to use + the HSP modem. You need install the pctel.o, the modem + driver itself. -1. Real player cannot be run (the same as es1371). + (You will need to get the pctel driver (binary only) and the support for + this option from the CMI site. It is not included in the Linux kernel + proper as it is non-free). diff --git a/Documentation/video4linux/zr36120.txt b/Documentation/video4linux/zr36120.txt new file mode 100644 index 000000000000..a028f2b543ca --- /dev/null +++ b/Documentation/video4linux/zr36120.txt @@ -0,0 +1,159 @@ +Driver for Trust Computer Products Framegrabber, version 0.6.1 +------ --- ----- -------- -------- ------------ ------- - - - + +- ZORAN ------------------------------------------------------ + Author: Pauline Middelink + Date: 18 September 1999 +Version: 0.6.1 + +- Description ------------------------------------------------ + +Video4Linux compatible driver for an unknown brand framegrabber +(Sold in the Netherlands by TRUST Computer Products) and various +other zoran zr36120 based framegrabbers. + +The card contains a ZR36120 Multimedia PCI Interface and a Philips +SAA7110 Onechip Frontend videodecoder. There is also an DSP of +which I have forgotten the number, since i will never get that thing +to work without specs from the vendor itself. + +The SAA711x are capable of processing 6 different video inputs, +CVBS1..6 and Y1+C1, Y2+C2, Y3+C3. All in 50/60Hz, NTSC, PAL or +SECAM and delivering a YUV datastream. On my card the input +'CVBS-0' corresponds to channel CVBS2 and 'S-Video' to Y2+C2. + +I have some reports of other cards working with the mentioned +chip sets. For a list of other working cards please have a look +at the cards named in the tvcards struct in the beginning of +zr36120.c + +After some testing, I discovered that the carddesigner messed up +on the I2C interface. The Zoran chip includes 2 lines SDA and SCL +which (s)he connected reversely. So we have to clock on the SDA +and r/w data on the SCL pin. Life is fun... Each cardtype now has +a bit which signifies if you have a card with the same deficiancy. + +Oh, for the completness of this story I must mention that my +card delivers the VSYNC pulse of the SAA chip to GIRQ1, not +GIRQ0 as some other cards have. This is also incorperated in +the driver be clearing/setting the 'useirq1' bit in the tvcard +description. + +Another problems of contingious capturing data with a Zoran chip +is something nasty inside the chip. It effectively halves the +fps we ought to get... Here is the scenario: capturing frames +to memory is done in the so-called snapshot mode. In this mode +the Zoran stops after capturing a frame worth of data and wait +till the application set GRAB bit to indicate readyness for the +next frame. After detecting a set bit, the chip neetly waits +till the start of a frame, captures it and it goes back to off. +Smart ppl will notice the problem here. Its the waiting on the +_next_ frame each time we set the GRAB bit... Oh well, 12,5 fps +is still plenty fast for me. +-- update 28/7/1999 -- +Don't believe a word I just said... Proof is the output +of `streamer -t 300 -r 25 -f avi15 -o /dev/null` + ++--+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- 25/25 + +-s+-+-+-+-+-+-+-+-+-+-+-+-+-s+-+-+-+-+-+-+-+-+-+-+- + syncer: done + writer: done +(note the /dev/null is prudent here, my system is not able to + grab /and/ write 25 fps to a file... gifts welcome :) ) +The technical reasoning follows: The zoran completed the last +frame, the VSYNC goes low, and GRAB is cleared. The interrupt +routine starts to work since its VSYNC driven, and again +activates the GRAB bit. A few ms later the VSYNC (re-)rises and +the zoran starts to work on a new and freshly broadcasted frame.... + +For pointers I used the specs of both chips. Below are the URLs: + http://www.zoran.com/ftp/download/devices/pci/ZR36120/36120data.pdf + http://www-us.semiconductor.philips.com/acrobat/datasheets/SAA_7110_A_1.pdf + +The documentation has very little on absolute numbers or timings +needed for the various modes/resolutions, but there are other +programs you can borrow those from. + +------ Install -------------------------------------------- +Read the file called TODO. Note its long list of limitations. + +Build a kernel with VIDEO4LINUX enabled. Activate the +BT848 driver; we need this because we have need for the +other modules (i2c and videodev) it enables. + +To install this software, extract it into a suitable directory. +Examine the makefile and change anything you don't like. Type "make". + +After making the modules check if you have the much needed +/dev/video devices. If not, execute the following 4 lines: + mknod /dev/video c 81 0 + mknod /dev/video1 c 81 1 + mknod /dev/video2 c 81 2 + mknod /dev/video3 c 81 3 + mknod /dev/video4 c 81 4 + +After makeing/checking the devices do: + modprobe i2c + modprobe videodev + modprobe saa7110 (optional) + modprobe saa7111 (optional) + modprobe tuner (optional) + insmod zoran cardtype= + + is the cardtype of the card you have. The cardnumber can +be found in the source of zr36120. Look for tvcards. If your +card is not there, please try if any other card gives some +response, and mail me if you got a working tvcard addition. + +PS. > PAGE_SHIFT) #define PFN_PHYS(x) ((x) << PAGE_SHIFT) #define PFN_MAX PFN_DOWN(0x80000000) +#define for_each_mem_cluster(memdesc, cluster, i) \ + for ((cluster) = (memdesc)->cluster, (i) = 0; \ + (i) < (memdesc)->numclusters; (i)++, (cluster)++) static void __init setup_memory(void) { struct memclust_struct * cluster; struct memdesc_struct * memdesc; - unsigned long start_pfn, bootmap_size; + unsigned long start_pfn, bootmap_size, bootmap_pages, bootmap_start; + unsigned long start, end; extern char _end[]; int i; - /* alloc the bootmem after the kernel */ - start_pfn = PFN_UP(virt_to_phys(_end)); - SRM_printf("_end %p\n", _end); - /* find free clusters, and init and free the bootmem accordingly */ memdesc = (struct memdesc_struct *) (hwrpb->mddt_offset + (unsigned long) hwrpb); - for (cluster = memdesc->cluster, i = memdesc->numclusters; - i > 0; i--, cluster++) + for_each_mem_cluster(memdesc, cluster, i) { - unsigned long end; - - printk("memcluster %d, usage %02lx, start %8lu, end %8lu\n", + printk("memcluster %d, usage %01lx, start %8lu, end %8lu\n", i, cluster->usage, cluster->start_pfn, - cluster->numpages); + cluster->start_pfn + cluster->numpages); /* Bit 0 is console/PALcode reserved. Bit 1 is non-volatile memory -- we might want to mark @@ -226,38 +223,89 @@ static void __init setup_memory(void) /* Enforce maximum of 2GB even if there is more. Blah. */ if (max_low_pfn > PFN_MAX) max_low_pfn = PFN_MAX; - SRM_printf("max_low_pfn %d\n", max_low_pfn); + printk("max_low_pfn %ld\n", max_low_pfn); - /* allocate the bootmem array after the kernel and mark - the whole MM as reserved */ - bootmap_size = init_bootmem(start_pfn, max_low_pfn); + /* find the end of the kernel memory */ + start_pfn = PFN_UP(virt_to_phys(_end)); + printk("_end %p, start_pfn %ld\n", _end, start_pfn); - for (cluster = memdesc->cluster, i = memdesc->numclusters; - i > 0; i--, cluster++) - { - unsigned long end, start; + bootmap_start = -1; - /* Bit 0 is console/PALcode reserved. Bit 1 is - non-volatile memory -- we might want to mark - this for later */ + try_again: + if (max_low_pfn <= start_pfn) + panic("not enough memory to boot"); + + /* we need to know how many physically contigous pages + we'll need for the bootmap */ + bootmap_pages = bootmem_bootmap_pages(max_low_pfn); + printk("bootmap size: %ld pages\n", bootmap_pages); + + /* now find a good region where to allocate the bootmap */ + for_each_mem_cluster(memdesc, cluster, i) + { if (cluster->usage & 3) continue; - start = PFN_PHYS(cluster->start_pfn); - if (start < PFN_PHYS(start_pfn) + bootmap_size) - start = PFN_PHYS(start_pfn) + bootmap_size; - if (PFN_DOWN(start) >= PFN_MAX) + start = cluster->start_pfn; + end = start + cluster->numpages; + if (end <= start_pfn) + continue; + if (start >= max_low_pfn) + continue; + if (start < start_pfn) + start = start_pfn; + if (end > max_low_pfn) + end = max_low_pfn; + if (end - start >= bootmap_pages) + { + printk("allocating bootmap in area %ld:%ld\n", + start, start+bootmap_pages); + bootmap_start = start; + break; + } + } + + if (bootmap_start == -1) + { + max_low_pfn >>= 1; + printk("bootmap area not found now trying with %ld pages\n", + max_low_pfn); + goto try_again; + } + + /* allocate the bootmap and mark the whole MM as reserved */ + bootmap_size = init_bootmem(bootmap_start, max_low_pfn); + + /* mark the free regions */ + for_each_mem_cluster(memdesc, cluster, i) + { + if (cluster->usage & 3) continue; - end = PFN_PHYS(cluster->start_pfn + cluster->numpages); - if (PFN_DOWN(end) > PFN_MAX) - end = PFN_PHYS(PFN_MAX); + start = cluster->start_pfn; + if (start < start_pfn) + start = start_pfn; + + end = cluster->start_pfn + cluster->numpages; + if (end > max_low_pfn) + end = max_low_pfn; if (start >= end) continue; - free_bootmem(start, end-start); + + start = PFN_PHYS(start); + end = PFN_PHYS(end); + + free_bootmem(start, end - start); + printk("freeing pages %ld:%ld\n", + PFN_UP(start), PFN_DOWN(end)); } + /* reserve the bootmap memory */ + reserve_bootmem(PFN_PHYS(bootmap_start), bootmap_size); + printk("reserving bootmap %ld:%ld\n", bootmap_start, + bootmap_start + PFN_UP(bootmap_size)); + #ifdef CONFIG_BLK_DEV_INITRD initrd_start = INITRD_START; if (initrd_start) { @@ -355,10 +403,6 @@ setup_arch(char **cmdline_p) alpha_using_srm = strncmp((const char *)hwrpb->ssn, "MILO", 4) != 0; #endif - SRM_printf("Booting on %s%s%s using machine vector %s\n", - type_name, (*var_name ? " variation " : ""), - var_name, alpha_mv.vector_name); - printk("Booting " #ifdef CONFIG_ALPHA_GENERIC "GENERIC " diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index 105963a334c5..f1635118adb5 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -212,7 +212,7 @@ void paging_init(void) zones_size[ZONE_DMA] = high_pfn; else { - zones_size[0] = dma_pfn; + zones_size[ZONE_DMA] = dma_pfn; zones_size[ZONE_NORMAL] = high_pfn - dma_pfn; } @@ -278,7 +278,7 @@ mem_init(void) { max_mapnr = num_physpages = max_low_pfn; totalram_pages += free_all_bootmem(); - printk("Memory: %luk available\n", totalram_pages >> 10); + printk("Memory: %luk available\n", totalram_pages << (PAGE_SHIFT-10)); } void diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 9fb8bcd3a0b7..5ed9255f6a79 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -940,7 +940,7 @@ void print_all_local_APICs (void) print_local_APIC(NULL); } -static void __init init_sym_mode(void) +static void __init enable_IO_APIC(void) { struct IO_APIC_reg_01 reg_01; int i; @@ -976,31 +976,15 @@ static void __init init_sym_mode(void) clear_IO_APIC(); } -static void clear_lapic_ints (void * dummy) -{ - int maxlvt; - - maxlvt = get_maxlvt(); - apic_write_around(APIC_LVTT, 0x00010000); - apic_write_around(APIC_LVT0, 0x00010000); - apic_write_around(APIC_LVT1, 0x00010000); - if (maxlvt >= 3) - apic_write_around(APIC_LVTERR, 0x00010000); - if (maxlvt >= 4) - apic_write_around(APIC_LVTPC, 0x00010000); -} - /* * Not an __init, needed by the reboot code */ -void init_pic_mode(void) +void disable_IO_APIC(void) { /* - * Clear the IO-APIC and local APICs before rebooting: + * Clear the IO-APIC before rebooting: */ clear_IO_APIC(); - smp_call_function(clear_lapic_ints, NULL, 1, 1); - clear_lapic_ints(NULL); /* * Put it back into PIC mode (has an effect only on @@ -1379,8 +1363,10 @@ static inline void check_timer(void) } printk(" failed.\n"); - if (nmi_watchdog) - printk("timer doesnt work through the IO-APIC - cannot activate NMI Watchdog!\n"); + if (nmi_watchdog) { + printk("timer doesnt work through the IO-APIC - disabling NMI Watchdog!\n"); + nmi_watchdog = 0; + } printk("...trying to set up timer as Virtual Wire IRQ..."); @@ -1417,7 +1403,7 @@ static inline void check_timer(void) void __init setup_IO_APIC(void) { - init_sym_mode(); + enable_IO_APIC(); printk("ENABLING IO-APIC IRQs\n"); io_apic_irqs = ~PIC_IRQS; diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index e9feeca3ad97..854cff8d8345 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -263,7 +263,7 @@ static inline void wait_on_bh(void) * i thought that such things are guaranteed by design, since we use * the 'LOCK' prefix. */ -#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 1 +#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0 #if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND # define SYNC_OTHER_CORES(x) udelay(x+1) diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 429c4eacd9b1..680563959e2c 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -204,9 +204,11 @@ void machine_restart(char * __unused) { #if __SMP__ /* - * turn off the IO-APIC, so we can do a clean reboot + * Stop all CPUs and turn off local APICs and the IO-APIC, so + * other OSs see a clean IRQ state. */ - init_pic_mode(); + smp_send_stop(); + disable_IO_APIC(); #endif if(!reboot_thru_bios) { diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 8e4ecd7f4177..92113b559c01 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -439,9 +439,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, if (down_trylock(&lock)) return -EBUSY; - if (call_data) // temporary debugging check - BUG(); - call_data = &data; data.func = func; data.info = info; @@ -478,7 +475,8 @@ static void stop_this_cpu (void * dummy) * Remove this CPU: */ clear_bit(smp_processor_id(), &cpu_online_map); - + __cli(); + disable_local_APIC(); if (cpu_data[smp_processor_id()].hlt_works_ok) for(;;) __asm__("hlt"); for (;;); @@ -490,7 +488,14 @@ static void stop_this_cpu (void * dummy) void smp_send_stop(void) { + unsigned long flags; + + __save_flags(flags); + __cli(); smp_call_function(stop_this_cpu, NULL, 1, 0); + disable_local_APIC(); + __restore_flags(flags); + } /* @@ -539,7 +544,7 @@ asmlinkage void smp_call_function_interrupt(void) */ atomic_inc(&call_data->started); /* - * At this point the structure may be out of scope unless wait==1 + * At this point the info structure may be out of scope unless wait==1 */ (*func)(info); if (wait) @@ -575,8 +580,27 @@ asmlinkage void smp_error_interrupt(void) printk("... APIC ESR0: %08lx\n", v); apic_write(APIC_ESR, 0); - v = apic_read(APIC_ESR); + v |= apic_read(APIC_ESR); printk("... APIC ESR1: %08lx\n", v); + /* + * Be a bit more verbose. (multiple bits can be set) + */ + if (v & 0x01) + printk("... bit 0: APIC Send CS Error (hw problem).\n"); + if (v & 0x02) + printk("... bit 1: APIC Receive CS Error (hw problem).\n"); + if (v & 0x04) + printk("... bit 2: APIC Send Accept Error.\n"); + if (v & 0x08) + printk("... bit 3: APIC Receive Accept Error.\n"); + if (v & 0x10) + printk("... bit 4: Reserved!.\n"); + if (v & 0x20) + printk("... bit 5: Send Illegal Vector (kernel bug).\n"); + if (v & 0x40) + printk("... bit 6: Received Illegal Vector.\n"); + if (v & 0x80) + printk("... bit 7: Illegal Register Address.\n"); ack_APIC_irq(); diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 0f8a4060ab26..811f00f387e9 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -708,7 +708,35 @@ int get_maxlvt(void) return maxlvt; } -void __init setup_local_APIC(void) +void disable_local_APIC (void) +{ + unsigned long value; + int maxlvt; + + /* + * Disable APIC + */ + value = apic_read(APIC_SPIV); + value &= ~(1<<8); + apic_write(APIC_SPIV,value); + + /* + * Clean APIC state for other OSs: + */ + value = apic_read(APIC_SPIV); + value &= ~(1<<8); + apic_write(APIC_SPIV,value); + maxlvt = get_maxlvt(); + apic_write_around(APIC_LVTT, 0x00010000); + apic_write_around(APIC_LVT0, 0x00010000); + apic_write_around(APIC_LVT1, 0x00010000); + if (maxlvt >= 3) + apic_write_around(APIC_LVTERR, 0x00010000); + if (maxlvt >= 4) + apic_write_around(APIC_LVTPC, 0x00010000); +} + +void __init setup_local_APIC (void) { unsigned long value, ver, maxlvt; @@ -716,12 +744,25 @@ void __init setup_local_APIC(void) __error_in_io_apic_c(); value = apic_read(APIC_SPIV); - value = 0xf; /* * Enable APIC */ value |= (1<<8); -#if 1 + + /* + * Some unknown Intel IO/APIC (or APIC) errata is biting us with + * certain networking cards. If high frequency interrupts are + * happening on a particular IOAPIC pin, plus the IOAPIC routing + * entry is masked/unmasked at a high rate as well then sooner or + * later IOAPIC line gets 'stuck', no more interrupts are received + * from the device. If focus CPU is disabled then the hang goes + * away, oh well :-( + * + * [ This bug can be reproduced easily with a level-triggered + * PCI Ne2000 networking cards and PII/PIII processors, dual + * BX chipset. ] + */ +#if 0 /* Enable focus processor (bit==0) */ value &= ~(1<<9); #else diff --git a/arch/i386/kernel/visws_apic.c b/arch/i386/kernel/visws_apic.c index 6c767d0ebff8..be80cd628f09 100644 --- a/arch/i386/kernel/visws_apic.c +++ b/arch/i386/kernel/visws_apic.c @@ -104,7 +104,7 @@ static struct hw_interrupt_type cobalt_irq_type = { /* * Not an __init, needed by the reboot code */ -void init_pic_mode(void) +void disable_IO_APIC(void) { /* Nop on Cobalt */ } diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 11a303ed7b33..bfcf5b39ffe0 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -141,6 +141,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then fi if [ "$CONFIG_PCI" != "n" ]; then dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV + dep_tristate 'Zoran ZR36120/36125 support' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV fi dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then @@ -192,8 +193,9 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi - dep_tristate ' Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV + dep_tristate ' Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN + dep_tristate ' Zoran ZR36120/36125 support' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI fi endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4c3ed132ffea..f85f22b51e10 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -348,6 +348,9 @@ else endif endif +# +# for external dependencies in arm/config.in and video/config.in +# ifeq ($(CONFIG_BUS_I2C),y) L_I2C=y else @@ -357,12 +360,28 @@ else endif ifeq ($(CONFIG_VIDEO_BT848),y) -O_OBJS += bttv.o msp3400.o tuner.o +O_OBJS += bttv.o msp3400.o L_I2C=y +L_TUNERS=y else ifeq ($(CONFIG_VIDEO_BT848),m) - M_OBJS += bttv.o msp3400.o tuner.o + M_OBJS += bttv.o msp3400.o + M_I2C=y + M_TUNERS=y + endif +endif + +ifeq ($(CONFIG_VIDEO_ZR36120),y) +O_OBJS += zoran.o +L_I2C=y +L_TUNERS=y +L_DECODERS=y +else + ifeq ($(CONFIG_VIDEO_ZR36120),m) + M_OBJS += zoran.o M_I2C=y + M_TUNERS=y + M_DECODERS=y endif endif @@ -404,9 +423,13 @@ endif ifeq ($(CONFIG_VIDEO_ZORAN),y) O_OBJS += buz.o +L_I2C=y +L_DECODERS=y else ifeq ($(CONFIG_VIDEO_ZORAN),m) M_OBJS += buz.o + M_I2C=y + M_DECODERS=y endif endif @@ -418,14 +441,6 @@ else endif endif -ifeq ($(CONFIG_VIDEO_BUZ),y) -O_OBJS += saa7111.o saa7185.o -else - ifeq ($(CONFIG_VIDEO_BUZ),m) - M_OBJS += saa7111.o saa7185.o - endif -endif - ifeq ($(CONFIG_VIDEO_PMS),y) O_OBJS += pms.o else @@ -578,11 +593,31 @@ else endif endif + +# set when a framegrabber supports external tuners +ifeq ($(L_TUNERS),y) +O_OBJS += tuner.o +else + ifeq ($(M_TUNERS),y) + M_OBJS += tuner.o + endif +endif + +# set when a framegrabber supports external decoders +ifeq ($(L_DECODERS),y) +O_OBJS += saa7110.o saa7111.o saa7185.o +else + ifeq ($(M_DECODERS),y) + M_OBJS += saa7110.o saa7111.o saa7185.o + endif +endif + +# set when a framegrabber implements i2c support ifeq ($(L_I2C),y) OX_OBJS += i2c.o else - ifeq ($(M_I2C),y) - MX_OBJS += i2c.o + ifeq ($(M_I2C),y) + MX_OBJS += i2c.o endif endif @@ -615,3 +650,5 @@ consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h defkeymap.c: defkeymap.map loadkeys --mktable defkeymap.map > defkeymap.c +zoran.o: zr36120.o zr36120_i2c.o zr36120_mem.o + $(LD) $(LD_RFLAG) -r -o $@ zr36120.o zr36120_i2c.o zr36120_mem.o diff --git a/drivers/char/buz.c b/drivers/char/buz.c index 91c131c56766..de688ae0b340 100644 --- a/drivers/char/buz.c +++ b/drivers/char/buz.c @@ -3035,7 +3035,7 @@ static struct video_device zoran_template = BUZ_NAME, VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | VID_TYPE_SCALES | VID_TYPE_SUBCAPTURE, - VID_HARDWARE_BT848, /* Not true, but the buz is not yet in the list */ + VID_HARDWARE_ZR36067, zoran_open, zoran_close, zoran_read, diff --git a/drivers/char/mem.c b/drivers/char/mem.c index bf8d57e9ce71..5d907e300bed 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -56,9 +56,6 @@ extern void adbdev_init(void); #ifdef CONFIG_USB extern void usb_init(void); #endif -#ifdef CONFIG_PPDEV -extern int pp_init(void); -#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -675,9 +672,6 @@ int __init chr_dev_init(void) #endif #ifdef CONFIG_VIDEO_DEV videodev_init(); -#endif -#ifdef CONFIG_PPDEV - pp_init(); #endif return 0; } diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 5afcec0c9e63..71bb3a18c409 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -43,6 +43,7 @@ */ #include +#include #include #include #include @@ -578,11 +579,7 @@ static struct file_operations pp_fops = { pp_release }; -#ifdef MODULE -#define pp_init init_module -#endif - -int pp_init (void) +static int __init ppdev_init (void) { if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { printk (KERN_WARNING CHRDEV ": unable to get major %d\n", @@ -594,10 +591,11 @@ int pp_init (void) return 0; } -#ifdef MODULE -void cleanup_module (void) +static void __exit ppdev_cleanup (void) { /* Clean up all parport stuff */ unregister_chrdev (PP_MAJOR, CHRDEV); } -#endif /* MODULE */ + +module_init(ppdev_init); +module_exit(ppdev_cleanup); diff --git a/drivers/char/saa7110.c b/drivers/char/saa7110.c new file mode 100644 index 000000000000..6a0402f67312 --- /dev/null +++ b/drivers/char/saa7110.c @@ -0,0 +1,429 @@ +/* + saa7110 - Philips SAA7110(A) video decoder driver + + Copyright (C) 1998 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "linux/video_decoder.h" + +#define DEBUG(x...) x /* remove when no long debugging */ + +#define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ +#define SAA7110_MAX_OUTPUT 0 /* its a decoder only */ + +#define I2C_SAA7110 0x9C /* or 0x9E */ + +#define I2C_DELAY 10 /* 10 us or 100khz */ + +struct saa7110 { + struct i2c_bus *bus; + int addr; + unsigned char reg[36]; + + int norm; + int input; + int enable; + int bright; + int contrast; + int hue; + int sat; +}; + +/* ----------------------------------------------------------------------- */ +/* I2C support functions */ +/* ----------------------------------------------------------------------- */ +static +int saa7110_write(struct saa7110 *decoder, unsigned char subaddr, unsigned char data) +{ + int ack; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); + i2c_sendbyte(decoder->bus, subaddr, I2C_DELAY); + ack = i2c_sendbyte(decoder->bus, data, I2C_DELAY); + i2c_stop(decoder->bus); + decoder->reg[subaddr] = data; + UNLOCK_I2C_BUS(decoder->bus); + return ack; +} + +static +int saa7110_write_block(struct saa7110* decoder, unsigned const char *data, unsigned int len) +{ + unsigned subaddr = *data; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus,decoder->addr,I2C_DELAY); + while (len-- > 0) { + if (i2c_sendbyte(decoder->bus,*data,0)) { + i2c_stop(decoder->bus); + return -EAGAIN; + } + decoder->reg[subaddr++] = *data++; + } + i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); + + return 0; +} + +static +int saa7110_read(struct saa7110* decoder) +{ + int data; + + LOCK_I2C_BUS(decoder->bus); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr, I2C_DELAY); + i2c_start(decoder->bus); + i2c_sendbyte(decoder->bus, decoder->addr | 1, I2C_DELAY); + data = i2c_readbyte(decoder->bus, 1); + i2c_stop(decoder->bus); + UNLOCK_I2C_BUS(decoder->bus); + return data; +} + +/* ----------------------------------------------------------------------- */ +/* SAA7110 functions */ +/* ----------------------------------------------------------------------- */ +static +int saa7110_selmux(struct i2c_device *device, int chan) +{ +static const unsigned char modes[9][8] = { +/* mode 0 */ { 0x00, 0xD9, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, +/* mode 1 */ { 0x00, 0xD8, 0x17, 0x40, 0x03, 0x44, 0x75, 0x16 }, +/* mode 2 */ { 0x00, 0xBA, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, +/* mode 3 */ { 0x00, 0xB8, 0x07, 0x91, 0x03, 0x60, 0xB5, 0x05 }, +/* mode 4 */ { 0x00, 0x7C, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, +/* mode 5 */ { 0x00, 0x78, 0x07, 0xD2, 0x83, 0x60, 0xB5, 0x03 }, +/* mode 6 */ { 0x80, 0x59, 0x17, 0x42, 0xA3, 0x44, 0x75, 0x12 }, +/* mode 7 */ { 0x80, 0x9A, 0x17, 0xB1, 0x13, 0x60, 0xB5, 0x14 }, +/* mode 8 */ { 0x80, 0x3C, 0x27, 0xC1, 0x23, 0x44, 0x75, 0x21 } }; + struct saa7110* decoder = device->data; + const unsigned char* ptr = modes[chan]; + + saa7110_write(decoder,0x06,ptr[0]); /* Luminance control */ + saa7110_write(decoder,0x20,ptr[1]); /* Analog Control #1 */ + saa7110_write(decoder,0x21,ptr[2]); /* Analog Control #2 */ + saa7110_write(decoder,0x22,ptr[3]); /* Mixer Control #1 */ + saa7110_write(decoder,0x2C,ptr[4]); /* Mixer Control #2 */ + saa7110_write(decoder,0x30,ptr[5]); /* ADCs gain control */ + saa7110_write(decoder,0x31,ptr[6]); /* Mixer Control #3 */ + saa7110_write(decoder,0x21,ptr[7]); /* Analog Control #2 */ + + return 0; +} + +static +int determine_norm(struct i2c_device* dev) +{ + struct saa7110* decoder = dev->data; + int status; + + /* mode changed, start automatic detection */ + status = saa7110_read(decoder); + if ((status & 3) == 0) { + saa7110_write(decoder,0x06,0x80); + if (status & 0x20) { + DEBUG(printk(KERN_INFO "%s: norm=bw60\n",dev->name)); + saa7110_write(decoder,0x2E,0x81); + return VIDEO_MODE_NTSC; + } + DEBUG(printk(KERN_INFO "%s: norm=bw50\n",dev->name)); + saa7110_write(decoder,0x2E,0x9A); + return VIDEO_MODE_PAL; + } + + saa7110_write(decoder,0x06,0x00); + if (status & 0x20) { /* 60Hz */ + DEBUG(printk(KERN_INFO "%s: norm=ntsc\n",dev->name)); + saa7110_write(decoder,0x0D,0x06); + saa7110_write(decoder,0x11,0x2C); + saa7110_write(decoder,0x2E,0x81); + return VIDEO_MODE_NTSC; + } + + /* 50Hz -> PAL/SECAM */ + saa7110_write(decoder,0x0D,0x06); + saa7110_write(decoder,0x11,0x59); + saa7110_write(decoder,0x2E,0x9A); + + mdelay(150); /* pause 150 ms */ + + status = saa7110_read(decoder); + if ((status & 0x03) == 0x01) { + DEBUG(printk(KERN_INFO "%s: norm=secam\n",dev->name)); + saa7110_write(decoder,0x0D,0x07); + return VIDEO_MODE_SECAM; + } + DEBUG(printk(KERN_INFO "%s: norm=pal\n",dev->name)); + return VIDEO_MODE_PAL; +} + +static +int saa7110_attach(struct i2c_device *device) +{ +static const unsigned char initseq[] = { + 0, 0x4C, 0x3C, 0x0D, 0xEF, 0xBD, 0xF0, 0x00, 0x00, + 0xF8, 0xF8, 0x60, 0x60, 0x00, 0x06, 0x18, 0x90, + 0x00, 0x2C, 0x40, 0x46, 0x42, 0x1A, 0xFF, 0xDA, + 0xF0, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xD9, 0x17, 0x40, 0x41, 0x80, 0x41, 0x80, 0x4F, + 0xFE, 0x01, 0xCF, 0x0F, 0x03, 0x01, 0x81, 0x03, + 0x40, 0x75, 0x01, 0x8C, 0x03}; + struct saa7110* decoder; + int rv; + + device->data = decoder = kmalloc(sizeof(struct saa7110), GFP_KERNEL); + if (device->data == 0) + return -ENOMEM; + + MOD_INC_USE_COUNT; + + /* clear our private data */ + memset(decoder, 0, sizeof(struct saa7110)); + strcpy(device->name, "saa7110"); + decoder->bus = device->bus; + decoder->addr = device->addr; + decoder->norm = VIDEO_MODE_PAL; + decoder->input = 0; + decoder->enable = 1; + decoder->bright = 32768; + decoder->contrast = 32768; + decoder->hue = 32768; + decoder->sat = 32768; + + rv = saa7110_write_block(decoder, initseq, sizeof(initseq)); + if (rv < 0) + printk(KERN_ERR "%s_attach: init status %d\n", device->name, rv); + else { + saa7110_write(decoder,0x21,0x16); + saa7110_write(decoder,0x0D,0x04); + printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder)); + saa7110_write(decoder,0x0D,0x06); + } + + /* setup and implicit mode 0 select has been performed */ + return 0; +} + +static +int saa7110_detach(struct i2c_device *device) +{ + struct saa7110* decoder = device->data; + + DEBUG(printk(KERN_INFO "%s_detach\n",device->name)); + + /* stop further output */ + saa7110_write(decoder,0x0E,0x00); + + kfree(device->data); + + MOD_DEC_USE_COUNT; + return 0; +} + +static +int saa7110_command(struct i2c_device *device, unsigned int cmd, void *arg) +{ + struct saa7110* decoder = device->data; + int v; + + switch (cmd) { + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *dc = arg; + dc->flags = VIDEO_DECODER_PAL + | VIDEO_DECODER_NTSC + | VIDEO_DECODER_SECAM + | VIDEO_DECODER_AUTO + | VIDEO_DECODER_CCIR; + dc->inputs = SAA7110_MAX_INPUT; + dc->outputs = SAA7110_MAX_OUTPUT; + } + break; + + case DECODER_GET_STATUS: + { + struct saa7110* decoder = device->data; + int status; + int res = 0; + + status = i2c_read(device->bus,device->addr|1); + if (status & 0x40) + res |= DECODER_STATUS_GOOD; + if (status & 0x03) + res |= DECODER_STATUS_COLOR; + + switch (decoder->norm) { + case VIDEO_MODE_NTSC: + res |= DECODER_STATUS_NTSC; + break; + case VIDEO_MODE_PAL: + res |= DECODER_STATUS_PAL; + break; + case VIDEO_MODE_SECAM: + res |= DECODER_STATUS_SECAM; + break; + } + *(int*)arg = res; + } + break; + + case DECODER_SET_NORM: + v = *(int*)arg; + if (decoder->norm != v) { + decoder->norm = v; + saa7110_write(decoder, 0x06, 0x00); + switch (v) { + case VIDEO_MODE_NTSC: + saa7110_write(decoder, 0x0D, 0x06); + saa7110_write(decoder, 0x11, 0x2C); + saa7110_write(decoder, 0x30, 0x81); +saa7110_write(decoder, 0x2A, 0xDF); + break; + case VIDEO_MODE_PAL: + saa7110_write(decoder, 0x0D, 0x06); + saa7110_write(decoder, 0x11, 0x59); + saa7110_write(decoder, 0x2E, 0x9A); + break; + case VIDEO_MODE_SECAM: + saa7110_write(decoder, 0x0D, 0x07); + saa7110_write(decoder, 0x11, 0x59); + saa7110_write(decoder, 0x2E, 0x9A); + break; + case VIDEO_MODE_AUTO: + *(int*)arg = determine_norm(device); + break; + default: + return -EPERM; + } + } + break; + + case DECODER_SET_INPUT: + v = *(int*)arg; + if (v<0 || v>SAA7110_MAX_INPUT) + return -EINVAL; + if (decoder->input != v) { + decoder->input = v; + saa7110_selmux(device, v); + } + break; + + case DECODER_SET_OUTPUT: + v = *(int*)arg; + /* not much choice of outputs */ + if (v != 0) + return -EINVAL; + break; + + case DECODER_ENABLE_OUTPUT: + v = *(int*)arg; + if (decoder->enable != v) { + decoder->enable = v; + saa7110_write(decoder,0x0E, v ? 0x18 : 0x00); + } + break; + + case DECODER_SET_PICTURE: + { + struct video_picture *pic = arg; + + if (decoder->bright != pic->brightness) { + /* We want 0 to 255 we get 0-65535 */ + decoder->bright = pic->brightness; + saa7110_write(decoder, 0x19, decoder->bright >> 8); + } + if (decoder->contrast != pic->contrast) { + /* We want 0 to 127 we get 0-65535 */ + decoder->contrast = pic->contrast; + saa7110_write(decoder, 0x13, decoder->contrast >> 9); + } + if (decoder->sat != pic->colour) { + /* We want 0 to 127 we get 0-65535 */ + decoder->sat = pic->colour; + saa7110_write(decoder, 0x12, decoder->sat >> 9); + } + if (decoder->hue != pic->hue) { + /* We want -128 to 127 we get 0-65535 */ + decoder->hue = pic->hue; + saa7110_write(decoder, 0x07, (decoder->hue>>8)-128); + } + } + break; + + case DECODER_DUMP: + for (v=0; v<34; v+=16) { + int j; + DEBUG(printk(KERN_INFO "%s: %03x\n",device->name,v)); + for (j=0; j<16; j++) { + DEBUG(printk(KERN_INFO " %02x",decoder->reg[v+j])); + } + DEBUG(printk(KERN_INFO "\n")); + } + break; + + default: + DEBUG(printk(KERN_INFO "unknown saa7110_command??(%d)\n",cmd)); + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +struct i2c_driver i2c_driver_saa7110 = +{ + "saa7110", /* name */ + + I2C_DRIVERID_VIDEODECODER, /* in i2c.h */ + I2C_SAA7110, I2C_SAA7110+1, /* Addr range */ + + saa7110_attach, + saa7110_detach, + saa7110_command +}; + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +int saa7110_init(void) +#endif +{ + return i2c_register_driver(&i2c_driver_saa7110); +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_unregister_driver(&i2c_driver_saa7110); +} +#endif diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index 05f2eeeeaead..ab41407bf760 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -54,6 +54,9 @@ extern int init_planbs(struct video_init *); #ifdef CONFIG_VIDEO_ZORAN extern int init_zoran_cards(struct video_init *); #endif +#ifdef CONFIG_VIDEO_ZR36120 +extern int init_zr36120_cards(struct video_init *); +#endif static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_BT848 @@ -71,6 +74,9 @@ static struct video_init video_init_list[]={ #endif #ifdef CONFIG_VIDEO_ZORAN {"zoran", init_zoran_cards}, +#endif +#ifdef CONFIG_VIDEO_ZR36120 + {"zr36120", init_zr36120_cards}, #endif {"end", NULL} }; diff --git a/drivers/char/zr36120.c b/drivers/char/zr36120.c new file mode 100644 index 000000000000..f0cfc5a4f3c0 --- /dev/null +++ b/drivers/char/zr36120.c @@ -0,0 +1,1608 @@ +/* + zr36120.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "linux/video_decoder.h" +#include "tuner.h" +#include "zr36120.h" +#include "zr36120_mem.h" + +/* sensible default */ +#ifndef CARDTYPE +#define CARDTYPE 0 +#endif + +/* Anybody who uses more than four? */ +#define ZORAN_MAX 4 + +static ulong irq1 = 0; + + unsigned int triton1=0; /* triton1 chipset? */ +static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; + +MODULE_AUTHOR("Pauline Middelink "); +MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); +MODULE_PARM(triton1,"i"); +MODULE_PARM(cardtype,"1-" __MODULE_STRING(ZORAN_MAX) "i"); + +static int zoran_cards; +static struct zoran zorans[ZORAN_MAX]; + +/* + * the meaning of each element can be found in zr36120.h + * Determining the value of gpdir/gpval can be tricky. The + * best way is to run the card under the original software + * and read the values from the general purpose registers + * 0x28 and 0x2C. How you do that is left as an exercise + * to the impatient reader :) + */ +#define T 1 /* to seperate the bools from the ints */ +#define F 0 +static struct tvcard tvcards[] = { + /* reported working by */ +/*0*/ { "Trust Victor II", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by */ +/*1*/ { "Aitech WaveWatcher TV-PCI", + 3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } }, + /* reported working by ? */ +/*2*/ { "Genius Video Wonder PCI Video Capture Card", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by */ +/*3*/ { "Guillemot Maxi-TV PCI", + 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, + /* reported working by "Craig Whitmore */ +/*4*/ { "Quadrant Buster", + 3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } }, + /* a debug entry which has all inputs mapped */ +/*5*/ { "ZR36120 based framegrabber (all inputs enabled)", + 6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } } +}; +#undef T +#undef F +#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0])) + +static struct { const char name[8]; int mode; int bpp; } palette2fmt[] = { +/* n/a */ { "n/a", 0, 0 }, +/* GREY */ { "GRAY", 0, 0 }, +/* HI240 */ { "HI240", 0, 0 }, +/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ZORAN_VFEC_LE, 2 }, +/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24, 3 }, +/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE, 4 }, +/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ZORAN_VFEC_LE, 2 }, +/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ZORAN_VFEC_LE, 3 }, +/* YUYV */ { "YUYV", 0, 0 }, +/* UYVY */ { "UYVY", 0, 0 }, +/* YUV420 */ { "YUV420", 0, 0 }, +/* YUV411 */ { "YUV411", 0, 0 }, +/* RAW */ { "RAW", 0, 0 }, +/* YUV422P */ { "YUV422P", 0, 0 }, +/* YUV411P */ { "YUV411P", 0, 0 }}; +#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0])) + +/* ----------------------------------------------------------------------- */ +/* ZORAN chipset detector */ +/* shamelessly stolen from bttv.c */ +/* Reason for beeing here: we need to detect if we are running on a */ +/* Triton based chipset, and if so, enable a certain bit */ +/* ----------------------------------------------------------------------- */ + +void handle_chipset(void) +{ + struct pci_dev *dev = NULL; + + /* Just in case some nut set this to something dangerous */ + if (triton1) + triton1 = ZORAN_VDC_TRICOM; + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) + { + printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n"); + triton1 = ZORAN_VDC_TRICOM; + } +} + +/* ----------------------------------------------------------------------- */ +/* ZORAN functions */ +/* ----------------------------------------------------------------------- */ + +static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i); + +static +void zoran_dump(struct zoran *ztv) +{ + char str[1024]; + char *p=str; /* shut up, gcc! */ + int i; + + for (i=0; i<0x60; i+=4) { + if ((i % 16) == 0) { + if (i) printk(/*KERN_DEBUG*/ "%s\n",str); + p = str; + p+= sprintf(str, " %04x: ",i); + } + p += sprintf(p, "%08x ",zrread(i)); + } +} + +static +void reap_states(struct zoran* ztv) +{ + irq1++; /* debugging... */ + + /* + * GRABBING? + */ + if ( test_bit(STATE_GRAB, &ztv->state) ) { + int i; + + /* are we already grabbing? */ + if (test_bit(STATE_GRAB, &ztv->prevstate)) { + + /* did we get a complete grab? */ + if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) + goto out; + + /* we are done with this buffer, tell everyone */ + ztv->grabinfo[ztv->lastframe].status = FBUFFER_DONE; + wake_up_interruptible(&ztv->grabq); + } + + /* locate a new frame to grab */ + for (i=0; igrabinfo[i].status == FBUFFER_GRABBING) { + + /* there is a buffer more to be grabbed... */ + ztv->lastframe = i; + +DEBUG(printk(KERN_DEBUG "irq(%ld): starting grab(%d)\n",irq1,i)); + + /* loadup the frame settings */ + read_lock(&ztv->lock); + zoran_set_geo(ztv,&ztv->grabinfo[i]); + read_unlock(&ztv->lock); + + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); + zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); + zror(ZORAN_VDC_VIDEN,ZORAN_VDC); + + /* start single-shot grab */ + zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); + goto out; + } + +DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to grab\n",irq1)); + + /* turn grabbing off the next time around */ + clear_bit(STATE_GRAB, &ztv->state); + + /* force re-init of Read or Overlay settings */ + clear_bit(STATE_READ, &ztv->prevstate); + clear_bit(STATE_OVERLAY, &ztv->prevstate); + } + + /* + * READING? + */ + if ( test_bit(STATE_READ, &ztv->state) ) { + /* are we already reading? */ + if (!test_bit(STATE_READ, &ztv->prevstate)) { + +DEBUG(printk(KERN_DEBUG "irq(%ld): starting read\n",irq1)); + + read_lock(&ztv->lock); + zoran_set_geo(ztv,&ztv->readinfo); + read_unlock(&ztv->lock); + + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); + zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); + zror(ZORAN_VDC_VIDEN,ZORAN_VDC); + + /* start single-shot grab */ + zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); + goto out; + } + + /* did we get a complete grab? */ + if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) + goto out; + +DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to read\n",irq1)); + + /* turn reading off the next time around */ + clear_bit(STATE_READ, &ztv->state); + /* force re-init of Overlay settings */ + clear_bit(STATE_OVERLAY, &ztv->prevstate); + + /* we are done, tell everyone */ + wake_up_interruptible(&ztv->readq); + } + + /* + * OVERLAYING? + */ + if ( test_bit(STATE_OVERLAY, &ztv->state) ) { + /* are we already overlaying? */ + if (!test_bit(STATE_OVERLAY, &ztv->prevstate)) { + +DEBUG(printk(KERN_DEBUG "irq(%ld): starting overlay\n",irq1)); + + read_lock(&ztv->lock); + zoran_set_geo(ztv,&ztv->overinfo); + read_unlock(&ztv->lock); + + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); + zror(ZORAN_OCR_OVLEN, ZORAN_OCR); + zror(ZORAN_VDC_VIDEN,ZORAN_VDC); + } + + /* + * leave overlaying on, but turn interrupts off. + */ + zrand(~ZORAN_ICR_EN,ZORAN_ICR); + goto out; + } + + /* + * THEN WE MUST BE IDLING + */ +DEBUG(printk(KERN_DEBUG "irq(%ld): turning off\n",irq1)); + /* nothing further to do, disable DMA and further IRQs */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_ICR_EN,ZORAN_ICR); +out: + ztv->prevstate = ztv->state; +} + +static +void zoran_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,estat; + int count = 0; + struct zoran *ztv = (struct zoran *)dev_id; + + for (;;) { + /* get/clear interrupt status bits */ + stat=zrread(ZORAN_ISR); + estat=stat & zrread(ZORAN_ICR); + if (!estat) + return; + zrwrite(estat,ZORAN_ISR); + IDEBUG(printk(KERN_DEBUG "%s: estat %08x\n",CARD,estat)); + IDEBUG(printk(KERN_DEBUG "%s: stat %08x\n",CARD,stat)); + + if (estat & ZORAN_ISR_CODE) + { + IDEBUG(printk(KERN_DEBUG "%s: CodReplIRQ\n",CARD)); + } + if (estat & ZORAN_ISR_GIRQ0) + { + IDEBUG(printk(KERN_DEBUG "%s: GIRQ0\n",CARD)); + if (!ztv->card->usegirq1) + reap_states(ztv); + } + if (estat & ZORAN_ISR_GIRQ1) + { + IDEBUG(printk(KERN_DEBUG "%s: GIRQ1\n",CARD)); + if (ztv->card->usegirq1) + reap_states(ztv); + } + + count++; + if (count > 10) + printk(KERN_ERR "%s: irq loop %d (%x)\n",CARD,count,estat); + if (count > 20) + { + zrwrite(0, ZORAN_ICR); + printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n",CARD); + } + } +} + +/* + * Scan for a Zoran chip, request the irq and map the io memory + */ +static int find_zoran(void) +{ + unsigned char command, latency; + int result; + struct zoran *ztv; + struct pci_dev *dev; + int zoran_num=0; + + if (!pcibios_present()) + { + DEBUG(printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n")); + return 0; + } + + for (dev = pci_devices; dev != NULL; dev = dev->next) + { + if (dev->vendor != PCI_VENDOR_ID_ZORAN) + continue; + if (dev->device != PCI_DEVICE_ID_ZORAN_36120) + continue; + + /* Ok, ZR36120 found! */ + ztv=&zorans[zoran_num]; + ztv->dev=dev; + ztv->id=dev->device; + ztv->zoran_mem=NULL; + + ztv->zoran_adr = ztv->dev->resource[0].start; + pci_read_config_byte(ztv->dev, PCI_CLASS_REVISION, + &ztv->revision); + printk(KERN_INFO "zoran: Zoran %x (rev %d) ", + ztv->id, ztv->revision); + printk("bus: %d, devfn: %d, ", + ztv->dev->bus->number, ztv->dev->devfn); + printk("irq: %d, ",ztv->dev->irq); + printk("memory: 0x%08x.\n", ztv->zoran_adr); + + ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); + DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); + + result = request_irq(ztv->dev->irq, zoran_irq, + SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv); + if (result==-EINVAL) + { + printk(KERN_ERR "zoran: Bad irq number or handler\n"); + return -EINVAL; + } + if (result==-EBUSY) + { + printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",ztv->dev->irq); + return result; + } + if (result < 0) + return result; + + /* Enable bus-mastering */ + pci_read_config_byte(ztv->dev, PCI_COMMAND, &command); + command|=PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY; + pci_write_config_byte(ztv->dev, PCI_COMMAND, command); + pci_read_config_byte(ztv->dev, PCI_COMMAND, &command); + if (!(command&PCI_COMMAND_MASTER)) + { + printk(KERN_ERR "zoran: PCI bus-mastering could not be enabled\n"); + return -1; + } + pci_read_config_byte(ztv->dev, PCI_LATENCY_TIMER, &latency); + if (!latency) + { + latency=32; + pci_write_config_byte(ztv->dev, PCI_LATENCY_TIMER, latency); + DEBUG(printk(KERN_INFO "zoran: latency set to %d\n",latency)); + } + zoran_num++; + } + if(zoran_num) + printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); + return zoran_num; +} + +static +int zoran_muxsel(struct zoran* ztv, int channel, int norm) +{ + int rv; + + /* set the new video norm */ + rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + if (rv) + return rv; + ztv->norm = norm; + + /* map the given channel to the cards decoder's channel */ + channel = ztv->card->video_mux[channel] & CHANNEL_MASK; + + /* set the new channel */ + rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel); + return rv; +} + +/* Tell the interrupt handler what to to. */ +static +void zoran_cap(struct zoran* ztv, int on) +{ + DEBUG(printk(KERN_DEBUG " zoran_cap(%d) at %ld, state=%x\n",on,irq1,ztv->state)); + + if (on) { + ztv->running = 1; + /* + * Clear the previous state flag. This way the irq + * handler will be forced to re-examine its current + * state from scratch, setting up the registers along + * the way. + */ + clear_bit(STATE_OVERLAY, &ztv->prevstate); + /* + * turn interrupts back on. The DMA will be enabled + * inside the irq handler when it detects a restart. + */ + zror(ZORAN_ICR_CODE|ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1,ZORAN_ICR); + zror(ZORAN_ICR_EN,ZORAN_ICR); + } + else { + ztv->running = 0; + /* + * turn interrupts and DMA both off + */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + zrand(~ZORAN_ICR_EN,ZORAN_ICR); + } +} + +static ulong dmask[] = { + 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, + 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, + 0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, + 0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, + 0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000, + 0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000, + 0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000, + 0xF0000000, 0xE0000000, 0xC0000000, 0x80000000 +}; + +static +void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp) +{ + ulong* mtop; + int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */ + int mult = ztv->interlace; /* double height? */ + int i; + + DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count)); + if (ztv->overinfo.overlay == 0) { + zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); + return; + } + +for (i=0; ix,vp->y,vp->width,vp->height)); +} + + /* clear entire blob */ +/* memset(ztv->overinfo.overlay, 0, 1024*1024/8); */ + + /* + * activate the visible portion of the screen + * Note we take some shortcuts here, because we + * know the width can never be < 32. (I.e. a DWORD) + * We also assume the overlay starts somewhere in + * the FIRST dword. + */ + { + int start = ztv->vidXshift; + ulong firstd = dmask[start]; + ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31]; + mtop = ztv->overinfo.overlay; + for (i=0; ioverinfo.h; i++) { + int w = ztv->vidWidth; + ulong* line = mtop; + if (start & 31) { + *line++ = firstd; + w -= 32-(start&31); + } + memset(line, ~0, w/8); + if (w & 31) + line[w/32] = lastd; + mtop += ystep; + } + } + + /* process clipping regions */ + for (i=0; ix < 0 || vcp->x > ztv->overinfo.w || + vcp->y < 0 || vcp->y > ztv->overinfo.h || + vcp->width < 0 || (vcp->x+vcp->width) > ztv->overinfo.w || + vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h) + { + DEBUG(printk(KERN_DEBUG "%s: illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h)); + if (vcp->x < 0) vcp->x = 0; + if (vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w; + if (vcp->y < 0) vcp->y = 0; + if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h; + if (vcp->width < 0) vcp->width = 0; + if (vcp->x+vcp->width > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x; + if (vcp->height < 0) vcp->height = 0; + if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y; +// continue; + } + + mtop = &ztv->overinfo.overlay[vcp->y*ystep]; + for (h=0; h<=vcp->height; h++) { + int w; + int x = ztv->vidXshift + vcp->x; + for (w=0; w<=vcp->width; w++) { + clear_bit(x&31, &mtop[x/32]); + x++; + } + mtop += ystep; + } + ++vcp; + } + + mtop = ztv->overinfo.overlay; + zrwrite(virt_to_bus(mtop), ZORAN_MTOP); + zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT); + zraor((mult*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR); +} + +struct tvnorm +{ + u16 Wt, Wa, Ht, Ha, HStart, VStart; +}; + +static struct tvnorm tvnorms[] = { + /* PAL-BDGHI */ +/* { 864, 720, 625, 576, 131, 21 },*/ +/*00*/ { 864, 768, 625, 576, 81, 17 }, + /* NTSC */ +/*01*/ { 858, 720, 525, 480, 121, 10 }, + /* SECAM */ +/*02*/ { 864, 720, 625, 576, 131, 21 }, + /* BW50 */ +/*03*/ { 864, 720, 625, 576, 131, 21 }, + /* BW60 */ +/*04*/ { 858, 720, 525, 480, 121, 10 } +}; +#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) + +static +void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) +{ + ulong top, bot; + int stride; + int winWidth, winHeight; + int maxWidth, maxHeight, maxXOffset, maxYOffset; + int filter; + + DEBUG(printk(KERN_DEBUG " set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, vidadr=%lx, overlay=%p)\n", i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->vidadr,i->overlay)); + + /* + * make sure the DMA transfers are inhibited during our + * reprogramming of the chip + */ + zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + + maxWidth = tvnorms[ztv->norm].Wa; + maxHeight = tvnorms[ztv->norm].Ha; + maxXOffset = tvnorms[ztv->norm].HStart; + maxYOffset = tvnorms[ztv->norm].VStart; + + /* + * Set top, bottom ptrs. Since these must be DWORD aligned, + * possible adjust the x and the width of the window. + * so the endposition stay the same. The vidXshift will make + * sure we are not writing pixels before the requested x. + */ + ztv->vidXshift = 0; + winWidth = i->w; + top = i->vidadr + i->x*i->bpp + i->y*i->bpl; + if (top & 3) { + ztv->vidXshift = (top & 3) / i->bpp; + winWidth += ztv->vidXshift; + DEBUG(printk(KERN_DEBUG " window-x shifted %d pixels left\n",ztv->vidXshift)); + top &= ~3; + } + + /* + * bottom points to next frame but in interleaved mode we want + * to 'mix' the 2 frames to one capture, so 'bot' points to one + * (physical) line below the top line. + */ + bot = top + i->bpl; + zrwrite(top,ZORAN_VTOP); + zrwrite(bot,ZORAN_VBOT); + + /* + * Make sure the winWidth is DWORD aligned too, + * thereby automaticly making sure the stride to the + * next line is DWORD aligned too (as required by spec). + */ + if ((winWidth*i->bpp) & 3) { + DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); + winWidth += (winWidth*i->bpp) & 3; + } + + /* determine the DispMode and stride */ + if (i->h <= maxHeight/2) { + /* single frame suffices for this height */ + zror(ZORAN_VFEC_DISPMOD, ZORAN_VFEC); + ztv->interlace = 0; + winHeight = i->h; + if (winHeight < 0) /* can happen for read's! */ + winHeight = -winHeight; + stride = i->bpl - (winWidth*i->bpp); + } + else { + /* interleaving needed for this height */ + zrand(~ZORAN_VFEC_DISPMOD, ZORAN_VFEC); + ztv->interlace = 1; + winHeight = i->h/2; + stride = i->bpl*2 - (winWidth*i->bpp); + } + /* safety net, sometimes bpl is too short??? */ + if (stride<0) { + DEBUG(printk(KERN_DEBUG "%s: WARNING stride = %d\n",CARD,stride)); + stride = 0; + } + + zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC); + zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR); + + /* remember vidWidth, vidHeight for overlay calculations */ + ztv->vidWidth = winWidth; + ztv->vidHeight = winHeight; +DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx, winWidth=%d, winHeight=%d, maxWidth=%d, maxHeight=%d, stride=%d\n",top,bot,winWidth,winHeight,maxWidth,maxHeight,stride)); + + /* determine scales and crops */ + if (1) { + int Wa, X, We, HorDcm, hcrop1, hcrop2, Hstart, Hend; + +A: Wa = maxWidth; + X = (winWidth*64+Wa-1)/Wa; + We = winWidth*64/X; + HorDcm = 64-X; + hcrop1 = 2*(Wa-We)/4; + hcrop2 = Wa-We-hcrop1; + Hstart = maxXOffset + hcrop1; + Hend = maxXOffset + Wa-1-hcrop2; + + /* + * BUGFIX: Juha Nurmela + * found the solution to the color phase shift. + * See ChangeLog for the full explanation) + */ + if (!(Hstart & 1)) { +DEBUG(printk(KERN_DEBUG " correcting horizontal start/end by one\n")); + winWidth--; + goto A; + } + +DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend)); + + zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); + zraor((HorDcm<<14),~ZORAN_VFEC_HORDCM, ZORAN_VFEC); + + filter = ZORAN_VFEC_HFILTER_1; + if (HorDcm >= 48) + filter = ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ + else if (HorDcm >= 32) + filter = ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ + else if (HorDcm >= 16) + filter = ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ + zraor(filter, ~ZORAN_VFEC_HFILTER, ZORAN_VFEC); + } + /* when height is negative, we want to read from line 0 */ + if (i->h < 0) { + int Vstart = 0; + int Vend = Vstart + winHeight; + int VerDcm = 0; +DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); + zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); + zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC); + } + else { + int Ha = maxHeight/2; + int Y = (winHeight*64+Ha-1)/Ha; + int He = winHeight*64/Y; + int VerDcm = 64-Y; + int vcrop1 = 2*(Ha-He)/4; + int vcrop2 = Ha-He-vcrop1; + int Vstart = maxYOffset + vcrop1; + int Vend = maxYOffset + Ha-1-vcrop2; + +DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); + zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); + zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC); + } + +DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name)); + /* setup the requested format */ + zraor(palette2fmt[i->format].mode, ~(ZORAN_VFEC_RGB|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24), ZORAN_VFEC); +} + +#if LINUX_VERSION_CODE >= 0x020100 +static +unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait) +{ + struct zoran *ztv = (struct zoran *)dev; + + poll_wait(file, &ztv->readq, wait); + + return (POLLIN | POLLRDNORM); +} +#endif + +/* + * Open a zoran card. Right now the flags are just a hack + */ +static int zoran_open(struct video_device *dev, int flags) +{ + struct zoran *ztv = (struct zoran*)dev; + int i; + + DEBUG(printk(KERN_DEBUG "%s: open(dev,%d)\n",CARD,flags)); + + switch (flags) { + case 0: + /* already active? */ + if (ztv->user) + return -EBUSY; + ztv->user++; + + /* unmute audio */ + /* /what/ audio? */ + +/****************************************** + We really should be doing lazy allocing... + ******************************************/ + /* allocate a frame buffer */ + if (!ztv->fbuffer) + ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); + if (!ztv->fbuffer) { + /* could not get a buffer, bail out */ + ztv->user--; + return -ENOBUFS; + } + /* at this time we _always_ have a framebuffer */ + memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); + + if (!ztv->overinfo.overlay) + ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL); + if (!ztv->overinfo.overlay) { + /* could not get an overlay buffer, bail out */ + ztv->user--; + bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); + return -ENOBUFS; + } + /* at this time we _always_ have a overlay */ + + /* clear buffer status */ + for (i=0; igrabinfo[i].status = FBUFFER_UNUSED; + ztv->state = 0; + ztv->prevstate = 0; + ztv->lastframe = -1; + + /* setup the encoder to the initial values */ + i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); + + /* default to the compisite input since my camera is there */ + zoran_muxsel(ztv, 0, VIDEO_MODE_PAL); + break; + case 1: + break; + } + MOD_INC_USE_COUNT; + return 0; +} + +static +void zoran_close(struct video_device* dev) +{ + struct zoran *ztv = (struct zoran*)dev; + + DEBUG(printk(KERN_DEBUG "%s: close(dev)\n",CARD)); + + /* we are no longer active, goodbye */ + ztv->user--; + + /* mute audio */ + /* stop the chip */ + zoran_cap(ztv, 0); + + /* free the allocated framebuffer */ + if (ztv->fbuffer) + bfree( ztv->fbuffer, ZORAN_MAX_FBUFSIZE ); + ztv->fbuffer = 0; + if (ztv->overinfo.overlay) + kfree( ztv->overinfo.overlay ); + ztv->overinfo.overlay = 0; + + MOD_DEC_USE_COUNT; +} + +static +long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock) +{ + DEBUG(printk(KERN_DEBUG "zoran_write\n")); + return -EINVAL; +} + +static +long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran*)dev; + int max; + + DEBUG(printk(KERN_DEBUG "zoran_read(%p,%ld,%d)\n",buf,count,nonblock)); + + /* tell the state machine we want in too */ + write_lock_irq(&ztv->lock); + ztv->readinfo.vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer)); + set_bit(STATE_READ, &ztv->state); + write_unlock_irq(&ztv->lock); + zoran_cap(ztv, 1); + + /* wait for data to arrive */ + interruptible_sleep_on(&ztv->readq); + + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + + /* give the user what he requested */ + max = ztv->readinfo.w*ztv->readinfo.bpp - ztv->readinfo.h*ztv->readinfo.bpl; + if (count > max) + count = max; + if (copy_to_user((void*)buf, (void*)ztv->fbuffer, count)) + return -EFAULT; + + /* goodbye */ + return count; +} + +/* append a new clipregion to the vector of video_clips */ +static +void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h) +{ + vcp[vw->clipcount].x = x; + vcp[vw->clipcount].y = y; + vcp[vw->clipcount].width = w; + vcp[vw->clipcount].height = h; + vw->clipcount++; +} + +static +int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) +{ + struct zoran* ztv = (struct zoran*)dev; + + switch (cmd) { + case VIDIOCGCAP: + { /* get video capabilities */ + struct video_capability c; + struct video_decoder_capability dc; + int rv; + DEBUG(printk(KERN_DEBUG "%s: GetCapabilities\n",CARD)); + + /* fetch the capabilites of the decoder */ + dc.flags = 0; + dc.inputs = -1; + dc.outputs = -1; + rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc); + if (rv) + return rv; + DEBUG(printk(KERN_DEBUG "%s: capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs)); + + strcpy(c.name,ztv->video_dev.name); + c.type = VID_TYPE_CAPTURE| + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + c.channels = ztv->card->video_inputs; + c.audios = ztv->card->audio_inputs; + c.maxwidth = 768; + c.maxheight = 576; + c.minwidth = 32; + c.minheight = 32; + if (copy_to_user(arg,&c,sizeof(c))) + return -EFAULT; + return 0; + } + + case VIDIOCGCHAN: + { + struct video_channel v; + int mux; + + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(KERN_DEBUG "%s: GetChannel(%d)\n",CARD,v.channel)); + v.flags=VIDEO_VC_AUDIO +#ifdef VIDEO_VC_NORM + |VIDEO_VC_NORM +#endif + ; + v.tuners=0; + v.type=VIDEO_TYPE_CAMERA; +#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API + v.norm=VIDEO_MODE_PAL| + VIDEO_MODE_NTSC| + VIDEO_MODE_SECAM; +#else + v.norm=VIDEO_MODE_PAL; +#endif + /* too many inputs? */ + if (v.channel >= ztv->card->video_inputs) + return -EINVAL; + + /* now determine the name of the channel */ + mux = ztv->card->video_mux[v.channel]; + if (mux & IS_TUNER) { + /* lets assume only one tuner, yes? */ + strcpy(v.name,"Television"); + v.type = VIDEO_TYPE_TV; + if (ztv->have_tuner) { + v.flags |= VIDEO_VC_TUNER; + v.tuners = 1; + } + } + else if (mux & IS_SVHS) + sprintf(v.name,"S-Video-%d",v.channel); + else + sprintf(v.name,"CVBS-%d",v.channel); + + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSCHAN: + { /* set video channel */ + struct video_channel v; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + DEBUG(printk(KERN_DEBUG "%s: SetChannel(%d,%d)\n",CARD,v.channel,v.norm)); + if (v.channel >= ztv->card->video_inputs) + return -EINVAL; + + if (v.norm != VIDEO_MODE_PAL && + v.norm != VIDEO_MODE_NTSC && + v.norm != VIDEO_MODE_SECAM && + v.norm != VIDEO_MODE_AUTO) + return -EOPNOTSUPP; + + /* make it happen, nr1! */ + return zoran_muxsel(ztv,v.channel,v.norm); + } + + case VIDIOCGTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + + /* Only one tuner for now */ + if (!ztv->have_tuner && v.tuner) + return -EINVAL; + + strcpy(v.name,"Television"); + v.rangelow = 0; + v.rangehigh = ~0; + v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v.mode = ztv->norm; + v.signal = 0xFFFF; /* unknown */ + + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + + case VIDIOCSTUNER: + { + struct video_tuner v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + /* Only one tuner for now */ + if (!ztv->have_tuner && v.tuner) + return -EINVAL; + + /* and it only has certain valid modes */ + if( v.mode != VIDEO_MODE_PAL && + v.mode != VIDEO_MODE_NTSC && + v.mode != VIDEO_MODE_SECAM) + return -EOPNOTSUPP; + + /* engage! */ + return zoran_muxsel(ztv,v.tuner,v.mode); + } + + case VIDIOCGPICT: + { + struct video_picture p = ztv->picture; + DEBUG(printk(KERN_DEBUG "%s: GetPicture\n",CARD)); + p.depth = ztv->depth; + switch (p.depth) { + case 8: p.palette=VIDEO_PALETTE_YUV422; + break; + case 15: p.palette=VIDEO_PALETTE_RGB555; + break; + case 16: p.palette=VIDEO_PALETTE_RGB565; + break; + case 24: p.palette=VIDEO_PALETTE_RGB24; + break; + case 32: p.palette=VIDEO_PALETTE_RGB32; + break; + } + if (copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + DEBUG(printk(KERN_DEBUG "%s: SetPicture\n",CARD)); + if (copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + + /* depth must match with framebuffer */ + if (p.depth != ztv->depth) + return -EINVAL; + + /* check if palette matches this bpp */ + if (p.palette<1 || p.palette>NRPALETTES || + palette2fmt[p.palette].bpp != ztv->overinfo.bpp) + return -EINVAL; + + write_lock_irq(&ztv->lock); + ztv->overinfo.format = p.palette; + ztv->picture = p; + write_unlock_irq(&ztv->lock); + + /* tell the decoder */ + i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); + return 0; + } + + case VIDIOCGWIN: + { + struct video_window vw; + DEBUG(printk(KERN_DEBUG "%s: GetWindow\n",CARD)); + read_lock(&ztv->lock); + vw.x = ztv->overinfo.x; + vw.y = ztv->overinfo.y; + vw.width = ztv->overinfo.w; + vw.height = ztv->overinfo.h; + vw.chromakey= 0; + vw.flags = 0; + if (ztv->interlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + read_unlock(&ztv->lock); + if (copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp; + int on; + + if (copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + DEBUG(printk(KERN_DEBUG "%s: SetWindow(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); + + if (vw.flags) + return -EINVAL; + + if (vw.clipcount>256) + return -EDOM; /* Too many! */ + + /* + * Do any clips. + */ + vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); + if (vcp==NULL) + return -ENOMEM; + if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) + return -EFAULT; + + on = ztv->running; + if (on) + zoran_cap(ztv, 0); + + /* by now we are committed to the new data... */ + write_lock_irq(&ztv->lock); + ztv->overinfo.x = vw.x; + ztv->overinfo.y = vw.y; + ztv->overinfo.w = vw.width; + ztv->overinfo.h = vw.height; + write_unlock_irq(&ztv->lock); + + /* + * Impose display clips + */ + if (vw.x<0) + new_clip(&vw, vcp, 0, 0, -vw.x, vw.height-1); + if (vw.y<0) + new_clip(&vw, vcp, 0, 0, vw.width-1,-vw.y); + if (vw.x+vw.width > ztv->swidth) + new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1); + if (vw.y+vw.height > ztv->sheight) + new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1); + + /* built the requested clipping zones */ + zoran_set_geo(ztv, &ztv->overinfo); + zoran_built_overlay(ztv, vw.clipcount, vcp); + vfree(vcp); + + /* if we were on, restart the video engine */ + if (on) zoran_cap(ztv, on); + return 0; + } + case VIDIOCCAPTURE: + { + int v; + get_user_ret(v,(int*)arg, -EFAULT); + DEBUG(printk(KERN_DEBUG "%s: Capture(%d)\n",CARD,v)); + + if (v==0) { + zoran_cap(ztv, 0); + clear_bit(STATE_OVERLAY, &ztv->state); + } + else { + /* is VIDIOCSFBUF, VIDIOCSWIN done? */ + if (ztv->overinfo.vidadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) + return -EINVAL; + + set_bit(STATE_OVERLAY, &ztv->state); + zoran_cap(ztv, 1); + } + return 0; + } + + case VIDIOCGFBUF: + { + struct video_buffer v; + DEBUG(printk(KERN_DEBUG "%s: GetFramebuffer\n",CARD)); + read_lock(&ztv->lock); + v.base = (void *)ztv->overinfo.vidadr; + v.height = ztv->sheight; + v.width = ztv->swidth; + v.depth = ztv->depth; + v.bytesperline = ztv->overinfo.bpl; + read_unlock(&ztv->lock); + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSFBUF: + { + struct video_buffer v; +#if LINUX_VERSION_CODE >= 0x020100 + if(!capable(CAP_SYS_ADMIN)) +#else + if(!suser()) +#endif + return -EPERM; + if (copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) + return -EINVAL; + if (v.bytesperline<1) + return -EINVAL; + if (ztv->running) + return -EBUSY; + write_lock_irq(&ztv->lock); + ztv->overinfo.vidadr = (unsigned long)v.base; + ztv->sheight = v.height; + ztv->swidth = v.width; + ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ + ztv->depth = v.depth; /* bits per pixel */ + ztv->overinfo.bpl = v.bytesperline; + write_unlock_irq(&ztv->lock); + + DEBUG(printk(KERN_DEBUG "%s: SetFrameBuffer(%p,%dx%d, bpp %d, bpl %d)\n",CARD,v.base, v.width,v.height, ztv->overinfo.bpp, ztv->overinfo.bpl)); + return 0; + } + + case VIDIOCSYNC: + { + int i; + get_user_ret(i,(int*)arg, -EFAULT); + DEBUG(printk(KERN_DEBUG "%s: VIDEOCSYNC(%d)\n",CARD,i)); + if (i<0 || i>ZORAN_MAX_FBUFFERS) + return -EINVAL; + switch (ztv->grabinfo[i].status) { + case FBUFFER_UNUSED: + return -EINVAL; + case FBUFFER_GRABBING: + /* wait till this buffer gets grabbed */ + while (ztv->grabinfo[i].status == FBUFFER_GRABBING) { + interruptible_sleep_on(&ztv->grabq); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + } + /* fall through */ + case FBUFFER_DONE: + ztv->grabinfo[i].status = FBUFFER_UNUSED; + break; + } + return 0; + } + + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + return 0; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + struct vidinfo* frame; + if (copy_from_user(&vm,arg,sizeof(vm))) + return -EFAULT; + if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS || + vm.width<32 || vm.width>768 || + vm.height<32 || vm.height>576 || + vm.format<0 || vm.format>NRPALETTES || + palette2fmt[vm.format].mode == 0) + return -EINVAL; + + DEBUG(printk(KERN_DEBUG "%s: Mcapture(%d,(%d,%d),%d=%s)\n",CARD,vm.frame,vm.width,vm.height,vm.format,palette2fmt[vm.format].name)); + frame = &ztv->grabinfo[vm.frame]; + if (frame->status == FBUFFER_GRABBING) + return -EBUSY; + + /* setup the other parameters if they are given */ + write_lock_irq(&ztv->lock); + if (vm.width) + frame->w = vm.width; + if (vm.height) + frame->h = vm.height; + if (vm.format) + frame->format = vm.format; + frame->bpp = palette2fmt[frame->format].bpp; + frame->bpl = frame->w*frame->bpp; + frame->vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer+vm.frame*ZORAN_MAX_FBUFFER)); + frame->status = FBUFFER_GRABBING; + set_bit(STATE_GRAB, &ztv->state); + write_unlock_irq(&ztv->lock); + + zoran_cap(ztv, 1); + return 0; + } + + case VIDIOCGMBUF: + { + struct video_mbuf mb; + int i; + DEBUG(printk(KERN_DEBUG "%s: GetMemoryBuffer\n",CARD)); + mb.size = ZORAN_MAX_FBUFSIZE; + mb.frames = ZORAN_MAX_FBUFFERS; + for (i=0; ivideo_dev.minor; + vu.vbi = VIDEO_NO_UNIT; + vu.radio = VIDEO_NO_UNIT; + vu.audio = VIDEO_NO_UNIT; + vu.teletext = VIDEO_NO_UNIT; + if(copy_to_user(arg, &vu,sizeof(vu))) + return -EFAULT; + return 0; + } + + case VIDIOCGFREQ: + { + unsigned long v = ztv->tuner_freq; + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + + case VIDIOCSFREQ: + { + unsigned long v; + if (copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + + if (ztv->have_tuner) { + int fixme = v; + if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0) + return -EAGAIN; + } + ztv->tuner_freq = v; + return 0; + } + + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + case VIDIOCGCAPTURE: + case VIDIOCSCAPTURE: + DEBUG(printk(KERN_DEBUG "%s: unhandled video ioctl(%x)\n",CARD,cmd)); + return -EINVAL; + + default: + DEBUG(printk(KERN_DEBUG "%s: bad ioctl(%x)\n",CARD,cmd)); + } + return -EPERM; +} + +static +int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size) +{ + struct zoran* ztv = (struct zoran*)dev; + unsigned long start = (unsigned long)adr; + unsigned long pos; + + DEBUG(printk(KERN_DEBUG "zoran_mmap(0x%p,%ld)\n",adr,size)); + + /* sanity checks */ + if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) + return -EINVAL; + + /* start mapping the whole shabang to user memory */ + pos = (unsigned long)ztv->fbuffer; + while (size>0) { +#ifdef CONFIG_BIGPHYS_AREA + unsigned long page = virt_to_phys((void*)pos); +#else + unsigned long page = kvirt_to_phys(pos); +#endif + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +static struct video_device zoran_template= +{ + "UNSET", + VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, + VID_HARDWARE_ZR36120, + + zoran_open, + zoran_close, + zoran_read, + zoran_write, +#if LINUX_VERSION_CODE >= 0x020100 + zoran_poll, /* poll */ +#endif + zoran_ioctl, + zoran_mmap, + NULL, /* initialize */ + NULL, + 0, + -1 +}; + +static +int init_zoran(int card) +{ + struct zoran *ztv = &zorans[card]; + int i; + + /* if the given cardtype valid? */ + if (cardtype[card]<0 || cardtype[card]>=NRTVCARDS) { + printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]); + return -1; + } + + /* reset the zoran */ + zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI); + udelay(10); + zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); + udelay(10); + + /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ + + /* framegrabber details */ + ztv->swidth=800; + ztv->sheight=600; + ztv->depth=16; + + /* channel details */ + ztv->norm=0; /* PAL */ + ztv->card=tvcards+cardtype[card]; /* point to the selected card */ + ztv->tuner_freq = 0; + + ztv->overinfo.status = FBUFFER_UNUSED; + ztv->overinfo.x = 0; + ztv->overinfo.y = 0; + ztv->overinfo.w = 768; /* 640 */ + ztv->overinfo.h = 576; /* 480 */ + ztv->overinfo.format = VIDEO_PALETTE_RGB565; + ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp; + ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth; + ztv->overinfo.vidadr = 0; + ztv->overinfo.overlay = 0; + + ztv->readinfo = ztv->overinfo; + ztv->readinfo.w = 768; + ztv->readinfo.h = -22; + ztv->readinfo.format = VIDEO_PALETTE_YUV422; + ztv->readinfo.bpp = palette2fmt[ztv->readinfo.format].bpp; + ztv->readinfo.bpl = ztv->readinfo.w*ztv->readinfo.bpp; + + /* grabbing details */ + for (i=0; igrabinfo[i] = ztv->overinfo; + ztv->grabinfo[i].format = VIDEO_PALETTE_RGB24; + } + + /* maintenance data */ + ztv->fbuffer = NULL; + ztv->user = 0; + ztv->have_decoder = 0; + ztv->have_tuner = 0; + ztv->running = 0; + init_waitqueue_head(&ztv->grabq); + init_waitqueue_head(&ztv->readq); + ztv->lock = RW_LOCK_UNLOCKED; + ztv->state = 0; + ztv->prevstate = 0; + ztv->lastframe = -1; + + /* picture details */ + ztv->picture.colour=254<<7; + ztv->picture.brightness=128<<8; + ztv->picture.hue=128<<8; + ztv->picture.contrast=216<<7; + + if (triton1) + zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC); + + /* external FL determines TOP frame */ + zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); + + /* set HSpol */ + if (ztv->card->hsync_pos) + zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH); + /* set VSpol */ + if (ztv->card->vsync_pos) + zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV); + + /* Set the proper General Purpuse register bits */ + /* implicit: no softreset, 0 waitstates */ + zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI); + /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */ + zrwrite(ztv->card->gpval<<24,ZORAN_GUEST); + + /* clear interrupt status */ + zrwrite(~0, ZORAN_ISR); + + /* + * i2c template + */ + ztv->i2c = zoran_i2c_bus_template; + sprintf(ztv->i2c.name,"zoran-%d",card); + ztv->i2c.data = ztv; + + /* + * Now add the template and register the device unit + */ + ztv->video_dev = zoran_template; + strcpy(ztv->video_dev.name, ztv->i2c.name); + if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0) + return -1; + i2c_register_bus(&ztv->i2c); + + /* set interrupt mask - the PIN enable will be set later */ + zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR); + + printk(KERN_INFO "%s: installed %s\n",CARD,ztv->card->name); + return 0; +} + +static +void release_zoran(int max) +{ + u8 command; + struct zoran *ztv; + int i; + + for (i=0;idev->irq,ztv); + + /* unregister i2c_bus */ + i2c_unregister_bus((&ztv->i2c)); + + /* disable PCI bus-mastering */ + pci_read_config_byte(ztv->dev, PCI_COMMAND, &command); + command&=PCI_COMMAND_MASTER; + pci_write_config_byte(ztv->dev, PCI_COMMAND, command); + + /* unmap and free memory */ + if (ztv->zoran_mem) + iounmap(ztv->zoran_mem); + + video_unregister_device(&ztv->video_dev); + } +} + +#ifdef MODULE +void cleanup_module(void) +{ + release_zoran(zoran_cards); +} + +int init_module(void) +{ +#else +int init_zr36120_cards(struct video_init *unused) +{ +#endif + int card; + + handle_chipset(); + zoran_cards = find_zoran(); + if (zoran_cards<0) + /* no cards found, no need for a driver */ + return -EIO; + + /* initialize Zorans */ + for (card=0; card +#include + +#include +#include + +#include + +/* + * Debug macro's, place an x behind the ) for actual debug-compilation + * E.g. #define DEBUG(x...) x + */ +#define DEBUG(x...) /* Debug driver */ +#define IDEBUG(x...) /* Debug interrupt handler */ +#define PDEBUG 0 /* Debug PCI writes */ + +/* defined in zr36120_i2c */ +extern struct i2c_bus zoran_i2c_bus_template; + +#define ZORAN_MAX_FBUFFERS 2 +#define ZORAN_MAX_FBUFFER 0x0A2000 +#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER) + +/* external declarations */ +extern unsigned long zoran_alloc_memory(void); +extern void zoran_free_memory(void); + +struct tvcard { + char* name; /* name of the cardtype */ + int video_inputs; /* number of channels defined in video_mux */ + int audio_inputs; /* number of channels defined in audio_mux */ + __u32 swapi2c:1, /* need to swap i2c wires SDA/SCL? */ + usegirq1:1, /* VSYNC at GIRQ1 instead of GIRQ0? */ + vsync_pos:1, /* positive VSYNC signal? */ + hsync_pos:1, /* positive HSYNC signal? */ + gpdir:8, /* General Purpose Direction register */ + gpval:8; /* General Purpose Value register */ + int video_mux[6]; /* mapping channel number to physical input */ +#define IS_TUNER 0x80 +#define IS_SVHS 0x40 +#define CHANNEL_MASK 0x3F + int audio_mux[6]; /* mapping channel number to physical input */ +}; +#define TUNER(x) ((x)|IS_TUNER) +#define SVHS(x) ((x)|IS_SVHS) + +struct vidinfo { + int status; +#define FBUFFER_UNUSED 0 +#define FBUFFER_GRABBING 1 +#define FBUFFER_DONE 2 + int x,y; + int w,h; + int bpl; + int bpp; /* should be calculated */ + int format; + ulong vidadr; /* physical video address */ + ulong* overlay; +}; + +struct zoran +{ + struct video_device video_dev; +#define CARD ztv->video_dev.name + struct i2c_bus i2c; + struct video_picture picture; /* Current picture params */ + struct video_audio audio_dev; /* Current audio params */ + + /* zoran chip specific details */ + struct pci_dev* dev; /* ptr to PCI device */ + ushort id; /* chip id */ + unsigned char revision; /* chip revision */ + int zoran_adr; /* bus address of IO memory */ + char* zoran_mem; /* pointer to mapped IO memory */ + + /* videocard details */ + int swidth; /* screen width */ + int sheight; /* screen height */ + int depth; /* depth in bits */ + + /* channel details */ + int norm; /* 0=PAL, 1=NTSC, 2=SECAM */ + struct tvcard* card; /* the cardtype */ + int tuner_freq; /* in Hz */ + + /* State details */ + struct vidinfo overinfo; /* overlay data */ + struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data */ + struct vidinfo readinfo; /* reading data */ + + /* maintenance data */ + char* fbuffer; /* framebuffers for mmap */ + int user; /* # users */ + int have_decoder; /* did we detect a mux? */ + int have_tuner; /* did we detect a tuner? */ + int tuner_type; /* tuner type, when found */ + int running; + wait_queue_head_t grabq; /* waiting capturers */ + wait_queue_head_t readq; /* waiting readers */ + rwlock_t lock; + int state; /* what is requested of us? */ +#define STATE_READ 0 +#define STATE_GRAB 1 +#define STATE_OVERLAY 2 + int prevstate; + int lastframe; + + int interlace; /* calculated */ + int vidXshift; /* calculated */ + int vidWidth; /* calculated */ + int vidHeight; /* calculated */ +}; + +#define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr))) +#define zrread(adr) readl(ztv->zoran_mem+(adr)) + +#if !defined(PDEBUG) || (PDEBUG == 0) +#define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr) +#define zror(dat,adr) zrwrite((dat) | zrread(adr), adr) +#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr) +#else +#define zrand(dat, adr) \ +do { \ + ulong data = (dat) & zrread((adr)); \ + zrwrite(data, (adr)); \ + if (0 != (~(dat) & zrread((adr)))) \ + printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \ +} while(0) + +#define zror(dat, adr) \ +do { \ + ulong data = (dat) | zrread((adr)); \ + zrwrite(data, (adr)); \ + if ((dat) != ((dat) & zrread(adr))) \ + printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \ +} while(0) + +#define zraor(dat, mask, adr) \ +do { \ + ulong data; \ + if ((dat) & (mask)) \ + printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ + data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \ + zrwrite(data,(adr)); \ + if ( (dat) != (~(mask) & zrread((adr))) ) \ + printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ +} while(0) +#endif + +#endif + +/* zoran PCI address space */ +#define ZORAN_VFEH 0x000 /* Video Front End Horizontal Conf. */ +#define ZORAN_VFEH_HSPOL (1<<30) +#define ZORAN_VFEH_HSTART (0x3FF<<10) +#define ZORAN_VFEH_HEND (0x3FF<<0) + +#define ZORAN_VFEV 0x004 /* Video Front End Vertical Conf. */ +#define ZORAN_VFEV_VSPOL (1<<30) +#define ZORAN_VFEV_VSTART (0x3FF<<10) +#define ZORAN_VFEV_VEND (0x3FF<<0) + +#define ZORAN_VFEC 0x008 /* Video Front End Scaler and Pixel */ +#define ZORAN_VFEC_EXTFL (1<<26) +#define ZORAN_VFEC_TOPFIELD (1<<25) +#define ZORAN_VFEC_VCLKPOL (1<<24) +#define ZORAN_VFEC_HFILTER (7<<21) +#define ZORAN_VFEC_HFILTER_1 (0<<21) /* no lumi, 3-tap chromo */ +#define ZORAN_VFEC_HFILTER_2 (1<<21) /* 3-tap lumi, 3-tap chromo */ +#define ZORAN_VFEC_HFILTER_3 (2<<21) /* 4-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_HFILTER_4 (3<<21) /* 5-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_HFILTER_5 (4<<21) /* 4-tap lumi, 4-tap chromo */ +#define ZORAN_VFEC_DUPFLD (1<<20) +#define ZORAN_VFEC_HORDCM (63<<14) +#define ZORAN_VFEC_VERDCM (63<<8) +#define ZORAN_VFEC_DISPMOD (1<<6) +#define ZORAN_VFEC_RGB (3<<3) +#define ZORAN_VFEC_RGB_YUV422 (0<<3) +#define ZORAN_VFEC_RGB_RGB888 (1<<3) +#define ZORAN_VFEC_RGB_RGB565 (2<<3) +#define ZORAN_VFEC_RGB_RGB555 (3<<3) +#define ZORAN_VFEC_ERRDIF (1<<2) +#define ZORAN_VFEC_PACK24 (1<<1) +#define ZORAN_VFEC_LE (1<<0) + +#define ZORAN_VTOP 0x00C /* Video Display "Top" */ + +#define ZORAN_VBOT 0x010 /* Video Display "Bottom" */ + +#define ZORAN_VSTR 0x014 /* Video Display Stride */ +#define ZORAN_VSTR_DISPSTRIDE (0xFFFF<<16) +#define ZORAN_VSTR_VIDOVF (1<<8) +#define ZORAN_VSTR_SNAPSHOT (1<<1) +#define ZORAN_VSTR_GRAB (1<<0) + +#define ZORAN_VDC 0x018 /* Video Display Conf. */ +#define ZORAN_VDC_VIDEN (1<<31) +#define ZORAN_VDC_MINPIX (0x1F<<25) +#define ZORAN_VDC_TRICOM (1<<24) +#define ZORAN_VDC_VIDWINHT (0x3FF<<12) +#define ZORAN_VDC_VIDWINWID (0x3FF<<0) + +#define ZORAN_MTOP 0x01C /* Masking Map "Top" */ + +#define ZORAN_MBOT 0x020 /* Masking Map "Bottom" */ + +#define ZORAN_OCR 0x024 /* Overlay Control */ +#define ZORAN_OCR_OVLEN (1<<15) +#define ZORAN_OCR_MASKSTRIDE (0xFF<<0) + +#define ZORAN_PCI 0x028 /* System, PCI and GPP Control */ +#define ZORAN_PCI_SOFTRESET (1<<24) +#define ZORAN_PCI_WAITSTATE (3<<16) +#define ZORAN_PCI_GENPURDIR (0xFF<<0) + +#define ZORAN_GUEST 0x02C /* GuestBus Control */ + +#define ZORAN_CSOURCE 0x030 /* Code Source Address */ + +#define ZORAN_CTRANS 0x034 /* Code Transfer Control */ + +#define ZORAN_CMEM 0x038 /* Code Memory Pointer */ + +#define ZORAN_ISR 0x03C /* Interrupt Status Register */ +#define ZORAN_ISR_CODE (1<<28) +#define ZORAN_ISR_GIRQ0 (1<<29) +#define ZORAN_ISR_GIRQ1 (1<<30) + +#define ZORAN_ICR 0x040 /* Interrupt Control Register */ +#define ZORAN_ICR_EN (1<<24) +#define ZORAN_ICR_CODE (1<<28) +#define ZORAN_ICR_GIRQ0 (1<<29) +#define ZORAN_ICR_GIRQ1 (1<<30) + +#define ZORAN_I2C 0x044 /* I2C-Bus */ +#define ZORAN_I2C_SCL (1<<1) +#define ZORAN_I2C_SDA (1<<0) + +#define ZORAN_POST 0x48 /* PostOffice */ +#define ZORAN_POST_PEN (1<<25) +#define ZORAN_POST_TIME (1<<24) +#define ZORAN_POST_DIR (1<<23) +#define ZORAN_POST_GUESTID (3<<20) +#define ZORAN_POST_GUEST (7<<16) +#define ZORAN_POST_DATA (0xFF<<0) + +#endif diff --git a/drivers/char/zr36120_i2c.c b/drivers/char/zr36120_i2c.c new file mode 100644 index 000000000000..8eb618b14f54 --- /dev/null +++ b/drivers/char/zr36120_i2c.c @@ -0,0 +1,118 @@ +/* + zr36120_i2c.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include +#include + +#include "linux/video_decoder.h" +#include "tuner.h" +#include "zr36120.h" + +/* ----------------------------------------------------------------------- */ +/* I2C functions */ +/* ----------------------------------------------------------------------- */ + +/* software I2C functions */ + +#define I2C_DELAY 10 + +static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) +{ + struct zoran *ztv = (struct zoran*)bus->data; + unsigned int b = 0; + if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA; + if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL; + zrwrite(b, ZORAN_I2C); + udelay(I2C_DELAY); +} + +static int i2c_getdataline(struct i2c_bus *bus) +{ + struct zoran *ztv = (struct zoran*)bus->data; + if (ztv->card->swapi2c) + return zrread(ZORAN_I2C) & ZORAN_I2C_SCL; + return zrread(ZORAN_I2C) & ZORAN_I2C_SDA; +} + +static +void attach_inform(struct i2c_bus *bus, int id) +{ + struct zoran *ztv = (struct zoran*)bus->data; + + switch (id) { + case I2C_DRIVERID_VIDEODECODER: + ztv->have_decoder = 1; + DEBUG(printk(KERN_INFO "%s: decoder attached\n",CARD)); + break; + case I2C_DRIVERID_TUNER: + ztv->have_tuner = 1; + DEBUG(printk(KERN_INFO "%s: tuner attached\n",CARD)); + if (ztv->tuner_type >= 0) + { + if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0) + DEBUG(printk(KERN_INFO "%s: attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type)); + } + break; + default: + DEBUG(printk(KERN_INFO "%s: attach_inform; unknown device id=%d\n",CARD,id)); + break; + } +} + +static +void detach_inform(struct i2c_bus *bus, int id) +{ + struct zoran *ztv = (struct zoran*)bus->data; + + switch (id) { + case I2C_DRIVERID_VIDEODECODER: + ztv->have_decoder = 0; + DEBUG(printk(KERN_INFO "%s: decoder detached\n",CARD)); + break; + case I2C_DRIVERID_TUNER: + ztv->have_tuner = 0; + DEBUG(printk(KERN_INFO "%s: tuner detached\n",CARD)); + break; + default: + DEBUG(printk(KERN_INFO "%s: detach_inform; unknown device id=%d\n",CARD,id)); + break; + } +} + +struct i2c_bus zoran_i2c_bus_template = +{ + "ZR36120", + I2C_BUSID_ZORAN, + NULL, + + SPIN_LOCK_UNLOCKED, + + attach_inform, + detach_inform, + + i2c_setlines, + i2c_getdataline, + NULL, + NULL +}; diff --git a/drivers/char/zr36120_mem.c b/drivers/char/zr36120_mem.c new file mode 100644 index 000000000000..18f83f6d2f72 --- /dev/null +++ b/drivers/char/zr36120_mem.c @@ -0,0 +1,127 @@ +/* + zr36120_mem.c - Zoran 36120/36125 based framegrabbers + + Copyright (C) 1998-1999 Pauline Middelink + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#ifdef CONFIG_BIGPHYS_AREA +#include +#endif + +#include "zr36120.h" +#include "zr36120_mem.h" + +/* ----------------------------------------------------------------------- */ +/* Memory functions */ +/* shamelessly stolen and adapted from bttv.c */ +/* ----------------------------------------------------------------------- */ + +/* + * convert virtual user memory address to physical address + * (virt_to_phys only works for kmalloced kernel memory) + */ +inline unsigned long uvirt_to_phys(unsigned long adr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + + pgd = pgd_offset(current->mm, adr); + if (pgd_none(*pgd)) + return 0; + pmd = pmd_offset(pgd, adr); + if (pmd_none(*pmd)) + return 0; + ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); + pte = *ptep; + /* Note; page_address will panic for us if the page is high */ + if(pte_present(pte)) + return page_address(pte_page(pte))|(adr&(PAGE_SIZE-1)); + return 0; +} + +/* + * vmalloced address to physical address + */ +inline unsigned long kvirt_to_phys(unsigned long adr) +{ + return uvirt_to_phys(VMALLOC_VMADDR(adr)); +} + +/* + * vmalloced address to bus address + */ +inline unsigned long kvirt_to_bus(unsigned long adr) +{ + return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); +} + +inline int order(unsigned long size) +{ + int ordr = 0; + size = (size+PAGE_SIZE-1)/PAGE_SIZE; + while (size) { + size /= 2; + ordr++; + } + return ordr; +} + +void* bmalloc(unsigned long size) +{ + void* mem; +#ifdef CONFIG_BIGPHYS_AREA + mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL); +#else + /* + * The following function got a lot of memory at boottime, + * so we know its always there... + */ + mem = (void*)__get_free_pages(GFP_USER,order(size)); +#endif + if (mem) { + unsigned long adr = (unsigned long)mem; + while (size > 0) { + mem_map_reserve(MAP_NR(phys_to_virt(adr))); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + return mem; +} + +void bfree(void* mem, unsigned long size) +{ + if (mem) { + unsigned long adr = (unsigned long)mem; + unsigned long siz = size; + while (siz > 0) { + mem_map_unreserve(MAP_NR(phys_to_virt(adr))); + adr += PAGE_SIZE; + siz -= PAGE_SIZE; + } +#ifdef CONFIG_BIGPHYS_AREA + bigphysarea_free_pages(mem); +#else + free_pages((unsigned long)mem,order(size)); +#endif + } +} diff --git a/drivers/char/zr36120_mem.h b/drivers/char/zr36120_mem.h new file mode 100644 index 000000000000..609f0a1a9a4f --- /dev/null +++ b/drivers/char/zr36120_mem.h @@ -0,0 +1,17 @@ +extern inline unsigned long uvirt_to_phys(unsigned long adr); + +/* vmalloced address to physical address */ +extern inline unsigned long kvirt_to_phys(unsigned long adr) +{ return uvirt_to_phys(VMALLOC_VMADDR(adr)); } + +/* vmalloced address to bus address */ +extern inline unsigned long kvirt_to_bus(unsigned long adr) +{ return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); } + +/* always vmalloced memory - not always continuous! */ +void* rvmalloc(unsigned long size); +void rvfree(void* mem, unsigned long size); + +/* either kmalloc() or bigphysarea() alloced memory - continuous */ +void* bmalloc(unsigned long size); +void bfree(void* mem, unsigned long size); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 37eb785f9faf..1371c31abf82 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -120,7 +120,7 @@ struct cardinfo_table cardinfo[] = { "SK NET TR 4/16 ISA"}, { TMS_PCI, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, "Compaq 4/16 TR PCI"}, - { TMS_PCI, PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_TR, + { TMS_PCI, PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, "SK NET TR 4/16 PCI"}, { TMS_PCI, PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, "Thomas-Conrad TC4048 PCI 4/16"}, diff --git a/drivers/net/wavelan.c b/drivers/net/wavelan.c index 2dd4eaa12002..73771fc96ce1 100644 --- a/drivers/net/wavelan.c +++ b/drivers/net/wavelan.c @@ -1910,18 +1910,18 @@ wavelan_ioctl(struct net_device * dev, /* device on which the ioctl is applied * case SIOCSIWNWID: /* Set NWID in WaveLAN. */ - if(wrq->u.nwid.on) + if(!wrq->u.nwid.disabled) { - /* Set NWID in psa. */ - psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; - psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; + /* Set NWID in psa */ + psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; + psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; psa.psa_nwid_select = 0x01; psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, (unsigned char *)psa.psa_nwid, 3); /* Set NWID in mmc. */ - m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF; - m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8; + m.w.mmw_netw_id_l = psa.psa_nwid[1]; + m.w.mmw_netw_id_h = psa.psa_nwid[0]; mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); @@ -1945,8 +1945,9 @@ wavelan_ioctl(struct net_device * dev, /* device on which the ioctl is applied * /* Read the NWID. */ psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, (unsigned char *)psa.psa_nwid, 3); - wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; - wrq->u.nwid.on = psa.psa_nwid_select; + wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; + wrq->u.nwid.disabled = !(psa.psa_nwid_select); + wrq->u.nwid.fixed = 1; /* Superfluous */ break; case SIOCSIWFREQ: @@ -2006,83 +2007,96 @@ wavelan_ioctl(struct net_device * dev, /* device on which the ioctl is applied * wrq->u.sens.fixed = 1; break; - case SIOCSIWENCODE: - /* Set encryption key. */ - if(!mmc_encr(ioaddr)) - { - ret = -EOPNOTSUPP; - break; - } - - if(wrq->u.encoding.method) - { /* Enable encryption. */ - int i; - long long key = wrq->u.encoding.code; - - for(i = 7; i >= 0; i--) - { - psa.psa_encryption_key[i] = key & 0xFF; - key >>= 8; - } - psa.psa_encryption_select = 1; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 8+1); - - mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), - MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); - mmc_write(ioaddr, mmwoff(0, mmw_encr_key), - (unsigned char *) &psa.psa_encryption_key, 8); - } - else - { /* Disable encryption. */ - psa.psa_encryption_select = 0; - psa_write(ioaddr, lp->hacr, - (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1); - - mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); - } - /* update the Wavelan checksum */ - update_psa_checksum(dev, ioaddr, lp->hacr); - break; - - case SIOCGIWENCODE: - /* Read the encryption key. */ - if(!mmc_encr(ioaddr)) - { - ret = -EOPNOTSUPP; - break; - } - - /* Only super-user can see encryption key. */ - if(!suser()) - { - ret = -EPERM; - break; - } - else - { - int i; - long long key = 0; - - psa_read(ioaddr, lp->hacr, + case SIOCSIWENCODE: + /* Set encryption key */ + if(!mmc_encr(ioaddr)) + { + ret = -EOPNOTSUPP; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + /* Check the size of the key */ + if(wrq->u.encoding.length != 8) + { + ret = -EINVAL; + break; + } + + /* Copy the key in the driver */ + if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, + wrq->u.encoding.length)) + { + ret = -EFAULT; + break; + } + + psa.psa_encryption_select = 1; + psa_write(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 8+1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), + MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); + mmc_write(ioaddr, mmwoff(0, mmw_encr_key), + (unsigned char *) &psa.psa_encryption_key, 8); + } + + if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) + { /* disable encryption */ + psa.psa_encryption_select = 0; + psa_write(ioaddr, lp->hacr, (char *) &psa.psa_encryption_select - (char *) &psa, - (unsigned char *) &psa.psa_encryption_select, 1+8); - for(i = 0; i < 8; i++) - { - key <<= 8; - key += psa.psa_encryption_key[i]; - } - wrq->u.encoding.code = key; - - /* encryption is enabled */ - if(psa.psa_encryption_select) - wrq->u.encoding.method = mmc_encr(ioaddr); - else - wrq->u.encoding.method = 0; - } - break; + (unsigned char *) &psa.psa_encryption_select, 1); + + mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); + } + /* update the Wavelan checksum */ + update_psa_checksum(dev, ioaddr, lp->hacr); + break; + + case SIOCGIWENCODE: + /* Read the encryption key */ + if(!mmc_encr(ioaddr)) + { + ret = -EOPNOTSUPP; + break; + } + + /* only super-user can see encryption key */ + if(!suser()) + { + ret = -EPERM; + break; + } + + /* Basic checking... */ + if(wrq->u.encoding.pointer != (caddr_t) 0) + { + /* Verify the user buffer */ + ret = verify_area(VERIFY_WRITE, wrq->u.encoding.pointer, 8); + if(ret) + break; + + psa_read(ioaddr, lp->hacr, + (char *) &psa.psa_encryption_select - (char *) &psa, + (unsigned char *) &psa.psa_encryption_select, 1+8); + + /* encryption is enabled ? */ + if(psa.psa_encryption_select) + wrq->u.encoding.flags = IW_ENCODE_ENABLED; + else + wrq->u.encoding.flags = IW_ENCODE_DISABLED; + wrq->u.encoding.flags |= mmc_encr(ioaddr); + + /* Copy the key to the user buffer */ + wrq->u.encoding.length = 8; + if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) + ret = -EFAULT; + } + break; case SIOCGIWRANGE: /* basic checking */ @@ -2117,6 +2131,19 @@ wavelan_ioctl(struct net_device * dev, /* device on which the ioctl is applied * range.num_bitrates = 1; range.bitrate[0] = 2000000; /* 2 Mb/s */ + /* Encryption supported ? */ + if(mmc_encr(ioaddr)) + { + range.encoding_size[0] = 8; /* DES = 64 bits key */ + range.num_encoding_sizes = 1; + range.max_encoding_tokens = 1; /* Only one key possible */ + } + else + { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } + /* Copy structure to the user buffer. */ if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range))) ret = -EFAULT; diff --git a/drivers/net/wavelan.p.h b/drivers/net/wavelan.p.h index fc43ce303771..e4b722cf1373 100644 --- a/drivers/net/wavelan.p.h +++ b/drivers/net/wavelan.p.h @@ -300,6 +300,11 @@ * - Add the (short) list of bit-rates in range * - Developp a new sensitivity... (sens.value & sens.fixed) * + * Changes made for release in 2.2.14 & 2.3.23 : + * ------------------------------------------- + * - Fix check for root permission (break instead of exit) + * - New nwid & encoding setting (Wireless Extension 9) + * * Wishes & dreams: * ---------------- * - roaming (see Pcmcia driver) @@ -390,7 +395,7 @@ /************************ CONSTANTS & MACROS ************************/ #ifdef DEBUG_VERSION_SHOW -static const char *version = "wavelan.c : v20 (wireless extensions) 29/7/99\n"; +static const char *version = "wavelan.c : v21 (wireless extensions) 16/10/99\n"; #endif /* Watchdog temporisation */ diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 6c3835089a10..240453144db6 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1247,7 +1247,7 @@ static int sd_init_onedisk(int i) SCpnt->sense_buffer[2] = 0; sd_wait_cmd (SCpnt, (void *) cmd, (void *) buffer, - 512, sd_init_done, SD_TIMEOUT, MAX_RETRIES); + 0/*512*/, sd_init_done, SD_TIMEOUT, MAX_RETRIES); the_result = SCpnt->result; retries++; diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index e3218180279a..8610c17e052c 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -11,8 +11,11 @@ dep_tristate ' C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then - bool ' Enable legacy FM' CONFIG_SOUND_CMPCI_FM - bool ' Enable legacy MPU-401' CONFIG_SOUND_CMPCI_MIDI + bool ' Enable S/PDIF loop for CMI8738' CONFIG_SOUND_CMPCI_SPDIFLOOP + bool ' Enable 4 channel mode for CMI8738' CONFIG_SOUND_CMPCI_4CH + if [ "$CONFIG_SOUND_CMPCI_4CH" = "y" ]; then + bool ' Separate rear out jack' CONFIG_SOUND_CMPCI_REAR + fi fi dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c index 81663c8db13c..fc2083e3485d 100644 --- a/drivers/sound/cmpci.c +++ b/drivers/sound/cmpci.c @@ -21,7 +21,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * Special thanks to David C. Niemi + * Special thanks to David C. Niemi, Jan Pfeifer * * * Module command line parameters: @@ -59,8 +59,43 @@ * read/write cannot be executed * 20 09 99 0.13 merged the generic changes in sonicvibes since this * diverged. + * 18.08.99 1.5 Only deallocate DMA buffer when unloading. + * 02.09.99 1.6 Enable SPDIF LOOP + * Change the mixer read back + * 21.09.99 2.33 Use RCS version aas driver version. + * Add support for modem, S/PDIF loop and 4 channels. + * (8738 only) + * Fix bug cause x11amp cannot play. + * $Log: cmpci.c,v $ + * Revision 2.41 1999/10/27 02:00:05 cltien + * Now the fragsize for modem is activated by parameter. + * + * Revision 2.40 1999/10/26 23:38:26 cltien + * Remove debugging message in cm_write which may cause module counter not 0. + * + * Revision 2.39 1999/10/26 21:52:50 cltien + * I forgor too adjust mic recording volume, as it should be moved to 5MUTEMONO. + * Change the DYNAMIC macro to FIXEDDMA, which means static DMA buffer. + * + * Revision 2.38 1999/10/08 21:59:03 cltien + * Set FLINKON and reset FLINKOFF for modem. + * + * Revision 2.37 1999/09/28 02:57:04 cltien + * Add set_bus_master() to make sure bus master enabled. + * + * Revision 2.36 1999/09/22 14:15:03 cltien + * Use open_sem to avoid multiple access to open_mode. + * Use wakeup in IntrClose to activate process in waiting queue. + * + * Revision 2.35 1999/09/22 13:20:53 cltien + * Use open_mode to check if DAC in used. Also more check in IntrWrite and IntrClose. Now the modem can access DAC safely. + * + * Revision 2.34 1999/09/22 03:29:57 cltien + * Use module count to decide which one to access the dac. + * + * */ - + /*****************************************************************************/ #include @@ -252,6 +287,7 @@ struct cm_state { unsigned fragsize; unsigned dmasize; unsigned fragsamples; + unsigned dmasamples; /* OSS stuff */ unsigned mapped:1; unsigned ready:1; @@ -276,6 +312,7 @@ struct cm_state { /* --------------------------------------------------------------------- */ static struct cm_state *devs = NULL; +static struct cm_state *devaudio = NULL; static unsigned long wavetable_mem = 0; /* --------------------------------------------------------------------- */ @@ -331,7 +368,7 @@ static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1); outw(count, s->iobase + CODEC_CMI_CH0_FRAME2); outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) & ~1, s->iobase + CODEC_CMI_FUNCTRL0); - outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2); +// outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2); } static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count) @@ -340,13 +377,16 @@ static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1); outw(count, s->iobase + CODEC_CMI_CH1_FRAME2); outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) | 2, s->iobase + CODEC_CMI_FUNCTRL0); - outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2); +// outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2); } extern __inline__ unsigned get_dmadac(struct cm_state *s) { unsigned int curr_addr; + if (!s->dma_dac.dmasize || !(s->enable & CM_CENABLE_PE)) + return 0; + curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1); curr_addr -= virt_to_bus(s->dma_dac.rawbuf); curr_addr = s->dma_dac.dmasize - curr_addr; @@ -358,6 +398,9 @@ extern __inline__ unsigned get_dmaadc(struct cm_state *s) { unsigned int curr_addr; + if (!s->dma_adc.dmasize || !(s->enable & CM_CENABLE_RE)) + return 0; + curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1); curr_addr -= virt_to_bus(s->dma_adc.rawbuf); curr_addr = s->dma_adc.dmasize - curr_addr; @@ -421,7 +464,7 @@ static struct { { 22050, (16000 + 22050) / 2, (22050 + 32000) / 2, 2 }, { 32000, (22050 + 32000) / 2, (32000 + 44100) / 2, 6 }, { 44100, (32000 + 44100) / 2, (44100 + 48000) / 2, 3 }, - { 48000, 48000, 48000, 7 } + { 48000, (44100 + 48000) /2, 48000, 7 } }; static void set_dac_rate(struct cm_state *s, unsigned rate) @@ -485,10 +528,12 @@ extern inline void stop_adc(struct cm_state *s) unsigned long flags; spin_lock_irqsave(&s->lock, flags); + /* disable channel */ + outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); s->enable &= ~CM_CENABLE_RE; /* disable interrupt */ outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2); - /* disable channel and reset */ + /* reset */ outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2); udelay(10); outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2); @@ -500,10 +545,12 @@ extern inline void stop_dac(struct cm_state *s) unsigned long flags; spin_lock_irqsave(&s->lock, flags); + /* disable channel */ s->enable &= ~CM_CENABLE_PE; + outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable interrupt */ outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2); - /* disable channel and reset */ + /* reset */ outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2); udelay(10); outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2); @@ -516,10 +563,10 @@ static void start_dac(struct cm_state *s) spin_lock_irqsave(&s->lock, flags); if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { + outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2); s->enable |= CM_CENABLE_PE; outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); } - outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2); spin_unlock_irqrestore(&s->lock, flags); } @@ -530,10 +577,10 @@ static void start_adc(struct cm_state *s) spin_lock_irqsave(&s->lock, flags); if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) && s->dma_adc.ready) { + outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2); s->enable |= CM_CENABLE_RE; outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); } - outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2); spin_unlock_irqrestore(&s->lock, flags); } @@ -593,10 +640,10 @@ static int prog_dmabuf(struct cm_state *s, unsigned rec) return -ENOMEM; db->buforder = order; if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff) - printk(KERN_DEBUG "cm: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", + printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n", virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff) - printk(KERN_DEBUG "cm: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", + printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n", virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder); /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */ mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); @@ -623,17 +670,21 @@ static int prog_dmabuf(struct cm_state *s, unsigned rec) db->fragsize = 1 << db->fragshift; if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag) db->numfrag = db->ossmaxfrags; -#if 1 - /* to make fragsize >= 4096 */ - while (db->fragsize < 4096 && db->numfrag >= 4) - { - db->fragsize *= 2; - db->fragshift++; - db->numfrag /= 2; + /* to make fragsize >= 4096 */ +#if 0 + if(s->modem) + { + while (db->fragsize < 4096 && db->numfrag >= 4) + { + db->fragsize *= 2; + db->fragshift++; + db->numfrag /= 2; + } } -#endif +#endif db->fragsamples = db->fragsize >> sample_shift[fmt]; db->dmasize = db->numfrag << db->fragshift; + db->dmasamples = db->dmasize >> sample_shift[fmt]; memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize); spin_lock_irqsave(&s->lock, flags); if (rec) { @@ -665,6 +716,7 @@ extern __inline__ void clear_advance(struct cm_state *s) len -= x; } memset(buf + bptr, c, len); + outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2); } /* call with spinlock held! */ @@ -752,25 +804,26 @@ static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned int intsrc, intstat; /* fastpath out, to ease interrupt sharing */ - intsrc = inb(s->iobase + CODEC_CMI_INT_STATUS); - if (!(intsrc & (CM_INT_CH0 | CM_INT_CH1))) + intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS); + if (!(intsrc & 0x80000000)) return; spin_lock(&s->lock); intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2); - /* disable interrupt */ + /* acknowledge interrupt */ if (intsrc & CM_INT_CH0) + { outb(intstat & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2); + udelay(10); + outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2); + } if (intsrc & CM_INT_CH1) + { outb(intstat & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2); + udelay(10); + outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2); + } cm_update_ptr(s); -#ifdef SOUND_CONFIG_CMPCI_MIDI cm_handle_midi(s); -#endif - /* enable interrupt */ - if (intsrc & CM_INT_CH0) - outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2); - if (intsrc & CM_INT_CH1) - outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2); spin_unlock(&s->lock); } @@ -788,7 +841,7 @@ static void cm_midi_timer(unsigned long data) /* --------------------------------------------------------------------- */ -static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n"; +static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n"; #ifdef CONFIG_SOUND_CMPCI /* support multiple chips */ #define VALIDATE_STATE(s) @@ -808,6 +861,7 @@ static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n"; #define MT_5MUTE 2 #define MT_4MUTEMONO 3 #define MT_6MUTE 4 +#define MT_5MUTEMONO 5 static const struct { unsigned left; @@ -818,7 +872,7 @@ static const struct { } mixtable[SOUND_MIXER_NRDEVICES] = { [SOUND_MIXER_CD] = { DSP_MIX_CDVOLIDX_L, DSP_MIX_CDVOLIDX_R, MT_5MUTE, 0x04, 0x02 }, [SOUND_MIXER_LINE] = { DSP_MIX_LINEVOLIDX_L, DSP_MIX_LINEVOLIDX_R, MT_5MUTE, 0x10, 0x08 }, - [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, CODEC_CMI_MIXER2, MT_4MUTEMONO, 0x01, 0x01 }, + [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 }, [SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 }, [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 }, [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 } @@ -851,10 +905,16 @@ static int return_mixval(struct cm_state *s, unsigned i, int *arg) r = l; break; + case MT_5MUTEMONO: + r = l; + rl = 100 - 3 * ((l >> 3) & 31); + rr = rl; + break; + case MT_5MUTE: default: - rl = 100 - 3 * (l & 31); - rr = 100 - 3 * (r & 31); + rl = 100 - 3 * ((l >> 3) & 31); + rr = 100 - 3 * ((r >> 3) & 31); break; case MT_6MUTE: @@ -992,7 +1052,7 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) } spin_lock_irqsave(&s->lock, flags); wrmixer(s, DSP_MIX_ADCMIXIDX_L, j); - wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | j>>1); + wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1)); spin_unlock_irqrestore(&s->lock, flags); return 0; @@ -1041,6 +1101,14 @@ static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg) outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2); break; + case MT_5MUTEMONO: + r = l; + rl = l < 4 ? 0 : (l - 5) / 3; + rr = rl >> 2; + wrmixer(s, mixtable[i].left, rl<<3); + outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2); + break; + case MT_5MUTE: rl = l < 4 ? 0 : (l - 5) / 3; rr = r < 4 ? 0 : (r - 5) / 3; @@ -1154,10 +1222,10 @@ static int drain_dac(struct cm_state *s, int nonblock) current->state = TASK_RUNNING; return -EBUSY; } - tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac; + tmo = (count * HZ) / s->ratedac; tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]; - if (!schedule_timeout(tmo + 1)) - printk(KERN_DEBUG "cm: dma timed out??\n"); + if (!schedule_timeout(tmo ? : 1) && tmo) + printk(KERN_DEBUG "cmpci: dma timed out??\n"); } remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; @@ -1204,7 +1272,18 @@ static ssize_t cm_read(struct file *file, char *buffer, size_t count, loff_t *pp start_adc(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_adc.wait); + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + spin_lock_irqsave(&s->lock, flags); + set_dmaadc(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.dmasamples); + /* program sample counts */ + outw(s->dma_adc.fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -1264,7 +1343,18 @@ static ssize_t cm_write(struct file *file, const char *buffer, size_t count, lof start_dac(s); if (file->f_flags & O_NONBLOCK) return ret ? ret : -EAGAIN; - interruptible_sleep_on(&s->dma_dac.wait); + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + spin_lock_irqsave(&s->lock, flags); + set_dmadac(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.dmasamples); + /* program sample counts */ + outw(s->dma_dac.fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2); + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -1730,7 +1820,6 @@ static /*const*/ struct file_operations cm_audio_fops = { NULL, /* lock */ }; -#ifdef CONFIG_SOUND_CMPCI_MIDI /* --------------------------------------------------------------------- */ static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) @@ -1971,7 +2060,7 @@ static int cm_midi_release(struct inode *inode, struct file *file) } tmo = (count * HZ) / 3100; if (!schedule_timeout(tmo ? : 1) && tmo) - printk(KERN_DEBUG "cm: midi timed out??\n"); + printk(KERN_DEBUG "cmpci: midi timed out??\n"); } remove_wait_queue(&s->midi.owait, &wait); set_current_state(TASK_RUNNING); @@ -2011,11 +2100,9 @@ static /*const*/ struct file_operations cm_midi_fops = { NULL, /* revalidate */ NULL, /* lock */ }; -#endif /* --------------------------------------------------------------------- */ -#ifdef CONFIG_SOUND_CMPCI_FM static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { static const unsigned char op_offset[18] = { @@ -2187,7 +2274,6 @@ static /*const*/ struct file_operations cm_dmfm_fops = { NULL, /* revalidate */ NULL, /* lock */ }; -#endif /* CONFIG_SOUND_CMPCI_FM */ /* --------------------------------------------------------------------- */ @@ -2215,8 +2301,31 @@ static struct initvol { }; #ifdef MODULE -int __init init_module(void) +static int spdif_loop = 0; +static int four_ch = 0; +static int rear_out = 0; +MODULE_PARM(spdif_loop, "i"); +MODULE_PARM(four_ch, "i"); +MODULE_PARM(rear_out, "i"); + +int __init init_module(void) +#else +#ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP +static int spdif_loop = 1; #else +static int spdif_loop = 0; +#endif +#ifdef CONFIG_SOUND_CMPCI_4CH +static int four_ch = 1; +#else +static int four_ch = 0; +#endif +#ifdef CONFIG_SOUND_CMPCI_REAR +static int rear_out = 1; +#else +static int read_out = 0; +#endif + int __init init_cmpci(void) #endif { @@ -2224,6 +2333,7 @@ int __init init_cmpci(void) struct pci_dev *pcidev = NULL; mm_segment_t fs; int i, val, index = 0; + struct { unsigned short deviceid; char *devicename; @@ -2239,10 +2349,10 @@ int __init init_cmpci(void) if (!pci_present()) /* No PCI bus in this machine! */ #endif return -ENODEV; - printk(KERN_INFO "cm: version v1.1 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "cmpci: version v2.41-nomodem time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) - printk(KERN_INFO "cm: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); + printk(KERN_INFO "cmpci: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); #endif while (index < NR_DEVICE && pcidev == NULL && ( (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)) || @@ -2251,7 +2361,7 @@ int __init init_cmpci(void) if (pcidev->irq == 0) continue; if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) { - printk(KERN_WARNING "cm: out of memory\n"); + printk(KERN_WARNING "cmpci: out of memory\n"); continue; } /* search device name */ @@ -2272,65 +2382,60 @@ int __init init_cmpci(void) init_MUTEX(&s->open_sem); s->magic = CM_MAGIC; s->iobase = pcidev->resource[0].start; -#ifdef CONFIG_SOUND_CMPCI_FM s->iosynth = 0x388; -#endif -#ifdef CONFIG_SOUND_CMPCI_MIDI s->iomidi = 0x330; -#endif if (s->iobase == 0) continue; s->irq = pcidev->irq; if (check_region(s->iobase, CM_EXTENT_CODEC)) { - printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1); + printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1); goto err_region5; } request_region(s->iobase, CM_EXTENT_CODEC, "cmpci"); -#ifdef CONFIG_SOUND_CMPCI_MIDI if (check_region(s->iomidi, CM_EXTENT_MIDI)) { - printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1); - goto err_region4; + printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, midi disabled.\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1); + s->iomidi = 0; + } + else + { + request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi"); + /* set IO based at 0x330 */ + outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3); } - request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi"); - /* set IO based at 0x330 */ - outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3); -#endif -#ifdef CONFIG_SOUND_CMPCI_FM if (check_region(s->iosynth, CM_EXTENT_SYNTH)) { - printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1); - goto err_region1; + printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, synth disabled.\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1); + s->iosynth = 0; + } + else + { + request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM"); + /* enable FM */ + outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL); } - request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM"); - /* enable FM */ - outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL); -#endif /* initialize codec registers */ outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */ - outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* reset channels */ + outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */ /* reset mixer */ wrmixer(s, DSP_MIX_DATARESETIDX, 0); /* request irq */ if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) { - printk(KERN_ERR "cm: irq %u in use\n", s->irq); + printk(KERN_ERR "cmpci: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "cm: found %s adapter at io %#06x irq %u\n", + printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n", devicename, s->iobase, s->irq); /* register devices */ if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) goto err_dev1; if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0) goto err_dev2; -#ifdef CONFIG_SOUND_CMPCI_MIDI - if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0) + if (s->iomidi && (s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0) goto err_dev3; -#endif -#ifdef CONFIG_SOUND_CMPCI_FM - if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0) + if (s->iosynth && (s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0) goto err_dev4; -#endif + pci_set_master(pcidev); /* initialize the chips */ fs = get_fs(); set_fs(KERNEL_DS); @@ -2344,6 +2449,38 @@ int __init init_cmpci(void) mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); } set_fs(fs); + if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738) + { + /* enable SPDIF loop */ + if (spdif_loop) + { + /* turn on spdif-in to spdif-out */ + outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 0x80, s->iobase + CODEC_CMI_FUNCTRL1); + printk(KERN_INFO "cmpci: Enable SPDIF loop\n"); + } + else + outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~0x80, s->iobase + CODEC_CMI_FUNCTRL1); + /* enable 4 channels mode */ + if (four_ch) + { + /* 4 channel mode (analog duplicate) */ + outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) | 0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3); + printk(KERN_INFO "cmpci: Enable 4 channels mode\n"); + /* has separate rear-out jack ? */ + if (rear_out) + { + /* has separate rear out jack */ + outb(inb(s->iobase + CODEC_CMI_MIXER1) & ~0x20, s->iobase + CODEC_CMI_MIXER1); + } + else + { + outb(inb(s->iobase + CODEC_CMI_MIXER1) | 0x20, s->iobase + CODEC_CMI_MIXER1); + printk(KERN_INFO "cmpci: line-in routed as rear-out\n"); + } + } + else + outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) & ~0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3); + } /* queue it for later freeing */ s->next = devs; devs = s; @@ -2357,16 +2494,14 @@ int __init init_cmpci(void) err_dev2: unregister_sound_dsp(s->dev_audio); err_dev1: - printk(KERN_ERR "cm: cannot register misc device\n"); + printk(KERN_ERR "cmpci: cannot register misc device\n"); free_irq(s->irq, s); err_irq: -#ifdef CONFIG_SOUND_CMPCI_FM - release_region(s->iosynth, CM_EXTENT_SYNTH); + if(s->iosynth) + release_region(s->iosynth, CM_EXTENT_SYNTH); err_region1: -#endif -#ifdef CONFIG_SOUND_CMPCI_MIDI - release_region(s->iomidi, CM_EXTENT_MIDI); -#endif + if(s->iomidi) + release_region(s->iomidi, CM_EXTENT_MIDI); err_region4: release_region(s->iobase, CM_EXTENT_CODEC); err_region5: @@ -2395,32 +2530,30 @@ void cleanup_module(void) devs = devs->next; outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */ synchronize_irq(); - outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* reset channels */ + outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */ free_irq(s->irq, s); /* reset mixer */ wrmixer(s, DSP_MIX_DATARESETIDX, 0); release_region(s->iobase, CM_EXTENT_CODEC); -#ifdef CONFIG_SOUND_CMPCI_MIDI - release_region(s->iomidi, CM_EXTENT_MIDI); -#endif -#ifdef CONFIG_SOUND_CMPCI_FM - release_region(s->iosynth, CM_EXTENT_SYNTH); -#endif + if(s->iomidi) + { + release_region(s->iomidi, CM_EXTENT_MIDI); + unregister_sound_midi(s->dev_midi); + } + if(s->iosynth) + { + release_region(s->iosynth, CM_EXTENT_SYNTH); + unregister_sound_special(s->dev_dmfm); + } unregister_sound_dsp(s->dev_audio); unregister_sound_mixer(s->dev_mixer); -#ifdef CONFIG_SOUND_CMPCI_MIDI - unregister_sound_midi(s->dev_midi); -#endif -#ifdef CONFIG_SOUND_CMPCI_FM - unregister_sound_special(s->dev_dmfm); -#endif kfree_s(s, sizeof(struct cm_state)); } if (wavetable_mem) free_pages(wavetable_mem, 20-PAGE_SHIFT); - printk(KERN_INFO "cm: unloading\n"); + printk(KERN_INFO "cmpci: unloading\n"); } #endif /* MODULE */ diff --git a/drivers/video/Config.in b/drivers/video/Config.in index e9ab31ccb49f..cfd80db9e74f 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -14,7 +14,7 @@ if [ "$CONFIG_FB" = "y" ]; then bool ' nVidia Riva support (EXPERIMENTAL)' CONFIG_FB_RIVA fi if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then - tristate ' Cirrus Logic suport (EXPERIMENTAL)' CONFIG_FB_CLGEN + tristate ' Cirrus Logic support (EXPERIMENTAL)' CONFIG_FB_CLGEN tristate ' Permedia2 support (EXPERIMENTAL)' CONFIG_FB_PM2 if [ "$CONFIG_FB_PM2" = "y" ]; then if [ "$CONFIG_PCI" = "y" ]; then diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index d96f7edecb1f..ede497bed3a3 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -15,6 +15,7 @@ * 1997-08-09 removed extension stripping, locking cleanup */ +#include #include #include diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h index ea30675483aa..17c61130aa9c 100644 --- a/include/asm-alpha/page.h +++ b/include/asm-alpha/page.h @@ -106,16 +106,7 @@ typedef unsigned long pgprot_t; #endif /* STRICT_MM_TYPECHECKS */ -#if 0 #define BUG() __asm__ __volatile__("call_pal 129 # bugchk") -#else -/* hack to see the BUG() information in the early boot stage */ -#define BUG() \ -do { \ - SRM_printf("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - halt(); \ -} while(0) -#endif #define PAGE_BUG(page) BUG() #endif /* !ASSEMBLY */ diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index 22fe23868d67..880f0f4bb0c7 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -363,17 +363,6 @@ __xchg(unsigned long x, volatile void * ptr, int size) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) #define tas(ptr) (xchg((ptr),1)) -/* Very dirty but nevertheless very fun hack ;). I recall the aboot printf() - that will in turn use the SRM console to do the debugging of the boot - process. As there's no runtime symbol table, the address of printf() - is hardwired and is in function of the bootlx binary you have in /boot... - 1999 Andrea Arcangeli */ -#if 0 -#define SRM_printf(args...) ({ int (*__SRM_printf)(const char *fmt, ...) = (int (*)(const char *fmt, ...)) 0x20000aa0; __SRM_printf(args); }) -#else -#define SRM_printf(args...) -#endif - #endif /* __ASSEMBLY__ */ #endif diff --git a/include/asm-arm/arch-cl7500/acornfb.h b/include/asm-arm/arch-cl7500/acornfb.h index 12240d8d6b81..567d53973fd8 100644 --- a/include/asm-arm/arch-cl7500/acornfb.h +++ b/include/asm-arm/arch-cl7500/acornfb.h @@ -1,3 +1,4 @@ +#include #define acornfb_valid_pixrate(rate) (rate >= 39325 && rate <= 40119) static inline void diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index 864d3b47f5b3..f22867eecb19 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -4,8 +4,6 @@ #ifndef _ASMARM_PGTABLE_H #define _ASMARM_PGTABLE_H -#include - #include #include #include diff --git a/include/asm-arm/processor.h b/include/asm-arm/processor.h index f2e258e81293..ce080d4adcd3 100644 --- a/include/asm-arm/processor.h +++ b/include/asm-arm/processor.h @@ -7,7 +7,6 @@ #ifndef __ASM_ARM_PROCESSOR_H #define __ASM_ARM_PROCESSOR_H -#include /* * Default implementation of macro that returns current * instruction pointer ("program counter"). diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h index 3b0f4c55b6c6..12f25731f11d 100644 --- a/include/asm-i386/highmem.h +++ b/include/asm-i386/highmem.h @@ -20,6 +20,7 @@ #ifdef __KERNEL__ +#include #include #include #include diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 894055a7df92..0a2e01c3617e 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h @@ -79,10 +79,10 @@ extern void init_8259A(int aeoi); extern void FASTCALL(send_IPI_self(int vector)); extern void init_VISWS_APIC_irqs(void); extern void setup_IO_APIC(void); +extern void disable_IO_APIC(void); +extern void print_IO_APIC(void); extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); extern void send_IPI(int dest, int vector); -extern void init_pic_mode(void); -extern void print_IO_APIC(void); extern unsigned long io_apic_irqs; extern volatile unsigned long irq_err_count; diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 2aa6aec4e4e4..3425c2cd1834 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -174,6 +174,7 @@ extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; extern void smp_flush_tlb(void); extern int get_maxlvt(void); +extern void disable_local_APIC (void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); extern void smp_invalidate_rcv(void); /* Process an NMI */ diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h index a10ed9c5c5d8..cf66557f943a 100644 --- a/include/asm-i386/spinlock.h +++ b/include/asm-i386/spinlock.h @@ -36,7 +36,7 @@ typedef struct { unsigned long a[100]; } __dummy_lock_t; ".previous" #define spin_unlock_string \ - "lock ; btrl $0,%0" + "movb $0,%0" #define spin_lock(lock) \ __asm__ __volatile__( \ diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 65dc6864785b..96dbd7a54b9c 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -12,6 +12,7 @@ extern unsigned long max_low_pfn; +extern unsigned long __init bootmem_bootmap_pages (unsigned long); extern unsigned long __init init_bootmem (unsigned long addr, unsigned long memend); extern void __init reserve_bootmem (unsigned long addr, unsigned long size); extern void __init free_bootmem (unsigned long addr, unsigned long size); diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 7091d50870a4..d9cedda121fa 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -354,6 +354,8 @@ struct video_code #define VID_HARDWARE_TRUST 22 /* Trust FM Radio */ #define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */ #define VID_HARDWARE_CPIA 24 +#define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */ +#define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ /* * Initialiser list diff --git a/include/linux/wireless.h b/include/linux/wireless.h index acc0619eb5e5..868f812acbfb 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 8 28.7.99 + * Version : 9 16.10.99 * * Authors : Jean Tourrilhes - HPL - */ @@ -63,7 +63,7 @@ * (there is some stuff that will be added in the future...) * I just plan to increment with each new version. */ -#define WIRELESS_EXT 8 +#define WIRELESS_EXT 9 /* * Changes : @@ -96,6 +96,14 @@ * - Changed my e-mail address * - More 802.11 support (nickname, rate, rts, frag) * - List index in frequencies + * + * V8 to V9 + * -------- + * - Support for 'mode of operation' (ad-hoc, managed...) + * - Support for unicast and multicast power saving + * - Change encoding to support larger tokens (>64 bits) + * - Updated iw_params (disable, flags) and use it for NWID + * - Extracted iw_point from iwreq for clarity */ /* -------------------------- IOCTL LIST -------------------------- */ @@ -103,12 +111,12 @@ /* Basic operations */ #define SIOCSIWNAME 0x8B00 /* Unused ??? */ #define SIOCGIWNAME 0x8B01 /* get name */ -#define SIOCSIWNWID 0x8B02 /* set network id */ +#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */ #define SIOCGIWNWID 0x8B03 /* get network id */ #define SIOCSIWFREQ 0x8B04 /* set channel/frequency */ #define SIOCGIWFREQ 0x8B05 /* get channel/frequency */ -#define SIOCSIWENCODE 0x8B06 /* set encoding info */ -#define SIOCGIWENCODE 0x8B07 /* get encoding info */ +#define SIOCSIWMODE 0x8B06 /* set operation mode */ +#define SIOCGIWMODE 0x8B07 /* get operation mode */ #define SIOCSIWSENS 0x8B08 /* set sensitivity */ #define SIOCGIWSENS 0x8B09 /* get sensitivity */ @@ -146,11 +154,18 @@ #define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ #define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ +/* Encoding stuff (scrambling, hardware security, WEP...) */ +#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ +#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ +/* Power saving stuff (power management, unicast and multicast) */ +#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ +#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ + /* ------------------------- IOCTL STUFF ------------------------- */ /* The first and the last (range) */ #define SIOCIWFIRST 0x8B00 -#define SIOCIWLAST 0x8B25 +#define SIOCIWLAST 0x8B30 /* Even : get (world access), odd : set (root access) */ #define IW_IS_SET(cmd) (!((cmd) & 0x1)) @@ -200,9 +215,66 @@ /* Maximum size of the ESSID and NICKN strings */ #define IW_ESSID_MAX_SIZE 32 +/* Modes of operation */ +#define IW_MODE_AUTO 0 /* Let the driver decides */ +#define IW_MODE_ADHOC 1 /* Single cell network */ +#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ +#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ +#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ +#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ + +/* Maximum number of size of encoding token available + * they are listed in the range structure */ +#define IW_MAX_ENCODING_SIZES 8 + +/* Maximum size of the encoding token in bytes */ +#define IW_ENCODING_TOKEN_MAX 32 /* 256 bits (for now) */ + +/* Flags for encoding (along with the token) */ +#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ +#define IW_ENCODE_FLAGS 0xF000 /* Flags defined below */ +#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ +#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ +#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ +#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ + +/* Power management flags available (along with the value, if any) */ +#define IW_POWER_ON 0x0000 /* No details... */ +#define IW_POWER_TYPE 0xF000 /* Type of parameter */ +#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ +#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ +#define IW_POWER_MODE 0x0F00 /* Power Management mode */ +#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ +#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ +#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ +#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ +#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ + /****************************** TYPES ******************************/ /* --------------------------- SUBTYPES --------------------------- */ +/* + * Generic format for most parameters that fit in an int + */ +struct iw_param +{ + __s32 value; /* The value of the parameter itself */ + __u8 fixed; /* Hardware should not use auto select */ + __u8 disabled; /* Disable the feature */ + __u16 flags; /* Various specifc flags (if any) */ +}; + +/* + * For all data larger than 16 octets, we need to use a + * pointer to memory alocated in user space. + */ +struct iw_point +{ + caddr_t pointer; /* Pointer to the data (in user space) */ + __u16 length; /* number of fields or size in bytes */ + __u16 flags; /* Optional params */ +}; + /* * A frequency * For numbers lower than 10^9, we encode the number in 'm' and @@ -223,7 +295,7 @@ struct iw_freq */ struct iw_quality { - __u8 qual; /* link quality (SNR or better...) */ + __u8 qual; /* link quality (%retries, SNR or better...) */ __u8 level; /* signal level */ __u8 noise; /* noise level */ __u8 updated; /* Flags to know if updated */ @@ -240,33 +312,13 @@ struct iw_discarded __u32 misc; /* Others cases */ }; -/* - * Encoding information (setting and so on) - * Encoding might be hardware encryption, scrambing or others - */ -struct iw_encoding -{ - __u8 method; /* Algorithm number / key used */ - __u64 code; /* Data/key used for algorithm */ -}; - -/* - * Generic format for parameters - */ -struct iw_param -{ - __s32 value; /* The value of the parameter itself */ - __u8 fixed; /* Hardware should not use auto select */ -}; - - /* ------------------------ WIRELESS STATS ------------------------ */ /* * Wireless statistics (used for /proc/net/wireless) */ struct iw_statistics { - __u8 status; /* Status + __u16 status; /* Status * - device dependent for now */ struct iw_quality qual; /* Quality of the link @@ -295,37 +347,28 @@ struct iwreq union { /* Config - generic */ - char name[IFNAMSIZ]; + char name[IFNAMSIZ]; /* Name : used to verify the presence of wireless extensions. * Name of the protocol/provider... */ - struct /* network id (or domain) : used to to */ - { /* create logical channels on the air */ - __u32 nwid; /* value */ - __u8 on; /* active/unactive nwid */ - } nwid; - + struct iw_point essid; /* Extended network name */ + struct iw_param nwid; /* network id (or domain - the cell) */ struct iw_freq freq; /* frequency or channel : * 0-1000 = channel * > 1000 = frequency in Hz */ - struct iw_encoding encoding; /* Encoding stuff */ - - __u32 sensitivity; /* Obsolete, but compatible */ struct iw_param sens; /* signal level threshold */ struct iw_param bitrate; /* default bit rate */ struct iw_param rts; /* RTS threshold threshold */ struct iw_param frag; /* Fragmentation threshold */ + __u32 mode; /* Operation mode */ + + struct iw_point encoding; /* Encoding stuff : tokens */ + struct iw_param power; /* PM duration/timeout */ struct sockaddr ap_addr; /* Access point address */ - struct /* For all data bigger than 16 octets */ - { - caddr_t pointer; /* Pointer to the data - * (in user space) */ - __u16 length; /* fields or byte size */ - __u16 flags; /* Optional params */ - } data; + struct iw_point data; /* Other large parameters */ } u; }; @@ -366,9 +409,6 @@ struct iw_range /* Quality of link & SNR stuff */ struct iw_quality max_qual; /* Quality of the link */ - /* Encoder stuff */ - struct iw_encoding max_encoding; /* Encoding max range */ - /* Rates */ __u8 num_bitrates; /* Number of entries in the list */ __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ @@ -380,6 +420,17 @@ struct iw_range /* Frag threshold */ __s32 min_frag; /* Minimal frag threshold */ __s32 max_frag; /* Maximal frag threshold */ + + /* Power Management duration & timeout */ + __s32 min_pmd; /* Minimal PM duration */ + __s32 max_pmd; /* Maximal PM duration */ + __s32 min_pmt; /* Minimal PM timeout */ + __s32 max_pmt; /* Maximal PM timeout */ + + /* Encoder stuff */ + __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ + __u8 num_encoding_sizes; /* Number of entry in the list */ + __u8 max_encoding_tokens; /* Max number of tokens */ }; /* diff --git a/kernel/sched.c b/kernel/sched.c index 3f13728d6c57..e4980ecbcffa 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -254,10 +254,11 @@ static inline void reschedule_idle(struct task_struct * p, unsigned long flags) * wakeup, the frequent rescheduler will likely chose this * task during it's next schedule(): */ - tsk = cpu_curr(best_cpu); - if ((p->avg_slice < cacheflush_time) && - (tsk->avg_slice < cacheflush_time)) - goto out_no_target; + if (p->policy == SCHED_OTHER) { + tsk = cpu_curr(best_cpu); + if (p->avg_slice + tsk->avg_slice < cacheflush_time) + goto out_no_target; + } /* * We know that the preferred CPU has a cache-affine current diff --git a/mm/bootmem.c b/mm/bootmem.c index 270dfc8c99da..e0ab193dac96 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -28,6 +28,18 @@ unsigned long max_low_pfn; static void * bootmem_map = NULL; +/* return the number of _pages_ that will be allocated for the boot bitmap */ +unsigned long __init bootmem_bootmap_pages (unsigned long pages) +{ + unsigned long mapsize; + + mapsize = (pages+7)/8; + mapsize = (mapsize + ~PAGE_MASK) & PAGE_MASK; + mapsize >>= PAGE_SHIFT; + + return mapsize; +} + /* * Called once to set up the allocator itself. */ diff --git a/mm/highmem.c b/mm/highmem.c index c97a61ece407..e40eba4b587b 100644 --- a/mm/highmem.c +++ b/mm/highmem.c @@ -16,7 +16,6 @@ * Copyright (C) 1999 Ingo Molnar */ -#include #include #include #include