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
- 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
- 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
xterm-linux.xpm
- XPM image of penguin logo (see logo.txt) sitting on an xterm.
-
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
- 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
- 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
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
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).
--- /dev/null
+Driver for Trust Computer Products Framegrabber, version 0.6.1
+------ --- ----- -------- -------- ------------ ------- - - -
+
+- ZORAN ------------------------------------------------------
+ Author: Pauline Middelink <middelin@polyware.nl>
+ 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=<n>
+
+<n> 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. <TVCard editors behold!)
+ Dont forget to set video_input to the number of inputs
+ you defined in the video_mux part of the tvcard definition.
+ Its a common error to add a channel but not incrementing
+ video_input and getting angry with me/v4l/linux/linus :(
+
+You are now ready to test the framegrabber with your favorite
+video4linux compatible tool
+
+------ Application ----------------------------------------
+
+This device works with all Video4Linux compatible applications,
+given the limitations in the TODO file.
+
+------ API ------------------------------------------------
+
+This uses the V4L interface as of kernel release 2.1.116, and in
+fact has not been tested on any lower version. There are a couple
+of minor differences due to the fact that the amount of data returned
+with each frame varies, and no doubt there are discrepancies due to my
+misunderstanding of the API. I intend to convert this driver to the
+new V4L2 API when it has stabilized more.
+
+------ Current state --------------------------------------
+
+The driver is capable of overlaying a video image in screen, and
+even capable of grabbing frames. It uses the BIGPHYSAREA patch
+to allocate lots of large memory blocks when tis patch is
+found in the kernel, but it doesn't need it.
+The consequence is that, when loading the driver as a module,
+the module may tell you it's out of memory, but 'free' says
+otherwise. The reason is simple; the modules wants its memory
+contingious, not fragmented, and after a long uptime there
+probably isn't a fragment of memory large enough...
+
+The driver uses a double buffering scheme, which should realy
+be an n-way buffer, depending on the size of allocated framebuffer
+and the requested grab-size/format.
+This current version also fixes a dead-lock situation during irq
+time, which really, really froze my system... :)
+
+Good luck.
+ Pauline
L: linux-hams@vger.rutgers.edu
S: Maintained
+ZR36120 VIDEO FOR LINUX DRIVER
+P: Pauline Middelink
+M: middelin@polyware.nl
+W: http://www.polyware.nl/~middelin/En/hobbies.html
+W: http://www.polyware.nl/~middelin/hobbies.html
+S: Maintained
+
THE REST
P: Linus Torvalds
S: Buried alive in reporters
VERSION = 2
PATCHLEVEL = 3
-SUBLEVEL = 29
+SUBLEVEL = 30
EXTRAVERSION =
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
#define PFN_DOWN(x) ((x) >> 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
/* 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) {
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 "
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;
}
{
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
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;
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
}
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...");
void __init setup_IO_APIC(void)
{
- init_sym_mode();
+ enable_IO_APIC();
printk("ENABLING IO-APIC IRQs\n");
io_apic_irqs = ~PIC_IRQS;
* 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)
{
#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) {
if (down_trylock(&lock))
return -EBUSY;
- if (call_data) // temporary debugging check
- BUG();
-
call_data = &data;
data.func = func;
data.info = info;
* 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 (;;);
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);
+
}
/*
*/
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)
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();
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;
__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
/*
* Not an __init, needed by the reboot code
*/
-void init_pic_mode(void)
+void disable_IO_APIC(void)
{
/* Nop on Cobalt */
}
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
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
endif
endif
+#
+# for external dependencies in arm/config.in and video/config.in
+#
ifeq ($(CONFIG_BUS_I2C),y)
L_I2C=y
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
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
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
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
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
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,
#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)
#endif
#ifdef CONFIG_VIDEO_DEV
videodev_init();
-#endif
-#ifdef CONFIG_PPDEV
- pp_init();
#endif
return 0;
}
*/
#include <linux/module.h>
+#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/parport.h>
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",
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);
--- /dev/null
+/*
+ saa7110 - Philips SAA7110(A) video decoder driver
+
+ Copyright (C) 1998 Pauline Middelink <middelin@polyware.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#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
#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
#endif
#ifdef CONFIG_VIDEO_ZORAN
{"zoran", init_zoran_cards},
+#endif
+#ifdef CONFIG_VIDEO_ZR36120
+ {"zr36120", init_zr36120_cards},
#endif
{"end", NULL}
};
--- /dev/null
+/*
+ zr36120.c - Zoran 36120/36125 based framegrabbers
+
+ Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/segment.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#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 <middelin@polyware.nl>");
+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 <middelin@polyware.nl> */
+/*0*/ { "Trust Victor II",
+ 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
+ /* reported working by <Michael.Paxton@aihw.gov.au> */
+/*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 <Pascal.Gabriel@wanadoo.fr> */
+/*3*/ { "Guillemot Maxi-TV PCI",
+ 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } },
+ /* reported working by "Craig Whitmore <lennon@igrin.co.nz> */
+/*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; i<ZORAN_MAX_FBUFFERS; i++)
+ if (ztv->grabinfo[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; i<count; i++) {
+ struct video_clip *vp = vcp+i;
+ DEBUG(printk(KERN_DEBUG " %d: clip(%d,%d,%d,%d)\n",
+ i,vp->x,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; i<ztv->overinfo.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; i<count; i++) {
+ int h;
+ if (vcp->x < 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 <junki@qn-lpr2-165.quicknet.inet.fi>
+ * 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; i<ZORAN_MAX_FBUFFERS; i++)
+ ztv->grabinfo[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; i<ZORAN_MAX_FBUFFERS; i++)
+ mb.offsets[i] = i*ZORAN_MAX_FBUFFER;
+ if(copy_to_user(arg, &mb,sizeof(mb)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case VIDIOCGUNIT:
+ {
+ struct video_unit vu;
+ DEBUG(printk(KERN_DEBUG "%s: GetUnit\n",CARD));
+ vu.video = ztv->video_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; i<ZORAN_MAX_FBUFFERS; i++) {
+ ztv->grabinfo[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;i<max; i++)
+ {
+ ztv=&zorans[i];
+
+ /* turn off all capturing, DMA and IRQs */
+ /* reset the zoran */
+ zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI);
+ udelay(10);
+ zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI);
+ udelay(10);
+
+ /* first disable interrupts before unmapping the memory! */
+ zrwrite(0, ZORAN_ICR);
+ zrwrite(0xffffffffUL,ZORAN_ISR);
+
+ /* free it */
+ free_irq(ztv->dev->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<zoran_cards; card++) {
+ if (init_zoran(card)<0) {
+ /* only release the zorans we have registered */
+ release_zoran(card);
+ return -EIO;
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+ zr36120.h - Zoran 36120/36125 based framegrabbers
+
+ Copyright (C) 1998-1999 Pauline Middelink (middelin@polyware.nl)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _ZR36120_H
+#define _ZR36120_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+
+#include <asm/io.h>
+
+/*
+ * 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
--- /dev/null
+/*
+ zr36120_i2c.c - Zoran 36120/36125 based framegrabbers
+
+ Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#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
+};
--- /dev/null
+/*
+ zr36120_mem.c - Zoran 36120/36125 based framegrabbers
+
+ Copyright (C) 1998-1999 Pauline Middelink <middelin@polyware.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/wrapper.h>
+#include <asm/io.h>
+#ifdef CONFIG_BIGPHYS_AREA
+#include <linux/bigphysarea.h>
+#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
+ }
+}
--- /dev/null
+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);
"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"},
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);
/* 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:
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 */
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;
* - 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)
/************************ 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 */
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++;
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
* 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:
* 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 <linux/config.h>
unsigned fragsize;
unsigned dmasize;
unsigned fragsamples;
+ unsigned dmasamples;
/* OSS stuff */
unsigned mapped:1;
unsigned ready:1;
/* --------------------------------------------------------------------- */
static struct cm_state *devs = NULL;
+static struct cm_state *devaudio = NULL;
static unsigned long wavetable_mem = 0;
/* --------------------------------------------------------------------- */
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)
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;
{
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;
{ 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)
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);
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);
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);
}
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);
}
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);
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) {
len -= x;
}
memset(buf + bptr, c, len);
+ outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
}
/* call with spinlock held! */
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);
}
/* --------------------------------------------------------------------- */
-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)
#define MT_5MUTE 2
#define MT_4MUTEMONO 3
#define MT_6MUTE 4
+#define MT_5MUTEMONO 5
static const struct {
unsigned left;
} 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 }
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:
}
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;
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;
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;
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;
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;
NULL, /* lock */
};
-#ifdef CONFIG_SOUND_CMPCI_MIDI
/* --------------------------------------------------------------------- */
static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
}
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);
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] = {
NULL, /* revalidate */
NULL, /* lock */
};
-#endif /* CONFIG_SOUND_CMPCI_FM */
/* --------------------------------------------------------------------- */
};
#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
{
struct pci_dev *pcidev = NULL;
mm_segment_t fs;
int i, val, index = 0;
+
struct {
unsigned short deviceid;
char *devicename;
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)) ||
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 */
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);
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;
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:
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 */
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
* 1997-08-09 removed extension stripping, locking cleanup
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#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 */
((__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 <andrea@suse.de> */
-#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
+#include <linux/config.h>
#define acornfb_valid_pixrate(rate) (rate >= 39325 && rate <= 40119)
static inline void
#ifndef _ASMARM_PGTABLE_H
#define _ASMARM_PGTABLE_H
-#include <linux/config.h>
-
#include <asm/arch/memory.h>
#include <asm/proc-fns.h>
#include <asm/system.h>
#ifndef __ASM_ARM_PROCESSOR_H
#define __ASM_ARM_PROCESSOR_H
-#include <linux/config.h>
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
#ifdef __KERNEL__
+#include <linux/config.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/kmap_types.h>
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;
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 */
".previous"
#define spin_unlock_string \
- "lock ; btrl $0,%0"
+ "movb $0,%0"
#define spin_lock(lock) \
__asm__ __volatile__( \
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);
#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
/*
* This file define a set of standard wireless extensions
*
- * Version : 8 28.7.99
+ * Version : 9 16.10.99
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
*/
* (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 :
* - 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 -------------------------- */
/* 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 */
#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))
/* 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
*/
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 */
__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
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;
};
/* 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 */
/* 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 */
};
/*
* 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
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.
*/
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
*/
-#include <linux/config.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>