summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/ChangeLog5
-rw-r--r--drivers/char/Config.in5
-rw-r--r--drivers/char/Makefile16
-rw-r--r--drivers/char/acquirewdt.c1
-rw-r--r--drivers/char/adbmouse.c7
-rw-r--r--drivers/char/amigamouse.c7
-rw-r--r--drivers/char/apm_bios.c375
-rw-r--r--drivers/char/atarimouse.c7
-rw-r--r--drivers/char/atixlmouse.c7
-rw-r--r--drivers/char/bt848.h13
-rw-r--r--drivers/char/bttv.c1218
-rw-r--r--drivers/char/bttv.h51
-rw-r--r--drivers/char/busmouse.c7
-rw-r--r--drivers/char/cyclades.c46
-rw-r--r--drivers/char/dn_keyb.c7
-rw-r--r--drivers/char/dsp56k.c1
-rw-r--r--drivers/char/fbmem.c1
-rw-r--r--drivers/char/ftape/lowlevel/ftape-proc.c1
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c1
-rw-r--r--drivers/char/h8.c1
-rw-r--r--drivers/char/hfmodem/main.c1
-rw-r--r--drivers/char/joystick.c1
-rw-r--r--drivers/char/lp.c3
-rw-r--r--drivers/char/lp_m68k.c1
-rw-r--r--drivers/char/macmouse.c7
-rw-r--r--drivers/char/mem.c7
-rw-r--r--drivers/char/misc.c1
-rw-r--r--drivers/char/msbusmouse.c7
-rw-r--r--drivers/char/msp3400.c4
-rw-r--r--drivers/char/msp3400.h2
-rw-r--r--drivers/char/n_tty.c31
-rw-r--r--drivers/char/nvram.c1
-rw-r--r--drivers/char/pc110pad.c8
-rw-r--r--drivers/char/pc_keyb.c371
-rw-r--r--drivers/char/pc_keyb.h2
-rw-r--r--drivers/char/pcwd.c1
-rw-r--r--drivers/char/pms.c96
-rw-r--r--drivers/char/psaux.c20
-rw-r--r--drivers/char/radio-aimslab.c2
-rw-r--r--drivers/char/radio-aztech.c2
-rw-r--r--drivers/char/radio-miropcm20.c244
-rw-r--r--drivers/char/radio-rtrack2.c2
-rw-r--r--drivers/char/radio-sf16fmi.c83
-rw-r--r--drivers/char/radio-zoltrix.c4
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/rocket.c9
-rw-r--r--drivers/char/rtc.c1
-rw-r--r--drivers/char/saa5249.c4
-rw-r--r--drivers/char/serial.c22
-rw-r--r--drivers/char/softdog.c1
-rw-r--r--drivers/char/stallion.c1
-rw-r--r--drivers/char/tpqic02.c1
-rw-r--r--drivers/char/tty_io.c21
-rw-r--r--drivers/char/tuner.c2
-rw-r--r--drivers/char/vc_screen.c1
-rw-r--r--drivers/char/videodev.c7
-rw-r--r--drivers/char/wdt.c1
57 files changed, 1662 insertions, 1089 deletions
diff --git a/drivers/char/ChangeLog b/drivers/char/ChangeLog
index eddd9e674..7e0558013 100644
--- a/drivers/char/ChangeLog
+++ b/drivers/char/ChangeLog
@@ -1,3 +1,8 @@
+1998-08-26 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * serial.c (rs_open): Correctly decrement the module in-use count
+ on errors.
+
Thu Feb 19 14:24:08 1998 Theodore Ts'o <tytso@rsts-11.mit.edu>
* tty_io.c (tty_name): Remove the non-reentrant (and non-SMP safe)
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index eef6d8f66..451d898fc 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -117,10 +117,15 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
fi
+ dep_tristate 'AIMSlab RadioTrack II support' CONFIG_RADIO_RTRACK2 $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_RTRACK2" = "y" ]; then
+ hex ' RadioTrack II i/o port (0x20c or 0x30c)' CONFIG_RADIO_RTRACK2_PORT 30c
+ fi
dep_tristate 'Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
fi
+ dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 9f2a484e0..36fe0d105 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -397,6 +397,14 @@ else
endif
endif
+ifeq ($(CONFIG_RADIO_RTRACK2),y)
+L_OBJS += radio-rtrack2.o
+else
+ ifeq ($(CONFIG_RADIO_RTRACK2),m)
+ M_OBJS += radio-rtrack2.o
+ endif
+endif
+
ifeq ($(CONFIG_RADIO_ZOLTRIX),y)
L_OBJS += radio-zoltrix.o
else
@@ -405,6 +413,14 @@ else
endif
endif
+ifeq ($(CONFIG_RADIO_MIROPCM20),y)
+L_OBJS += radio-miropcm20.o
+else
+ ifeq ($(CONFIG_RADIO_MIROPCM20),m)
+ M_OBJS += radio-miropcm20.o
+ endif
+endif
+
ifeq ($(CONFIG_QIC02_TAPE),y)
L_OBJS += tpqic02.o
else
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index 153cb9ad7..a9aa76714 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -174,6 +174,7 @@ static struct file_operations acq_fops = {
acq_ioctl,
NULL, /* No mmap */
acq_open,
+ NULL, /* flush */
acq_close
};
diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c
index 35e0c833b..43930ff1b 100644
--- a/drivers/char/adbmouse.c
+++ b/drivers/char/adbmouse.c
@@ -144,11 +144,11 @@ static void adb_mouse_interrupt(char *buf, int nb)
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -156,7 +156,7 @@ static int fasync_mouse(struct file *filp, int on)
static int release_mouse(struct inode *inode, struct file *file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
@@ -236,6 +236,7 @@ struct file_operations adb_mouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
release_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c
index a3cbd737e..e62ea5753 100644
--- a/drivers/char/amigamouse.c
+++ b/drivers/char/amigamouse.c
@@ -159,10 +159,10 @@ static void mouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
AMI_MSE_INT_ON();
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -174,7 +174,7 @@ static int fasync_mouse(struct file *filp, int on)
static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
@@ -299,6 +299,7 @@ struct file_operations amiga_mouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
release_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c
index e9e964c43..08b3a78a2 100644
--- a/drivers/char/apm_bios.c
+++ b/drivers/char/apm_bios.c
@@ -1,7 +1,7 @@
/* -*- linux-c -*-
* APM BIOS driver for Linux
- * Copyright 1994, 1995, 1996 Stephen Rothwell
- * (Stephen.Rothwell@canb.auug.org.au)
+ * Copyright 1994-1998 Stephen Rothwell
+ * (Stephen.Rothwell@canb.auug.org.au)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -13,8 +13,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
- * $Id: apm_bios.c,v 0.22 1995/03/09 14:12:02 sfr Exp $
- *
* October 1995, Rik Faith (faith@cs.unc.edu):
* Minor enhancements and updates (to the patch set) for 1.3.x
* Documentation
@@ -28,6 +26,7 @@
* May 1996, Version 1.2
* Feb 1998, Version 1.3
* Feb 1998, Version 1.4
+ * Aug 1998, Version 1.5
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
@@ -50,6 +49,9 @@
* 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
* Dean Gaudet <dgaudet@arctic.org>.
* C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
+ * 1.5: Fix segment register reloading (in case of bad segments saved
+ * across BIOS call).
+ * Stephen ROthwell
*
* APM 1.1 Reference:
*
@@ -158,6 +160,7 @@ extern unsigned long get_cmos_time(void);
* [Confirmed by TI representative]
* U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification
* [Confirmed by BIOS disassembly]
+ * [This may work now ...]
* P: Toshiba 1950S: battery life information only gets updated after resume
* P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking
* broken in BIOS [Reported by Garst R. Reese <reese@isn.net>]
@@ -180,6 +183,7 @@ extern unsigned long get_cmos_time(void);
/*
* Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call
* should turn interrupts on before it does a 'hlt').
+ * This reportedly needs undefining for the ThinkPad 600.
*/
#define APM_NOINTS
@@ -207,121 +211,9 @@ extern unsigned long get_cmos_time(void);
#define APM_CHECK_TIMEOUT (HZ)
/*
- * These are the actual BIOS calls in assembler. Depending on
- * APM_ZERO_SEGS and APM_NOINTS, we are being really paranoid here! Not
- * only are interrupts disabled, but all the segment registers (except SS)
- * are saved and zeroed this means that if the BIOS tries to reference any
- * data without explicitly loading the segment registers, the kernel will
- * fault immediately rather than have some unforeseen circumstances for the
- * rest of the kernel. And it will be very obvious! :-) Doing this
- * depends on CS referring to the same physical memory as DS so that DS can
- * be zeroed before the call. Unfortunately, we can't do anything about the
- * stack segment/pointer. Also, we tell the compiler that everything could
- * change.
+ * Save a segment register away
*/
-#ifdef APM_NOINTS
-# define APM_DO_CLI "cli\n\t"
-#else
-# define APM_DO_CLI
-#endif
-#ifdef APM_ZERO_SEGS
-# define APM_DO_ZERO_SEGS \
- "pushl %%ds\n\t" \
- "pushl %%es\n\t" \
- "pushl %%fs\n\t" \
- "pushl %%gs\n\t" \
- "xorl %%edx, %%edx\n\t" \
- "movl %%dx, %%ds\n\t" \
- "movl %%dx, %%es\n\t" \
- "movl %%dx, %%fs\n\t" \
- "movl %%dx, %%gs\n\t"
-# define APM_DO_RESTORE_SEGS \
- "popl %%gs\n\t" \
- "popl %%fs\n\t" \
- "popl %%es\n\t" \
- "popl %%ds\n\t"
-#else
-# define APM_DO_ZERO_SEGS
-# define APM_DO_RESTORE_SEGS
-#endif
-
-#define APM_BIOS_CALL(error_reg) \
- __asm__ __volatile__( \
- APM_DO_ZERO_SEGS \
- "pushfl\n\t" \
- APM_DO_CLI \
- "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" \
- "setc %%" # error_reg "\n\t" \
- "popfl\n\t" \
- APM_DO_RESTORE_SEGS
-#define APM_BIOS_CALL_END \
- : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory")
-
-#ifdef CONFIG_APM_CPU_IDLE
-#define APM_SET_CPU_IDLE(error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5305) \
- APM_BIOS_CALL_END
-#endif
-
-#define APM_SET_CPU_BUSY(error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5306) \
- APM_BIOS_CALL_END
-
-#define APM_SET_POWER_STATE(state, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5307), "b" (0x0001), "c" (state) \
- APM_BIOS_CALL_END
-
-#ifdef CONFIG_APM_DISPLAY_BLANK
-#define APM_SET_DISPLAY_POWER_STATE(state, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5307), "b" (0x01ff), "c" (state) \
- APM_BIOS_CALL_END
-#endif
-
-#ifdef CONFIG_APM_DO_ENABLE
-#define APM_ENABLE_POWER_MANAGEMENT(device, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x5308), "b" (device), "c" (1) \
- APM_BIOS_CALL_END
-#endif
-
-#define APM_GET_POWER_STATUS(bx, cx, dx, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \
- : "a" (0x530a), "b" (1) \
- APM_BIOS_CALL_END
-
-#define APM_GET_BATTERY_STATUS(which, bx, cx, dx, si, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx), "=S" (si) \
- : "a" (0x530a), "b" (0x8000 | (which)) \
- APM_BIOS_CALL_END
-
-#define APM_GET_EVENT(event, info, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error), "=b" (event), "=c" (info) \
- : "a" (0x530b) \
- APM_BIOS_CALL_END
-
-#define APM_DRIVER_VERSION(ver, ax, error) \
- APM_BIOS_CALL(bl) \
- : "=a" (ax), "=b" (error) \
- : "a" (0x530e), "b" (0), "c" (ver) \
- APM_BIOS_CALL_END
-
-#define APM_ENGAGE_POWER_MANAGEMENT(device, error) \
- APM_BIOS_CALL(al) \
- : "=a" (error) \
- : "a" (0x530f), "b" (device), "c" (1) \
- APM_BIOS_CALL_END
+#define savesegment(seg, where) __asm__ __volatile__("movw %%" #seg ", %0\n" : "=m" (where))
/*
* Forward declarations
@@ -371,7 +263,7 @@ static struct apm_bios_struct * user_list = NULL;
static struct timer_list apm_timer;
-static char driver_version[] = "1.4"; /* no spaces */
+static char driver_version[] = "1.5"; /* no spaces */
#ifdef APM_DEBUG
static char * apm_event_name[] = {
@@ -401,6 +293,7 @@ static struct file_operations apm_bios_fops = {
do_ioctl,
NULL, /* mmap */
do_open,
+ NULL, /* flush */
do_release,
NULL, /* fsync */
NULL /* fasync */
@@ -444,74 +337,197 @@ static const lookup_t error_table[] = {
};
#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
-static int apm_driver_version(u_short *val)
+/*
+ * These are the actual BIOS calls. Depending on APM_ZERO_SEGS
+ * and APM_NOINTS, we are being really paranoid here! Not only are
+ * interrupts disabled, but all the segment registers (except SS) are
+ * saved and zeroed this means that if the BIOS tries to reference any
+ * data without explicitly loading the segment registers, the kernel will
+ * fault immediately rather than have some unforeseen circumstances for
+ * the rest of the kernel. And it will be very obvious! :-) Doing this
+ * depends on CS referring to the same physical memory as DS so that DS
+ * can be zeroed before the call. Unfortunately, we can't do anything
+ * about the stack segment/pointer. Also, we tell the compiler that
+ * everything could change.
+ */
+
+static inline int apm_bios_call(u32 eax_in, u32 ebx_in, u32 ecx_in,
+ u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi)
{
- u_short error;
+ u16 old_fs;
+ u16 old_gs;
+ int error;
+
+#ifdef APM_ZERO_SEGS
+ savesegment(fs, old_fs);
+ savesegment(gs, old_gs);
+#endif
+ __asm__ __volatile__(
+ "pushfl\n\t"
+#ifdef APM_NOINTS
+ "cli\n\t"
+#endif
+#ifdef APM_ZERO_SEGS
+ "pushl %%ds\n\t"
+ "pushl %%es\n\t"
+ "movw %9, %%ds\n\t"
+ "movw %9, %%es\n\t"
+ "movw %9, %%fs\n\t"
+ "movw %9, %%gs\n\t"
+#endif
+ "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
+ "movl $0, %%edi\n\t"
+ "jnc 1f\n\t"
+ "movl $1, %%edi\n"
+ "1:\tpopl %%es\n\t"
+ "popl %%ds\n\t"
+ "popfl\n\t"
+ : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),
+ "=S" (*esi), "=D" (error)
+ : "a" (eax_in), "b" (ebx_in), "c" (ecx_in)
+#ifdef APM_ZERO_SEGS
+ , "r" (0)
+#endif
+ : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory");
+#ifdef APM_ZERO_SEGS
+ loadsegment(fs, old_fs);
+ loadsegment(gs, old_gs);
+#endif
+ return error;
+}
+
+/*
+ * This version only returns one value (usually an error code)
+ */
- APM_DRIVER_VERSION(*val, *val, error);
+static inline int apm_bios_call_simple(u32 eax_in, u32 ebx_in, u32 ecx_in, u32 *eax)
+{
+ u16 old_fs;
+ u16 old_gs;
+ int error;
- if (error & 0xff)
- return (*val >> 8);
+#ifdef APM_ZERO_SEGS
+ savesegment(fs, old_fs);
+ savesegment(gs, old_gs);
+#endif
+ __asm__ __volatile__(
+ "pushfl\n\t"
+#ifdef APM_NOINTS
+ "cli\n\t"
+#endif
+#ifdef APM_ZERO_SEGS
+ "pushl %%ds\n\t"
+ "pushl %%es\n\t"
+ "movw %5, %%ds\n\t"
+ "movw %5, %%es\n\t"
+ "movw %5, %%fs\n\t"
+ "movw %5, %%gs\n\t"
+#endif
+ "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"
+ "movl $0, %%edi\n\t"
+ "jnc 1f\n\t"
+ "movl $1, %%edi\n"
+ "1:\tpopl %%es\n\t"
+ "popl %%ds\n\t"
+ "popfl\n\t"
+ : "=a" (*eax), "=D" (error)
+ : "a" (eax_in), "b" (ebx_in), "c" (ecx_in)
+#ifdef APM_ZERO_SEGS
+ , "r" (0)
+#endif
+ : "ax", "bx", "cx", "dx", "si", "di", "bp", "memory");
+#ifdef APM_ZERO_SEGS
+ loadsegment(fs, old_fs);
+ loadsegment(gs, old_gs);
+#endif
+ return error;
+}
+
+static int apm_driver_version(u_short *val)
+{
+ int error;
+ u32 eax;
+
+ error = apm_bios_call_simple(0x530e, 0, *val, &eax);
+ if (error)
+ return (eax >> 8) & 0xff;
+ *val = eax;
return APM_SUCCESS;
}
static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info)
{
- u_short error;
+ int error;
+ u32 eax;
+ u32 ebx;
+ u32 ecx;
+ u32 dummy;
- APM_GET_EVENT(*event, *info, error);
- if (error & 0xff)
- return (error >> 8);
+ error = apm_bios_call(0x530b, 0, 0, &eax, &ebx, &ecx, &dummy, &dummy);
+ if (error)
+ return (eax >> 8) & 0xff;
+ *event = ebx;
if (apm_bios_info.version < 0x0102)
*info = ~0; /* indicate info not valid */
+ else
+ *info = ecx;
return APM_SUCCESS;
}
-int apm_set_power_state(u_short state)
+static int set_power_state(u_short what, u_short state)
{
- u_short error;
+ int error;
+ u32 eax;
- APM_SET_POWER_STATE(state, error);
- if (error & 0xff)
- return (error >> 8);
+ error = apm_bios_call_simple(0x5307, what, state, &eax);
+ if (error)
+ return (eax >> 8) & 0xff;
return APM_SUCCESS;
}
+int apm_set_power_state(u_short state)
+{
+ return set_power_state(0x0001, state);
+}
+
#ifdef CONFIG_APM_DISPLAY_BLANK
/* Called by apm_display_blank and apm_display_unblank when apm_enabled. */
static int apm_set_display_power_state(u_short state)
{
- u_short error;
-
- APM_SET_DISPLAY_POWER_STATE(state, error);
- if (error & 0xff)
- return (error >> 8);
- return APM_SUCCESS;
+ return set_power_state(0x01ff, state);
}
#endif
#ifdef CONFIG_APM_DO_ENABLE
/* Called by apm_setup if apm_enabled will be true. */
-static inline int apm_enable_power_management(void)
+static int apm_enable_power_management(void)
{
- u_short error;
+ int error;
+ u32 eax;
- APM_ENABLE_POWER_MANAGEMENT((apm_bios_info.version > 0x100)
- ? 0x0001 : 0xffff,
- error);
- if (error & 0xff)
- return (error >> 8);
+ error = apm_bios_call_simple(0x5308,
+ (apm_bios_info.version > 0x100) ? 0x0001 : 0xffff, 1, &eax);
+ if (error)
+ return (eax >> 8) & 0xff;
return APM_SUCCESS;
}
#endif
static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
{
- u_short error;
+ int error;
+ u32 eax;
+ u32 ebx;
+ u32 ecx;
+ u32 edx;
+ u32 dummy;
- APM_GET_POWER_STATUS(*status, *bat, *life, error);
- if (error & 0xff)
- return (error >> 8);
+ error = apm_bios_call(0x530a, 1, 0, &eax, &ebx, &ecx, &edx, &dummy);
+ if (error)
+ return (eax >> 8) & 0xff;
+ *status = ebx;
+ *bat = ecx;
+ *life = edx;
return APM_SUCCESS;
}
@@ -520,29 +536,40 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
static int apm_get_battery_status(u_short which,
u_short *bat, u_short *life, u_short *nbat)
{
- u_short status, error;
+ u_short status;
+ int error;
+ u32 eax;
+ u32 ebx;
+ u32 ecx;
+ u32 edx;
+ u32 esi;
if (apm_bios_info.version < 0x0102) {
/* pretend we only have one battery. */
- if (which!=1) return APM_BAD_DEVICE;
+ if (which != 1)
+ return APM_BAD_DEVICE;
*nbat = 1;
return apm_get_power_status(&status, bat, life);
}
- APM_GET_BATTERY_STATUS(which, status, *bat, *life, *nbat, error);
- if (error & 0xff)
- return (error >> 8);
+ error = apm_bios_call(0x530a, (0x8000 | (which)), 0, &eax, &ebx, &ecx, &edx, &esi);
+ if (error)
+ return (eax >> 8) & 0xff;
+ *bat = ecx;
+ *life = edx;
+ *nbat = esi;
return APM_SUCCESS;
}
#endif
-static inline int apm_engage_power_management(u_short device)
+static int apm_engage_power_management(u_short device)
{
- u_short error;
+ int error;
+ u32 eax;
- APM_ENGAGE_POWER_MANAGEMENT(device, error);
- if (error & 0xff)
- return (error >> 8);
+ error = apm_bios_call_simple(0x530f, device, 1, &eax);
+ if (error)
+ return (eax >> 8) & 0xff;
return APM_SUCCESS;
}
@@ -849,13 +876,14 @@ static void do_apm_timer(unsigned long unused)
int apm_do_idle(void)
{
#ifdef CONFIG_APM_CPU_IDLE
- unsigned short error;
+ int error;
+ u32 dummy;
if (!apm_enabled)
return 0;
- APM_SET_CPU_IDLE(error);
- if (error & 0xff)
+ error = apm_bios_call_simple(0x5305, 0, 0, &dummy);
+ if (error)
return 0;
clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
@@ -869,19 +897,16 @@ int apm_do_idle(void)
void apm_do_busy(void)
{
#ifdef CONFIG_APM_CPU_IDLE
- unsigned short error;
-
- if (!apm_enabled)
- return;
+ u32 dummy;
+ if (apm_enabled
#ifndef ALWAYS_CALL_BUSY
- if (!clock_slowed)
- return;
+ && clock_slowed
#endif
-
- APM_SET_CPU_BUSY(error);
-
- clock_slowed = 0;
+ ) {
+ (void) apm_bios_call_simple(0x5306, 0, 0, &dummy);
+ clock_slowed = 0;
+ }
#endif
}
@@ -1241,11 +1266,11 @@ __initfunc(void apm_bios_init(void))
*/
apm_bios_info.version = 0x0102;
error = apm_driver_version(&apm_bios_info.version);
- if (error != 0) { /* Fall back to an APM 1.1 connection. */
+ if (error != APM_SUCCESS) { /* Fall back to an APM 1.1 connection. */
apm_bios_info.version = 0x0101;
error = apm_driver_version(&apm_bios_info.version);
}
- if (error != 0) /* Fall back to an APM 1.0 connection. */
+ if (error != APM_SUCCESS) /* Fall back to an APM 1.0 connection. */
apm_bios_info.version = 0x100;
else {
apm_engage_power_management(0x0001);
diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c
index 113395dba..33d71d376 100644
--- a/drivers/char/atarimouse.c
+++ b/drivers/char/atarimouse.c
@@ -54,10 +54,10 @@ static void atari_mouse_interrupt(char *buf)
/* ikbd_mouse_rel_pos(); */
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -65,7 +65,7 @@ static int fasync_mouse(struct file *filp, int on)
static int release_mouse(struct inode *inode, struct file *file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
ikbd_mouse_disable();
@@ -149,6 +149,7 @@ struct file_operations atari_mouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
release_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c
index 9ccb06ca6..52ce4bf67 100644
--- a/drivers/char/atixlmouse.c
+++ b/drivers/char/atixlmouse.c
@@ -95,10 +95,10 @@ void mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
ATIXL_MSE_ENABLE_UPDATE();
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasync);
+ retval = fasync_helper(fd, filp, on, &mouse.fasync);
if (retval < 0)
return retval;
return 0;
@@ -106,7 +106,7 @@ static int fasync_mouse(struct file *filp, int on)
static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
@@ -191,6 +191,7 @@ struct file_operations atixl_busmouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
release_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/bt848.h b/drivers/char/bt848.h
index a50e31a5c..5227ef712 100644
--- a/drivers/char/bt848.h
+++ b/drivers/char/bt848.h
@@ -30,6 +30,12 @@
#ifndef PCI_DEVICE_ID_BT849
#define PCI_DEVICE_ID_BT849 0x351
#endif
+#ifndef PCI_DEVICE_ID_BT878
+#define PCI_DEVICE_ID_BT878 0x36e
+#endif
+#ifndef PCI_DEVICE_ID_BT879
+#define PCI_DEVICE_ID_BT879 0x36f
+#endif
/* Brooktree 848 registers */
@@ -336,7 +342,14 @@
#define BT848_FCAP 0x0E8
#define BT848_PLL_F_LO 0x0F0
#define BT848_PLL_F_HI 0x0F4
+
#define BT848_PLL_XCI 0x0F8
+#define BT848_PLL_X (1<<7)
+#define BT848_PLL_C (1<<6)
+
+/* Bt878 register */
+#define BT878_DEVCTRL 0x40
+#define BT878_EN_TBFX 0x02
#endif
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index 8bb3f203e..19c30d6fd 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -65,18 +65,12 @@
#define DEBUG(x) /* Debug driver */
#define IDEBUG(x) /* Debug interrupt handler */
-static unsigned int remap=0; /* remap Bt848 */
-static unsigned int vidmem=0; /* manually set video mem address */
-static int triton1=0;
-static int radio=0;
-
-static unsigned int card=0;
-
-MODULE_PARM(remap,"i");
MODULE_PARM(vidmem,"i");
MODULE_PARM(triton1,"i");
-MODULE_PARM(radio,"i");
-MODULE_PARM(card,"i");
+MODULE_PARM(remap,"1-4i");
+MODULE_PARM(radio,"1-4i");
+MODULE_PARM(card,"1-4i");
+MODULE_PARM(pll,"1-4i");
static int find_vga(void);
static void bt848_set_risc_jmps(struct bttv *btv);
@@ -84,12 +78,19 @@ static void bt848_set_risc_jmps(struct bttv *btv);
/* Anybody who uses more than four? */
#define BTTV_MAX 4
+static unsigned int vidmem=0; /* manually set video mem address */
+static int triton1=0;
+
+static unsigned int remap[BTTV_MAX]; /* remap Bt848 */
+static unsigned int radio[BTTV_MAX];
+static unsigned int card[BTTV_MAX] = { 0, 0,
+ 0, 0 };
+static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0 };
+
static int bttv_num; /* number of Bt848s in use */
static struct bttv bttvs[BTTV_MAX];
#define I2C_TIMING (0x7<<4)
-#define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA)
-
#define I2C_DELAY 10
#define I2C_SET(CTRL,DATA) \
{ btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
@@ -128,10 +129,6 @@ static inline unsigned long uvirt_to_phys(unsigned long adr)
static inline unsigned long uvirt_to_bus(unsigned long adr)
{
- /* printk("adr: 0x%8x, ",adr);
- printk("phys: 0x%8x, ",(uvirt_to_phys(adr)));
- printk("bus: 0x%8x\n",virt_to_bus(phys_to_virt(uvirt_to_phys(adr))));
- */
return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
}
@@ -199,7 +196,8 @@ static int fbuffer_alloc(struct bttv *btv)
if(!btv->fbuffer)
btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
else
- printk(KERN_ERR "bttv: Double alloc of fbuffer!\n");
+ printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",
+ btv->nr);
if(!btv->fbuffer)
return -ENOBUFS;
return 0;
@@ -236,7 +234,7 @@ static int I2CRead(struct i2c_bus *bus, unsigned char addr)
/* clear status bit ; BT848_INT_RACK is ro */
btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
- btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C);
+ btwrite(((addr & 0xff) << 24) | btv->i2c_command, BT848_I2C);
/*
* Timeout for I2CRead is 1 second (this should be enough, really!)
@@ -251,7 +249,8 @@ static int I2CRead(struct i2c_bus *bus, unsigned char addr)
if (!i)
{
- printk(KERN_DEBUG "bttv: I2CRead timeout\n");
+ printk(KERN_DEBUG "bttv%d: I2CRead timeout\n",
+ btv->nr);
return -1;
}
if (!(stat & BT848_INT_RACK))
@@ -274,7 +273,7 @@ static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
/* clear status bit; BT848_INT_RACK is ro */
btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
- data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | I2C_COMMAND;
+ data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | btv->i2c_command;
if (both)
{
data|=((b2 & 0xff) << 8);
@@ -293,7 +292,8 @@ static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
if (!i)
{
- printk(KERN_DEBUG "bttv: I2CWrite timeout\n");
+ printk(KERN_DEBUG "bttv%d: I2CWrite timeout\n",
+ btv->nr);
return -1;
}
if (!(stat & BT848_INT_RACK))
@@ -356,9 +356,10 @@ void attach_inform(struct i2c_bus *bus, int id)
if (btv->tuner_type != -1)
{
tunertype=btv->tuner_type;
- i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
- TUNER_SET_TYPE,&tunertype);
- }
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_TUNER,
+ TUNER_SET_TYPE,&tunertype);
+ }
break;
}
}
@@ -406,6 +407,7 @@ struct tvcard
u32 gpiomask;
u32 muxsel[8];
u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */
+ u32 gpiomask2; /* GPIO MUX mask */
};
static struct tvcard tvcards[] =
@@ -423,12 +425,17 @@ static struct tvcard tvcards[] =
/* Diamond DTV2000 */
{ 3, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}},
/* AVerMedia TVPhone */
- { 3, 0, 2,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
+ { 3, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
/* Matrix Vision MV-Delta */
- { 5,-1, 4, 0, { 2, 3, 1, 0, 0}},
+ { 5,-1, 3, 0, { 2, 3, 1, 0, 0}},
/* Fly Video II */
{ 3, 0, 2, 0xc00, { 2, 3, 1, 1},
{0, 0xc00, 0x800, 0x400, 0xc00, 0}},
+ /* TurboTV */
+ { 3, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}},
+ /* Newer Hauppauge */
+ { 2, 0, 2, 1, { 2, 0, 0, 0}, {0, 1, 2, 3, 4}},
+
};
#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
@@ -503,34 +510,74 @@ static void bt848_cap(struct bttv *btv, uint state)
/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/
+/* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C
+ PLL_X = Reference pre-divider (0=1, 1=2)
+ PLL_C = Post divider (0=6, 1=4)
+ PLL_I = Integer input
+ PLL_F = Fractional input
+
+ F_input = 28.636363 MHz:
+ PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0
+*/
+
+static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
+{
+ unsigned char fl, fh, fi;
+
+ /* prevent overflows */
+ fin/=4;
+ fout/=4;
+
+ fout*=12;
+ fi=fout/fin;
+
+ fout=(fout-fin*fi)*256;
+ fh=fout/fin;
+
+ fout=(fout-fin*fh)*256;
+ fl=fout/fin;
+
+ /*printk("0x%02x 0x%02x 0x%02x\n", fi, fh, fl);*/
+ btwrite(fl,BT848_PLL_F_LO);
+ btwrite(fh,BT848_PLL_F_HI);
+ btwrite(fi|BT848_PLL_X,BT848_PLL_XCI);
+}
+
static int set_pll(struct bttv *btv)
{
int i;
+ unsigned long tv;
- if (!btv->pll)
- return 0;
- if ((btread(BT848_IFORM)&BT848_IFORM_XT0))
+ if (!btv->pll.pll_crystal)
+ return 0;
+ if ((btread(BT848_IFORM)&btv->pll.pll_crystal))
{
/* printk ("switching PLL off\n");*/
btwrite(0x00,BT848_TGCTRL);
btwrite(0x00,BT848_PLL_XCI);
- btv->pll&=~2;
+ btv->pll.pll_crystal&=~2;
return 0;
}
/* do not set pll again if already active */
- if (btv->pll&2)
+ if (btv->pll.pll_crystal&2)
return 1;
/* printk ("setting PLL for PAL/SECAM\n");*/
- btwrite(0x00,BT848_TGCTRL);
- btwrite(0xf9,BT848_PLL_F_LO);
- btwrite(0xdc,BT848_PLL_F_HI);
- btwrite(0x8e,BT848_PLL_XCI);
+ set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);
+
+ /*
+ * Let other people run while the PLL stabilizes
+ */
+
+ tv=jiffies+HZ/10; /* .1 seconds */
+ do
+ {
+ schedule();
+ }
+ while(time_before(jiffies,tv));
- /* Ugh ugh ugh .. schedule ? */
- udelay(100000);
for (i=0; i<100; i++)
{
if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
@@ -538,7 +585,7 @@ static int set_pll(struct bttv *btv)
else
{
btwrite(0x08,BT848_TGCTRL);
- btv->pll|=2;
+ btv->pll.pll_crystal|=2;
return 1;
}
udelay(10000);
@@ -548,7 +595,8 @@ static int set_pll(struct bttv *btv)
static void bt848_muxsel(struct bttv *btv, unsigned int input)
{
- btwrite(tvcards[btv->type].gpiomask, BT848_GPIO_OUT_EN);
+ btaor(tvcards[btv->type].gpiomask2,~tvcards[btv->type].gpiomask2,
+ BT848_GPIO_OUT_EN);
/* This seems to get rid of some synchronization problems */
btand(~(3<<5), BT848_IFORM);
@@ -569,23 +617,7 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input)
audio(btv, (input!=tvcards[btv->type].tuner) ?
AUDIO_EXTERN : AUDIO_TUNER);
btaor(tvcards[btv->type].muxsel[input]>>4,
- ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
-#if 0
- if (input==3)
- {
- btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
- btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
- }
- else
- {
- btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
- btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
- }
- if (input==2)
- input=3;
- btaor(((input+2)&3)<<5, ~(3<<5), BT848_IFORM);
- audio(btv, input ? AUDIO_EXTERN : AUDIO_TUNER);
-#endif
+ ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
}
@@ -645,27 +677,28 @@ int palette2fmt[] = {
BT848_COLOR_FMT_RGB15,
BT848_COLOR_FMT_YUY2,
BT848_COLOR_FMT_BtYUV,
- -1,
- -1,
- -1,
+ 0,
+ 0,
+ 0,
BT848_COLOR_FMT_RAW,
BT848_COLOR_FMT_YCrCb422,
BT848_COLOR_FMT_YCrCb411,
};
#define PALETTEFMT_MAX 11
-static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
+static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
unsigned int *re, unsigned int *vbuf)
{
unsigned long line;
- unsigned long bpl=1024;
+ unsigned long bpl=1024; /* bytes per line */
unsigned long vadr=(unsigned long) vbuf;
*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
/* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
- is 2. We'll have to handle this inside the IRQ handler ... */
+ is 2 and without separate VBI grabbing.
+ We'll have to handle this inside the IRQ handler ... */
for (line=0; line < 640; line++)
{
@@ -802,6 +835,152 @@ static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr,
*x+=dx;
}
+static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
+{
+ int i,t;
+ int yy, y, x, dx;
+ struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2;
+ int bpp, bpl, width, height, inter;
+ unsigned int **rp,*ro,*re;
+ unsigned long adr;
+ int cx,cx2,cy,cy2;
+
+ inter=(btv->win.interlace&1)^1;
+ bpp=btv->win.bpp;
+ bpl=btv->win.bpl;
+ ro=btv->risc_odd;
+ re=btv->risc_even;
+ width=btv->win.width;
+ height=btv->win.height;
+ adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl;
+
+ /* clip clipping rects against viewing window AND screen
+ so we do not have to rely on the user program
+ */
+ cx=(btv->win.x<0) ? (-btv->win.x) : 0;
+ cy=(btv->win.y<0) ? (-btv->win.y) : 0;
+ cx2=(btv->win.x+width>btv->win.swidth) ?
+ (btv->win.swidth-btv->win.x) : width;
+ cy2=(btv->win.y+height>btv->win.sheight) ?
+ (btv->win.sheight-btv->win.y) : height;
+ first.next=NULL;
+ for (i=0; i<ncr; i++)
+ {
+ if ((t=cy-cr[i].y)>0)
+ {
+ if (cr[i].height<=t)
+ continue;
+ cr[i].height-=t;
+ cr[i].y=cy;
+ }
+ if ((t=cy2-cr[i].y)<cr[i].height)
+ {
+ if (t<=0)
+ continue;
+ cr[i].height=t;
+ }
+ if ((t=cx-cr[i].x)>0)
+ {
+ if (cr[i].width<=t)
+ continue;
+ cr[i].width-=t;
+ cr[i].x=cx;
+ }
+ if ((t=cx2-cr[i].x)<cr[i].width)
+ {
+ if (t<=0)
+ continue;
+ cr[i].width=t;
+ }
+ cur=&first;
+ while ((nx=cur->next) && (cr[i].y > cur->next->y))
+ cur=nx;
+ cur->next=&(cr[i]);
+ cr[i].next=nx;
+ }
+ first2.next=NULL;
+
+ *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
+ *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+
+ /* loop through all lines */
+ for (yy=0; yy<(height<<inter); yy++)
+ {
+ y=yy>>inter;
+ rp= (yy&1) ? &re : &ro;
+
+ /* remove rects with y2 > y */
+ if ((cur=first2.next))
+ {
+ prev=&first2;
+ do
+ {
+ if (cur->y+cur->height <= y)
+ prev->next=cur->next;
+ else
+ prev=cur;
+ }
+ while ((cur=cur->next));
+ }
+
+ /* add rect to second (x-sorted) list if rect.y == y */
+ if ((cur=first.next))
+ {
+ while ((cur) && (cur->y == y))
+ {
+ first.next=cur->next;
+ cur2=&first2;
+ while ((nx2=cur2->next) && (cur->x > cur2->next->x))
+ cur2=nx2;
+ cur2->next=cur;
+ cur->next=nx2;
+ cur=first.next;
+ }
+ }
+ x=0;
+ if ((btv->win.y+y<=0)||(btv->win.y+y>=btv->win.sheight))
+ write_risc_segment(rp, adr, BT848_RISC_SKIP, &x,
+ width, bpp, width);
+ else
+ {
+ dx=cx;
+ for (cur2=first2.next; cur2; cur2=cur2->next)
+ {
+ if (x+dx < cur2->x)
+ {
+ write_risc_segment(rp, adr, BT848_RISC_SKIP,
+ &x, dx, bpp, width);
+ dx=cur2->x-x;
+ write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+ &x, dx, bpp, width);
+ dx=cur2->width;
+ }
+ else if (x+dx < cur2->x+cur2->width)
+ dx=cur2->x+cur2->width-x;
+ }
+ if (cx2<width)
+ {
+ write_risc_segment(rp, adr, BT848_RISC_SKIP,
+ &x, dx, bpp, width);
+ write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+ &x, cx2-x, bpp, width);
+ dx=width-x;
+ }
+ write_risc_segment(rp, adr, BT848_RISC_SKIP,
+ &x, dx, bpp, width);
+ write_risc_segment(rp, adr, BT848_RISC_WRITEC,
+ &x, width-x, bpp, width);
+ }
+ if ((!inter)||(yy&1))
+ adr+=bpl;
+ }
+
+ *(ro++)=BT848_RISC_JUMP;
+ *(ro++)=btv->bus_vbi_even;
+ *(re++)=BT848_RISC_JUMP;
+ *(re++)=btv->bus_vbi_odd;
+}
+
/*
* Set the registers for the size we have specified. Don't bother
@@ -814,36 +993,50 @@ static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr,
struct tvnorm
{
- u16 cropwidth, cropheight;
+ u32 Fsc;
+ u16 swidth, sheight; /* scaled standard width, height */
u16 totalwidth;
u8 adelay, bdelay, iform;
u32 scaledtwidth;
u16 hdelayx1, hactivex1;
- u16 vdelay;
+ u16 vdelay, fporch;
};
static struct tvnorm tvnorms[] = {
/* PAL-BDGHI */
- { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+ { 35468950,
+ 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 1135, 186, 924, 0x20},
+/*
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+*/
/* NTSC */
- { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+ 780, 135, 754, 0x1a},
/* SECAM */
- { 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
/* PAL-M */
- { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
/* PAL-N */
- { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
- 944, 186, 922, 0x20},
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
/* PAL-NC */
- { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
- 944, 186, 922, 0x20},
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+ 944, 186, 922, 0x20},
/* NTSC-Japan */
- { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
- 780, 135, 754, 0x16},
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
};
#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
@@ -891,6 +1084,10 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
tvn=&tvnorms[btv->win.norm];
+ btv->win.cropheight=tvn->sheight;
+ btv->win.cropwidth=tvn->swidth;
+
+/*
if (btv->win.cropwidth>tvn->cropwidth)
btv->win.cropwidth=tvn->cropwidth;
if (btv->win.cropheight>tvn->cropheight)
@@ -900,7 +1097,7 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
width=btv->win.cropwidth;
if (height>btv->win.cropheight)
height=btv->win.cropheight;
-
+*/
btwrite(tvn->adelay, BT848_ADELAY);
btwrite(tvn->bdelay, BT848_BDELAY);
btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
@@ -916,12 +1113,13 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
inter=(btv->win.interlace&1)^1;
+ vdelay=btv->win.cropy+tvn->vdelay;
+
xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth;
hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
- vdelay=btv->win.cropy+tvn->vdelay;
- hdelay=(tvn->hdelayx1*tvn->scaledtwidth)/tvn->totalwidth;
- hdelay=((hdelay+btv->win.cropx)*hactive)/btv->win.cropwidth;
+ hdelay=tvn->hdelayx1+btv->win.cropx;
+ hdelay=(hdelay*hactive)/btv->win.cropwidth;
hdelay&=0x3fe;
sr=((btv->win.cropheight>>inter)*512)/height-512;
@@ -948,22 +1146,23 @@ static void bt848_set_winsize(struct bttv *btv)
{
unsigned short format;
- btv->win.color_fmt=format= (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
- bpp2fmt[(btv->win.bpp-1)&3];
-
+ btv->win.color_fmt = format =
+ (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
+ bpp2fmt[(btv->win.bpp-1)&3];
+
/* RGB8 seems to be a 9x5x5 GRB color cube starting at
* color 16. Why the h... can't they even mention this in the
* data sheet? [AC - because it's a standard format so I guess
* it never occurred to them]
* Enable dithering in this mode.
*/
-#if 0
+
if (format==BT848_COLOR_FMT_RGB8)
- btand(~0x10, BT848_CAP_CTL);
+ btand(~BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
else
- btor(0x10, BT848_CAP_CTL);
-#endif
- bt848_set_geo(btv,btv->win.width, btv->win.height, format);
+ btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL);
+
+ bt848_set_geo(btv, btv->win.width, btv->win.height, format);
}
/*
@@ -1027,7 +1226,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
if(fbuffer_alloc(btv))
return -ENOBUFS;
}
- if(btv->grabbing>1)
+ if(btv->grabbing >= MAX_GBUFFERS)
return -ENOBUFS;
/*
@@ -1040,9 +1239,16 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
if(mp->height <0 || mp->width <0)
return -EINVAL;
+/* This doesn´t work like this for NTSC anyway.
+ So, better check the total image size ...
+*/
+/*
if(mp->height>576 || mp->width>768)
return -EINVAL;
-
+*/
+ if (mp->height*mp->width*fmtbppx2[mp->format&0x0f]/2>BTTV_MAX_FBUF)
+ return -EINVAL;
+
/*
* FIXME: Check the format of the grab here. This is probably
* also less restrictive than the normal overlay grabs. Stuff
@@ -1055,27 +1261,31 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);
/* if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
- return -EAGAIN; */
+ return -EAGAIN;*/
ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
re=ro+2048;
btv->gwidth=mp->width;
btv->gheight=mp->height;
+
if (mp->format > PALETTEFMT_MAX)
return -EINVAL;
btv->gfmt=palette2fmt[mp->format];
- if(btv->gfmt==-1)
+ if(btv->gfmt==0)
return -EINVAL;
make_vrisctab(btv, ro, re, vbuf, btv->gwidth, btv->gheight, btv->gfmt);
/* bt848_set_risc_jmps(btv); */
btor(3, BT848_CAP_CTL);
btor(3, BT848_GPIO_DMA_CTL);
+ btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
if (btv->grabbing) {
btv->gro_next=virt_to_bus(ro);
btv->gre_next=virt_to_bus(re);
+ btv->grf_next=mp->frame;
} else {
btv->gro=virt_to_bus(ro);
btv->gre=virt_to_bus(re);
+ btv->grf=mp->frame;
}
if (!(btv->grabbing++))
btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
@@ -1159,7 +1369,12 @@ static int bttv_open(struct video_device *dev, int flags)
btv->user--;
return -EINVAL;
}
- break;
+ btv->grabbing = 0;
+ btv->grab = 0;
+ btv->lastgrab = 0;
+ for (i = 0; i < MAX_GBUFFERS; i++)
+ btv->frame_stat[i] = GBUFFER_UNUSED;
+ break;
case 1:
break;
}
@@ -1227,265 +1442,6 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
btaor(datahi, ~1, BT848_O_CONTROL);
}
-
-/*
- * Cliprect -> risc table.
- *
- * FIXME: This is generating wrong code when we have some kinds of
- * rectangle lists. If you generate overlapped rectangles then it
- * gets a bit confused. Since we add the frame buffer clip rectangles
- * we need to fix this. Better yet to rewrite this function.
- */
-
-static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
-{
- int i;
- u32 yy, y, x, dx, ox;
- u32 *rmem, *rmem2;
- struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2;
- u32 *rp, rpo=0, rpe=0, p, bpsl;
- u32 *rpp;
- u32 mask;
- int interlace;
- int depth;
-
- rmem=(u32 *)btv->risc_odd;
- rmem2=(u32 *)btv->risc_even;
- depth=btv->win.bpp;
-
- /* create y-sorted list */
-
- first.next=NULL;
- for (i=0; i<count; i++)
- {
- cur=&first;
- while ((nx=cur->next) && (vp[i].y > cur->next->y))
- cur=nx;
- cur->next=&(vp[i]);
- vp[i].next=nx;
- }
- first2.next=NULL;
-
- rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1|(0xf<<20);
- rmem[rpo++]=0;
-
- rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1;
- rmem2[rpe++]=0;
-
-
- /*
- * 32bit depth frame buffers need extra flags setting
- */
-
- if (depth==4)
- mask=BT848_RISC_BYTE3;
- else
- mask=0;
-
- bpsl=btv->win.width*btv->win.bpp;
- p=btv->win.vidadr+btv->win.x*btv->win.bpp+
- btv->win.y*btv->win.bpl;
-
- interlace=btv->win.interlace;
-
- /*
- * Loop through all lines
- */
-
- for (yy=0; yy<(btv->win.height<<(1^interlace)); yy++)
- {
- y=yy>>(1^interlace);
-
- /*
- * Even or odd frame generation. We have to
- * write the RISC instructions to the right stream.
- */
-
- if(!(y&1))
- {
- rp=&rpo;
- rpp=rmem;
- }
- else
- {
- rp=&rpe;
- rpp=rmem2;
- }
-
-
- /*
- * first2 is the header of a list of "active" rectangles. We add
- * rectangles as we hit their top and remove them as they fall off
- * the bottom
- */
-
- /* remove rects with y2 > y */
- if ((cur=first2.next))
- {
- prev=&first2;
- do
- {
- if (cur->y+cur->height < y)
- prev->next=cur->next;
- else
- prev=cur;
- }
- while ((cur=cur->next));
- }
-
- /*
- * Fixme - we have to handle overlapped rectangles
- * here, but the overlap might be partial
- */
-
- /* add rect to second (x-sorted) list if rect.y == y */
- if ((cur=first.next))
- {
- while ((cur) && (cur->y == y))
- {
- first.next=cur->next;
- cur2=&first2;
- while ((nx2=cur2->next) && (cur->x > cur2->next->x))
- cur2=nx2;
- cur2->next=cur;
- cur->next=nx2;
- cur=first.next;
- }
- }
-
-
- /*
- * Begin writing the RISC script
- */
-
- dx=x=0;
-
- /*
- * Starting at x position 0 on a new scan line
- * write to location p, don't yet write the number
- * of pixels for the instruction
- */
-
- rpp[(*rp)++]=BT848_RISC_WRITE|BT848_RISC_SOL;
- rpp[(*rp)++]=p;
-
- /*
- * For each rectangle we have in the "active" list - sorted left to
- * right..
- */
-
- for (cur2=first2.next; cur2; cur2=cur2->next)
- {
- /*
- * If we are to the left of the first drawing area
- */
-
- if (x+dx < cur2->x)
- {
- /* Bytes pending ? */
- if (dx)
- {
- /* For a delta away from the start we need to write a SKIP */
- if (x)
- rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth);
- else
- /* Rewrite the start of line WRITE to a SKIP */
- rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth);
- /* Move X to the next point (drawing start) */
- x=x+dx;
- }
- /* Ok how far are we from the start of the next rectangle ? */
- dx=cur2->x-x;
- /* dx is now the size of data to write */
-
- /* If this isnt the left edge generate a "write continue" */
- if (x)
- rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|mask;
- else
- /* Fill in the byte count on the initial WRITE */
- rpp[(*rp)-2]|=(dx*depth)|mask;
- /* Move to the start of the rectangle */
- x=cur2->x;
- /* x is our left dx is byte size of hole */
- dx=cur2->width+1;
- }
- else
- /* Already in a clip zone.. set dx */
- if (x+dx < cur2->x+cur2->width)
- dx=cur2->x+cur2->width-x+1;
- }
- /* now treat the rest of the line */
- ox=x;
- if (dx)
- {
- /* Complete the SKIP to eat to the end of the gap */
- if (x)
- rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth);
- else
- /* Rewrite to SKIP start to this point */
- rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth);
- x=x+dx;
- }
-
- /*
- * Not at the right hand edge ?
- */
-
- if ((dx=btv->win.width-x)!=0)
- {
- /* Write to edge of display */
- if (x)
- rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|BT848_RISC_EOL|mask;
- else
- /* Entire frame is a write - patch first order */
- rpp[(*rp)-2]|=(dx*depth)|BT848_RISC_EOL|mask;
- }
- else
- {
- /* End of line if needed */
- if (ox)
- rpp[(*rp)-1]|=BT848_RISC_EOL|mask;
- else
- {
- /* Skip the line : write a SKIP + start/end of line marks */
- (*rp)--;
- rpp[(*rp)-1]=BT848_RISC_SKIP|
- (btv->win.width*depth)|
- BT848_RISC_EOL|BT848_RISC_SOL;
- }
- }
- /*
- * Move the video render pointer on a line
- */
- if (interlace||(y&1))
- p+=btv->win.bpl;
- }
-
- /*
- * Attach the interframe jumps
- */
-
- rmem[rpo++]=BT848_RISC_JUMP;
- rmem[rpo++]=btv->bus_vbi_even;
-
- rmem2[rpe++]=BT848_RISC_JUMP;
- rmem2[rpe++]=btv->bus_vbi_odd;
-}
-
-/*
- * Helper for adding clips.
- */
-
-static void new_risc_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++;
-}
-
-
/*
* ioctl routine
*/
@@ -1495,7 +1451,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
unsigned char eedata[256];
struct bttv *btv=(struct bttv *)dev;
- static int lastchan=0;
+ int i;
switch (cmd)
{
@@ -1510,8 +1466,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
VID_TYPE_CLIPPING|
VID_TYPE_FRAMERAM|
VID_TYPE_SCALES;
- b.channels = 4; /* tv , input, svhs */
- b.audios = 4; /* tv, input, svhs */
+ b.channels = tvcards[btv->type].inputs;
+ b.audios = tvcards[btv->type].inputs;
b.maxwidth = 768;
b.maxheight = 576;
b.minwidth = 32;
@@ -1528,26 +1484,21 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.flags=VIDEO_VC_AUDIO;
v.tuners=0;
v.type=VIDEO_TYPE_CAMERA;
- switch(v.channel)
- {
- case 0:
- strcpy(v.name,"Television");
- v.flags|=VIDEO_VC_TUNER;
- v.type=VIDEO_TYPE_TV;
- v.tuners=1;
- break;
- case 1:
- strcpy(v.name,"Composite1");
- break;
- case 2:
- strcpy(v.name,"Composite2");
- break;
- case 3:
- strcpy(v.name,"SVHS");
- break;
- default:
- return -EINVAL;
- }
+ v.norm = btv->win.norm;
+ if (v.channel>=tvcards[btv->type].inputs)
+ return -EINVAL;
+ if(v.channel==tvcards[btv->type].tuner)
+ {
+ strcpy(v.name,"Television");
+ v.flags|=VIDEO_VC_TUNER;
+ v.type=VIDEO_TYPE_TV;
+ v.tuners=1;
+ }
+ else if(v.channel==tvcards[btv->type].svhs)
+ strcpy(v.name,"SVHS");
+ else
+ sprintf(v.name,"Composite%d",v.channel);
+
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -1557,11 +1508,19 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
*/
case VIDIOCSCHAN:
{
- int v;
- if(copy_from_user(&v, arg, sizeof(v)))
+ struct video_channel v;
+ if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- bt848_muxsel(btv, v);
- lastchan=v;
+
+ if (v.channel>tvcards[btv->type].inputs)
+ return -EINVAL;
+ bt848_muxsel(btv, v.channel);
+ if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC
+ &&v.norm!=VIDEO_MODE_SECAM)
+ return -EOPNOTSUPP;
+ btv->win.norm = v.norm;
+ bt848_set_winsize(btv);
+ btv->channel=v.channel;
return 0;
}
case VIDIOCGTUNER:
@@ -1569,7 +1528,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_tuner v;
if(copy_from_user(&v,arg,sizeof(v))!=0)
return -EFAULT;
- if(v.tuner||lastchan) /* Only tuner 0 */
+ if(v.tuner||btv->channel) /* Only tuner 0 */
return -EINVAL;
strcpy(v.name, "Television");
v.rangelow=0;
@@ -1581,23 +1540,22 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
return 0;
}
- /* We have but tuner 0 */
+ /* We have but one tuner */
case VIDIOCSTUNER:
{
struct video_tuner v;
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
- /* Only channel 0 has a tuner */
- if(v.tuner!=0 || lastchan)
- return -EINVAL;
+
+ /* Only one channel has a tuner */
+ if(v.tuner!=tvcards[btv->type].tuner)
+ return -EINVAL;
+
if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
&&v.mode!=VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
- /* FIXME: norm should be in video_channel struct
- composite source can have different norms too
- */
- btv->win.norm = v.mode;
- bt848_set_winsize(btv);
+ btv->win.norm = v.mode;
+ bt848_set_winsize(btv);
return 0;
}
case VIDIOCGPICT:
@@ -1682,24 +1640,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -ENOMEM;
if(vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount))
return -EFAULT;
- /*
- * Impose display clips
- */
- if(btv->win.x<0)
- new_risc_clip(&vw, vcp, 0, 0, -btv->win.x, btv->win.height-1);
- if(btv->win.y<0)
- new_risc_clip(&vw, vcp, 0, 0, btv->win.width-1,-btv->win.y);
- if(btv->win.x+btv->win.width> btv->win.swidth)
- new_risc_clip(&vw, vcp, btv->win.swidth-btv->win.x, 0, btv->win.width-1, btv->win.height-1);
- if(btv->win.y+btv->win.height > btv->win.sheight)
- new_risc_clip(&vw, vcp, 0, btv->win.sheight-btv->win.y, btv->win.width-1, btv->win.height-1);
- /*
- * Question: Do we need to walk the clip list
- * and saw off any clips outside the window
- * frame or will write_risc_tab do the right
- * thing ?
- */
- write_risc_data(btv,vcp, vw.clipcount);
+ make_clip_tab(btv,vcp, vw.clipcount);
vfree(vcp);
if(on && btv->win.vidadr!=0)
bt848_cap(btv,1);
@@ -1764,7 +1705,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
btv->win.vidadr=(unsigned long)v.base;
btv->win.sheight=v.height;
btv->win.swidth=v.width;
- btv->win.bpp=((v.depth+1)&0x38)/8;
+ btv->win.bpp=((v.depth+7)&0x38)/8;
btv->win.depth=v.depth;
btv->win.bpl=v.bytesperline;
@@ -1832,8 +1773,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
if(v.flags&VIDEO_AUDIO_MUTE)
audio(btv, AUDIO_MUTE);
- /* One audio source per tuner */
- if(v.audio!=0)
+ /* One audio source per tuner */
+ if(v.audio!=0)
return -EINVAL;
bt848_muxsel(btv,v.audio);
if(!(v.flags&VIDEO_AUDIO_MUTE))
@@ -1858,12 +1799,22 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
}
case VIDIOCSYNC:
- if (!btv->grabbing)
- return -EAGAIN;
- if (btv->grab==btv->lastgrab)
- interruptible_sleep_on(&btv->capq);
- btv->lastgrab++;
- return 0;
+ if(copy_from_user((void *)&i,arg,sizeof(int)))
+ return -EFAULT;
+ if(i>1 || i<0)
+ return -EINVAL;
+
+ switch (btv->frame_stat[i]) {
+ case GBUFFER_UNUSED:
+ return -EINVAL;
+ case GBUFFER_GRABBING:
+ interruptible_sleep_on(&btv->capq);
+ /* fall */
+ case GBUFFER_DONE:
+ btv->frame_stat[i] = GBUFFER_UNUSED;
+ break;
+ }
+ return 0;
case BTTV_WRITEE:
if(!capable(CAP_SYS_ADMIN))
@@ -1881,13 +1832,68 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
break;
+ case BTTV_FIELDNR:
+ if(copy_to_user((void *) arg, (void *) &btv->last_field,
+ sizeof(btv->last_field)))
+ return -EFAULT;
+ break;
+
+ case BTTV_PLLSET: {
+ struct bttv_pll_info p;
+ if(!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
+ return -EFAULT;
+ btv->pll.pll_ifreq = p.pll_ifreq;
+ btv->pll.pll_ofreq = p.pll_ofreq;
+ btv->pll.pll_crystal = p.pll_crystal;
+
+ break;
+ }
case VIDIOCMCAPTURE:
{
struct video_mmap vm;
if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
return -EFAULT;
+ if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING)
+ return -EBUSY;
return vgrab(btv, &vm);
}
+
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf vm;
+ memset(&vm, 0 , sizeof(vm));
+ vm.size=BTTV_MAX_FBUF*2;
+ vm.frames=2;
+ vm.offsets[0]=0;
+ vm.offsets[1]=BTTV_MAX_FBUF;
+ if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case VIDIOCGUNIT:
+ {
+ struct video_unit vu;
+ vu.video=btv->video_dev.minor;
+ vu.vbi=btv->vbi_dev.minor;
+ if(btv->radio_dev.minor!=-1)
+ vu.radio=btv->radio_dev.minor;
+ else
+ vu.radio=VIDEO_NO_UNIT;
+ vu.audio=VIDEO_NO_UNIT;
+ if(btv->have_msp3400)
+ {
+ i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400,
+ MSP_GET_UNIT, &vu.audio);
+ }
+ vu.teletext=VIDEO_NO_UNIT;
+ if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu)))
+ return -EFAULT;
+ return 0;
+ }
+
default:
return -ENOIOCTLCMD;
}
@@ -1949,7 +1955,7 @@ static struct video_device bttv_template=
bttv_init_done,
NULL,
0,
- 0
+ -1
};
@@ -2054,7 +2060,7 @@ static struct video_device vbi_template=
bttv_init_done,
NULL,
0,
- 0
+ -1
};
@@ -2092,21 +2098,34 @@ static long radio_read(struct video_device *v, char *buf, unsigned long count, i
static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct bttv *btv=(struct bttv *)(dev-1);
- static int lastchan=0;
switch (cmd) {
case VIDIOCGCAP:
- /* XXX */
+ {
+ struct video_capability v;
+ strcpy(v.name,btv->video_dev.name);
+ v.type = VID_TYPE_TUNER;
+ v.channels = 1;
+ v.audios = 1;
+ /* No we don't do pictures */
+ v.maxwidth = 0;
+ v.maxheight = 0;
+ v.minwidth = 0;
+ v.minheight = 0;
+ if (copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
break;
+ }
case VIDIOCGTUNER:
{
struct video_tuner v;
if(copy_from_user(&v,arg,sizeof(v))!=0)
return -EFAULT;
- if(v.tuner||lastchan) /* Only tuner 0 */
+ if(v.tuner||btv->channel) /* Only tuner 0 */
return -EINVAL;
strcpy(v.name, "Radio");
v.rangelow=(int)(87.5*16);
- v.rangehigh=(int)(108.0*16);
+ v.rangehigh=(int)(108*16);
v.flags= 0; /* XXX */
v.mode = 0; /* XXX */
if(copy_to_user(arg,&v,sizeof(v)))
@@ -2119,7 +2138,7 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
/* Only channel 0 has a tuner */
- if(v.tuner!=0 || lastchan)
+ if(v.tuner!=0 || btv->channel)
return -EINVAL;
/* XXX anything to do ??? */
return 0;
@@ -2151,7 +2170,7 @@ static struct video_device radio_template=
bttv_init_done, /* just returns 0 */
NULL,
0,
- 0
+ -1
};
@@ -2163,6 +2182,8 @@ struct vidbases
};
static struct vidbases vbs[] = {
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215CT222,
+ "ATI MACH64 CT", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX,
"ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215GT,
@@ -2179,8 +2200,12 @@ static struct vidbases vbs[] = {
{ PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
{ PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128,
"Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128_2,
+ "Number Nine Imagine 128 Series 2", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_NVIDIA_SGS, PCI_DEVICE_ID_NVIDIA_SGS_RIVA128,
+ "Riva128", PCI_BASE_ADDRESS_1},
};
@@ -2374,13 +2399,16 @@ static void init_tda9850(struct i2c_bus *bus)
/* Figure out card and tuner type */
-static void idcard(struct bttv *btv)
+static void idcard(int i)
{
+ struct bttv *btv = &bttvs[i];
+
+ int tunertype;
btwrite(0, BT848_GPIO_OUT_EN);
- DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA)));
+ DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA)));
/* Default the card to the user-selected one. */
- btv->type=card;
+ btv->type=card[i];
btv->tuner_type=-1; /* use default tuner type */
/* If we were asked to auto-detect, then do so!
@@ -2391,7 +2419,12 @@ static void idcard(struct bttv *btv)
btv->type=BTTV_MIRO;
if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0)
- btv->type=BTTV_HAUPPAUGE;
+ {
+ if(btv->id>849)
+ btv->type=BTTV_HAUPPAUGE878;
+ else
+ btv->type=BTTV_HAUPPAUGE;
+ }
else
if (I2CRead(&(btv->i2c), I2C_STBEE)>=0)
btv->type=BTTV_STB;
@@ -2405,13 +2438,13 @@ static void idcard(struct bttv *btv)
if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0)
{
btv->audio_chip = TDA9850;
- printk(KERN_INFO "bttv: audio chip: TDA9850\n");
+ printk(KERN_INFO "bttv%d: audio chip: TDA9850\n", i);
}
if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0)
{
btv->audio_chip = TDA8425;
- printk("bttv: audio chip: TDA8425\n");
+ printk("bttv%d: audio chip: TDA8425\n", i);
}
switch(btv->audio_chip)
@@ -2425,36 +2458,46 @@ static void idcard(struct bttv *btv)
}
/* How do I detect the tuner type for other cards but Miro ??? */
- printk(KERN_INFO "bttv: model: ");
+ printk(KERN_INFO "bttv%d: model: ", btv->nr);
+
+ sprintf(btv->video_dev.name,"BT%d",btv->id);
switch (btv->type)
{
case BTTV_MIRO:
printk("MIRO\n");
- strcpy(btv->video_dev.name,"BT848(Miro)");
+ if (btv->have_tuner)
+ {
+ tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_TUNER,
+ TUNER_SET_TYPE,&tunertype);
+ }
+ strcat(btv->video_dev.name, "(Miro)");
break;
case BTTV_HAUPPAUGE:
+ case BTTV_HAUPPAUGE878:
printk("HAUPPAUGE\n");
- strcpy(btv->video_dev.name,"BT848(Hauppauge)");
+ strcat(btv->video_dev.name,"(Hauppauge)");
break;
case BTTV_STB:
printk("STB\n");
- strcpy(btv->video_dev.name,"BT848(STB)");
+ strcat(btv->video_dev.name,"(STB)");
break;
case BTTV_INTEL:
printk("Intel\n");
- strcpy(btv->video_dev.name,"BT848(Intel)");
+ strcat(btv->video_dev.name,"(Intel)");
break;
case BTTV_DIAMOND:
printk("Diamond\n");
- strcpy(btv->video_dev.name,"BT848(Diamond)");
+ strcat(btv->video_dev.name,"(Diamond)");
break;
case BTTV_AVERMEDIA:
printk("AVerMedia\n");
- strcpy(btv->video_dev.name,"BT848(AVerMedia)");
+ strcat(btv->video_dev.name,"(AVerMedia)");
break;
case BTTV_MATRIX_VISION:
printk("MATRIX-Vision\n");
- strcpy(btv->video_dev.name,"BT848(MATRIX-Vision)");
+ strcat(btv->video_dev.name,"(MATRIX-Vision)");
break;
}
audio(btv, AUDIO_MUTE);
@@ -2523,8 +2566,18 @@ static int init_bt848(int i)
/* reset the bt848 */
btwrite(0, BT848_SRESET);
-
- DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem));
+ DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%08x\n",i,(unsigned int) btv->bt848_mem));
+
+#ifdef RESET_MSP_HAUPPAUGE
+ /* Reset the MSP on some Hauppauge cards */
+ /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */
+ /* Can this hurt cards without one? What about Miros with MSP? */
+ btaor(32, ~32, BT848_GPIO_OUT_EN);
+ btaor(0, ~32, BT848_GPIO_DATA);
+ udelay(2500);
+ btaor(32, ~32, BT848_GPIO_DATA);
+ btaor(0, ~32, BT848_GPIO_OUT_EN);
+#endif
/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
@@ -2556,6 +2609,7 @@ static int init_bt848(int i)
btv->grabcount=0;
btv->grab=0;
btv->lastgrab=0;
+ btv->field=btv->last_field=0;
/* i2c */
memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus));
@@ -2607,8 +2661,8 @@ static int init_bt848(int i)
btwrite(0xd8, BT848_CONTRAST_LO);
bt848_bright(btv, 0x10);
- btwrite(0x60, BT848_E_VSCALE_HI);
- btwrite(0x60, BT848_O_VSCALE_HI);
+ btwrite(0x20, BT848_E_VSCALE_HI);
+ btwrite(0x20, BT848_O_VSCALE_HI);
btwrite(/*BT848_ADC_SYNC_T|*/
BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC);
@@ -2627,9 +2681,10 @@ static int init_bt848(int i)
btwrite(0xfffffUL, BT848_INT_STAT);
/* set interrupt mask */
- btwrite(triton1|
-/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
- BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
+ btwrite(btv->triton1|
+ /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
+ BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
+ BT848_INT_VSYNC|
BT848_INT_SCERR|
BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
BT848_INT_FMTCHG|BT848_INT_HLOCK,
@@ -2645,7 +2700,7 @@ static int init_bt848(int i)
memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template));
memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
- idcard(btv);
+ idcard(i);
if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
return -1;
@@ -2654,7 +2709,7 @@ static int init_bt848(int i)
video_unregister_device(&btv->video_dev);
return -1;
}
- if (radio)
+ if (radio[i])
{
if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0)
{
@@ -2685,28 +2740,28 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (!astat)
return;
btwrite(astat,BT848_INT_STAT);
- IDEBUG(printk ("bttv: astat %08x\n",astat));
- IDEBUG(printk ("bttv: stat %08x\n",stat));
+ IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat));
+ IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat));
/* get device status bits */
dstat=btread(BT848_DSTATUS);
if (astat&BT848_INT_FMTCHG)
{
- IDEBUG(printk ("bttv: IRQ_FMTCHG\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr));
/*btv->win.norm&=
(dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
}
if (astat&BT848_INT_VPRES)
{
- IDEBUG(printk ("bttv: IRQ_VPRES\n"));
+ IDEBUG(printk ("bttv%d: IRQ_VPRES\n", btv->nr));
}
if (astat&BT848_INT_VSYNC)
{
- IDEBUG(printk ("bttv: IRQ_VSYNC\n"));
+ IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
}
if (astat&BT848_INT_SCERR) {
- IDEBUG(printk ("bttv: IRQ_SCERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
bt848_dma(btv, 0);
bt848_dma(btv, 1);
wake_up_interruptible(&btv->vbiq);
@@ -2715,7 +2770,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
if (astat&BT848_INT_RISCI)
{
- IDEBUG(printk ("bttv: IRQ_RISCI\n"));
+ IDEBUG(printk ("bttv%d: IRQ_RISCI\n", btv->nr));
/* captured VBI frame */
if (stat&(1<<28))
@@ -2728,10 +2783,14 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (stat&(2<<28))
{
wake_up_interruptible(&btv->capq);
+ btv->last_field=btv->field;
+ btv->grab++;
+ btv->frame_stat[btv->grf] = GBUFFER_DONE;
if ((--btv->grabbing))
{
btv->gro = btv->gro_next;
btv->gre = btv->gre_next;
+ btv->grf = btv->grf_next;
btv->risc_jmp[5]=btv->gro;
btv->risc_jmp[11]=btv->gre;
bt848_set_geo(btv, btv->gwidth,
@@ -2757,31 +2816,31 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
if (astat&BT848_INT_OCERR)
{
- IDEBUG(printk ("bttv: IRQ_OCERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_OCERR\n", btv->nr));
}
if (astat&BT848_INT_PABORT)
{
- IDEBUG(printk ("bttv: IRQ_PABORT\n"));
+ IDEBUG(printk ("bttv%d: IRQ_PABORT\n", btv->nr));
}
if (astat&BT848_INT_RIPERR)
{
- IDEBUG(printk ("bttv: IRQ_RIPERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_RIPERR\n", btv->nr));
}
if (astat&BT848_INT_PPERR)
{
- IDEBUG(printk ("bttv: IRQ_PPERR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_PPERR\n", btv->nr));
}
if (astat&BT848_INT_FDSR)
{
- IDEBUG(printk ("bttv: IRQ_FDSR\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FDSR\n", btv->nr));
}
if (astat&BT848_INT_FTRGT)
{
- IDEBUG(printk ("bttv: IRQ_FTRGT\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FTRGT\n", btv->nr));
}
if (astat&BT848_INT_FBUS)
{
- IDEBUG(printk ("bttv: IRQ_FBUS\n"));
+ IDEBUG(printk ("bttv%d: IRQ_FBUS\n", btv->nr));
}
if (astat&BT848_INT_HLOCK)
{
@@ -2797,12 +2856,12 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
count++;
if (count > 10)
- printk (KERN_WARNING "bttv: irq loop %d\n", count);
+ printk (KERN_WARNING "bttv%d: irq loop %d\n", btv->nr, count);
if (count > 20)
{
btwrite(0, BT848_INT_MASK);
printk(KERN_ERR
- "bttv: IRQ lockup, cleared int mask\n");
+ "bttv%d: IRQ lockup, cleared int mask\n", btv->nr);
}
}
}
@@ -2812,120 +2871,136 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
/*
* Scan for a Bt848 card, request the irq and map the io memory
*/
-
-static int find_bt848(void)
+
+int configure_bt848(struct pci_dev *dev, int bttv_num)
{
- unsigned char command, latency;
int result;
+ unsigned char bus, devfn, command;
struct bttv *btv;
- struct pci_dev *dev;
- bttv_num=0;
+ btv=&bttvs[bttv_num];
+ btv->dev=dev;
+ btv->nr = bttv_num;
+ btv->bus=bus=dev->bus->number;
+ btv->devfn=devfn=dev->devfn;
+ btv->bt848_mem=NULL;
+ btv->vbibuf=NULL;
+ btv->risc_jmp=NULL;
+ btv->vbi_odd=NULL;
+ btv->vbi_even=NULL;
+ btv->vbiq=NULL;
+ btv->capq=NULL;
+ btv->capqo=NULL;
+ btv->capqe=NULL;
+ btv->vbip=VBIBUF_SIZE;
+
+ btv->id=dev->device;
+ btv->irq=dev->irq;
+ btv->bt848_adr=dev->base_address[0];
+ if (btv->id >= 878)
+ btv->i2c_command = 0x83;
+ else
+ btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA);
+
+ if (remap[bttv_num])
+ {
+ if (remap[bttv_num] < 0x1000)
+ remap[bttv_num]<<=20;
+ remap[bttv_num]&=PCI_BASE_ADDRESS_MEM_MASK;
+ printk(KERN_INFO "bttv%d: remapping to : 0x%08x.\n",
+ bttv_num,remap[bttv_num]);
+ remap[bttv_num]|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, remap[bttv_num]);
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
+ btv->dev->base_address[0] = btv->bt848_adr;
+ }
+ btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+ printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ",
+ bttv_num,btv->id, btv->revision);
+ printk("bus: %d, devfn: %d, ",
+ btv->bus, btv->devfn);
+ printk("irq: %d, ",btv->irq);
+ printk("memory: 0x%08x.\n", btv->bt848_adr);
+
+ btv->pll.pll_ifreq=0;
+ btv->pll.pll_ifreq=0;
+ btv->pll.pll_crystal=0;
+ if(pll[btv->nr])
+ if (!(btv->id==848 && btv->revision==0x11))
+ {
+ printk(KERN_INFO "bttv%d: internal PLL, single crystal operation enabled\n",bttv_num);
+ btv->pll.pll_ofreq=28636363;
+ btv->pll.pll_ifreq=35468950;
+ btv->pll.pll_crystal=BT848_IFORM_XT1;
+ }
+
+ btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+
+ /* clear interrupt mask */
+ btwrite(0, BT848_INT_MASK);
- if (!pcibios_present())
- {
- DEBUG(printk(KERN_DEBUG "bttv: 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_BROOKTREE)
- continue;
- if (dev->device != PCI_DEVICE_ID_BT849 &&
- dev->device != PCI_DEVICE_ID_BT848)
- continue;
+ result = request_irq(btv->irq, bttv_irq,
+ SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
+ if (result==-EINVAL)
+ {
+ printk(KERN_ERR "bttv%d: Bad irq number or handler\n",
+ bttv_num);
+ return -EINVAL;
+ }
+ if (result==-EBUSY)
+ {
+ printk(KERN_ERR "bttv%d: IRQ %d busy, change your PnP config in BIOS\n",bttv_num,btv->irq);
+ return result;
+ }
+ if (result < 0)
+ return result;
+
+ pci_set_master(dev);
- /* Ok, Bt848 or Bt849 found! */
- btv=&bttvs[bttv_num];
- btv->dev=dev;
- btv->bt848_mem=NULL;
- btv->vbibuf=NULL;
- btv->risc_jmp=NULL;
- btv->vbi_odd=NULL;
- btv->vbi_even=NULL;
- btv->vbiq=NULL;
- btv->capq=NULL;
- btv->capqo=NULL;
- btv->capqe=NULL;
-
- btv->vbip=VBIBUF_SIZE;
-
- pci_read_config_word (btv->dev, PCI_DEVICE_ID, &btv->id);
-
- /* pci_read_config_dword(btv->dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr); */
- btv->bt848_adr = btv->dev->base_address[0];
-
- if (remap&&(!bttv_num))
- {
- remap<<=20;
- remap&=PCI_BASE_ADDRESS_MEM_MASK;
- printk(KERN_INFO "Remapping to : 0x%08x.\n", remap);
- remap|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
- pci_write_config_dword(btv->dev, PCI_BASE_ADDRESS_0, remap);
- pci_read_config_dword(btv->dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
- btv->dev->base_address[0] = btv->bt848_adr;
- }
-
- btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
- pci_read_config_byte(btv->dev, PCI_CLASS_REVISION,
- &btv->revision);
- printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
- btv->id, btv->revision);
- printk("bus: %d, devfn: %d, ",
- btv->dev->bus->number, btv->dev->devfn);
- printk("irq: %d, ",btv->dev->irq);
- printk("memory: 0x%08x.\n", btv->bt848_adr);
-
- btv->pll = 0;
-#ifdef USE_PLL
- if (btv->id==849 || (btv->id==848 && btv->revision==0x12))
+ btv->triton1=triton1 ? BT848_INT_ETBF : 0;
+ if (triton1 && btv->id >= 878)
+ {
+ btv->triton1 = 0;
+ printk("bttv: Enabling 430FX compatibilty for bt878\n");
+ pci_read_config_byte(dev, BT878_DEVCTRL, &command);
+ command|=BT878_EN_TBFX;
+ pci_write_config_byte(dev, BT878_DEVCTRL, command);
+ pci_read_config_byte(dev, BT878_DEVCTRL, &command);
+ if (!(command&BT878_EN_TBFX))
{
- printk(KERN_INFO "bttv: internal PLL, single crystal operation enabled.\n");
- btv->pll=1;
+ printk("bttv: 430FX compatibility could not be enabled\n");
+ return -1;
}
-#endif
-
- btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+ }
+
+ return 0;
+}
- result = request_irq(btv->dev->irq, bttv_irq,
- SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
- if (result==-EINVAL)
- {
- printk(KERN_ERR "bttv: Bad irq number or handler\n");
- return -EINVAL;
- }
- if (result==-EBUSY)
- {
- printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->dev->irq);
- return result;
- }
- if (result < 0)
- return result;
+static int find_bt848(void)
+{
+ struct pci_dev *dev = pci_devices;
+ int result=0;
- /* Enable bus-mastering */
- pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
- command|=PCI_COMMAND_MASTER;
- pci_write_config_byte(btv->dev, PCI_COMMAND, command);
- pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
- if (!(command&PCI_COMMAND_MASTER))
- {
- printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n");
- return -1;
- }
- pci_read_config_byte(btv->dev, PCI_LATENCY_TIMER, &latency);
- if (!latency)
- {
- latency=32;
- pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
- }
- DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
- bttv_num++;
- }
+ bttv_num=0;
+
+ while (dev)
+ {
+ if (dev->vendor == PCI_VENDOR_ID_BROOKTREE)
+ if ((dev->device == PCI_DEVICE_ID_BT848)||
+ (dev->device == PCI_DEVICE_ID_BT849)||
+ (dev->device == PCI_DEVICE_ID_BT878)||
+ (dev->device == PCI_DEVICE_ID_BT879))
+ result=configure_bt848(dev,bttv_num++);
+ if (result)
+ return result;
+ dev = dev->next;
+ }
if(bttv_num)
- printk(KERN_INFO "bttv: %d Bt848 card(s) found.\n", bttv_num);
+ printk(KERN_INFO "bttv: %d BT8xx card(s) found.\n", bttv_num);
return bttv_num;
}
-
+
static void release_bttv(void)
{
@@ -2974,14 +3049,16 @@ static void release_bttv(void)
vfree((void *) btv->vbibuf);
- free_irq(btv->dev->irq,btv);
+ free_irq(btv->irq,btv);
DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
if (btv->bt848_mem)
iounmap(btv->bt848_mem);
- video_unregister_device(&btv->video_dev);
- video_unregister_device(&btv->vbi_dev);
- if (radio)
+ if(btv->video_dev.minor!=-1)
+ video_unregister_device(&btv->video_dev);
+ if(btv->vbi_dev.minor!=-1)
+ video_unregister_device(&btv->vbi_dev);
+ if (radio && btv->radio_dev.minor != -1)
video_unregister_device(&btv->radio_dev);
}
}
@@ -3036,3 +3113,4 @@ void cleanup_module(void)
* tab-width: 8
* End:
*/
+
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index e1e21f595..f8da6c6d0 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -32,17 +32,11 @@
#include <linux/videodev.h>
#define MAX_CLIPRECS 100
+#define MAX_GBUFFERS 2
#define RISCMEM_LEN (32744*2)
-#define BTTV_MAX_FBUF 0x144000
-
-
-/* clipping rectangle */
-struct cliprec
-{
- int x, y, x2, y2;
- struct cliprec *next;
-};
+/* maximum needed buffer size for extended VBI frame mode capturing */
+#define BTTV_MAX_FBUF 0x151000
#ifdef __KERNEL__
@@ -63,6 +57,12 @@ struct bttv_window
};
+struct bttv_pll_info {
+ unsigned int pll_ifreq; /* PLL input frequency */
+ unsigned int pll_ofreq; /* PLL output frequency */
+ unsigned int pll_crystal; /* Crystal used for input */
+};
+
struct bttv
{
struct video_device video_dev;
@@ -75,9 +75,14 @@ struct bttv
int have_msp3400;
int have_tuner;
int tuner_type;
-
+ int channel;
+
+ unsigned int nr;
unsigned short id;
+ unsigned char bus; /* PCI bus the Bt848 is on */
+ unsigned char devfn;
struct pci_dev *dev;
+ unsigned char irq; /* IRQ used by Bt848 card */
unsigned char revision;
unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */
unsigned char *bt848_mem; /* pointer to mapped IO memory */
@@ -106,26 +111,38 @@ struct bttv
u32 *risc_odd;
u32 *risc_even;
int cap;
- struct cliprec *cliprecs;
- int ncr; /* number of clipping rectangles */
+ struct video_clip *cliprecs;
struct gbuffer *ogbuffers;
struct gbuffer *egbuffers;
u16 gwidth, gheight, gfmt;
u32 *grisc;
+
unsigned long gro;
unsigned long gre;
unsigned long gro_next;
unsigned long gre_next;
- char *fbuffer;
+
+ int grf,grf_next; /* frame numbers in grab queue */
+ int frame_stat[MAX_GBUFFERS];
+#define GBUFFER_UNUSED 0
+#define GBUFFER_GRABBING 1
+#define GBUFFER_DONE 2
+
+ char *fbuffer;
int gmode;
int grabbing;
int lastgrab;
int grab;
int grabcount;
- int pll;
-};
+ struct bttv_pll_info pll;
+ unsigned int Fsc;
+ unsigned int field;
+ unsigned int last_field; /* number of last grabbed field */
+ int i2c_command;
+ int triton1;
+};
#endif
/*The following should be done in more portable way. It depends on define
@@ -148,6 +165,8 @@ struct bttv
#define BTTV_READEE _IOW('v', BASE_VIDIOCPRIVATE+0, char [256])
#define BTTV_WRITEE _IOR('v', BASE_VIDIOCPRIVATE+1, char [256])
#define BTTV_GRAB _IOR('v' , BASE_VIDIOCPRIVATE+2, struct gbuf)
+#define BTTV_FIELDNR _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)
+#define BTTV_PLLSET _IOW('v' , BASE_VIDIOCPRIVATE+3, struct bttv_pll_info)
#define BTTV_UNKNOWN 0x00
@@ -159,6 +178,7 @@ struct bttv
#define BTTV_AVERMEDIA 0x06
#define BTTV_MATRIX_VISION 0x07
#define BTTV_FLYVIDEO 0x08
+#define BTTV_HAUPPAUGE878 0x09
#define AUDIO_TUNER 0x00
#define AUDIO_RADIO 0x01
@@ -186,7 +206,6 @@ struct bttv
#define TDA9850_ALI2 0x09
#define TDA9850_ALI3 0x0a
-
#define TDA8425_VL 0x00
#define TDA8425_VR 0x01
#define TDA8425_BA 0x02
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index e8eb8ec8a..34651f9e9 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -106,11 +106,11 @@ static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
MSE_INT_ON();
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -122,7 +122,7 @@ static int fasync_mouse(struct file *filp, int on)
static int close_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
MSE_INT_OFF();
@@ -238,6 +238,7 @@ struct file_operations bus_mouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
close_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 976219825..026ced7e8 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,7 +1,7 @@
#define BLOCKMOVE
#define Z_WAKE
static char rcsid[] =
-"$Revision: 2.2.1.5 $$Date: 1998/08/10 18:10:28 $";
+"$Revision: 2.2.1.7 $$Date: 1998/09/03 12:07:28 $";
/*
* linux/drivers/char/cyclades.c
@@ -31,6 +31,16 @@ static char rcsid[] =
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
+ * Revision 2.2.1.7 1998/09/03 12:07:28 ivan
+ * Fixed bug in cy_close function, which was not informing HW of
+ * which port should have the reception disabled before doing so;
+ * fixed Cyclom-8YoP hardware detection bug.
+ *
+ * Revision 2.2.1.6 1998/08/20 17:15:39 ivan
+ * Fixed bug in cy_close function, which causes malfunction
+ * of one of the first 4 ports when a higher port is closed
+ * (Cyclom-Y only).
+ *
* Revision 2.2.1.5 1998/08/10 18:10:28 ivan
* Fixed Cyclom-4Yo hardware detection bug.
*
@@ -2679,10 +2689,14 @@ cy_close(struct tty_struct * tty, struct file * filp)
}
if (!IS_CYC_Z(cy_card[info->card])) {
- unsigned char *base_addr = (unsigned char *)
- cy_card[info->card].base_addr;
+ int channel = info->line - cy_card[info->card].first_line;
int index = cy_card[info->card].bus_index;
+ unsigned char *base_addr = (unsigned char *)
+ (cy_card[info->card].base_addr +
+ (cy_chip_offset[channel>>2] <<index));
/* Stop accepting input */
+ channel &= 0x03;
+ cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyRxData);
if (info->flags & ASYNC_INITIALIZED) {
@@ -4532,7 +4546,7 @@ cy_detect_pci(void))
unsigned long pci_intr_ctrl;
unsigned char cy_pci_irq = 0;
uclong cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
- unsigned short i,j,cy_pci_nchan;
+ unsigned short i,j,cy_pci_nchan, plx_ver;
unsigned short device_id,dev_index = 0;
uclong mailbox;
uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
@@ -4644,10 +4658,26 @@ cy_detect_pci(void))
IRQ_cards[cy_pci_irq] = &cy_card[j];
/* enable interrupts in the PCI interface */
- outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
- pci_intr_ctrl = (unsigned long)
- (inw(cy_pci_addr1+0x68)
+ plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
+ switch (plx_ver) {
+ case PLX_9050:
+
+ outw(inw(cy_pci_addr1+0x4c)|0x0040,cy_pci_addr1+0x4c);
+ pci_intr_ctrl = (unsigned long)
+ (inw(cy_pci_addr1+0x4c)
+ | inw(cy_pci_addr1+0x4e)<<16);
+ break;
+
+ case PLX_9060:
+ case PLX_9080:
+ default: /* Old boards, use PLX_9060 */
+
+ outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68);
+ pci_intr_ctrl = (unsigned long)
+ (inw(cy_pci_addr1+0x68)
| inw(cy_pci_addr1+0x6a)<<16);
+ break;
+ }
/* print message */
printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
@@ -4944,7 +4974,7 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
if (info->count)
size = sprintf(buf+len,
- "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6d\n",
+ "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
info->line,
JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ,
info->idle_stats.xmit_bytes,
diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c
index a694d9346..02436b8f2 100644
--- a/drivers/char/dn_keyb.c
+++ b/drivers/char/dn_keyb.c
@@ -360,11 +360,11 @@ static ssize_t read_mouse(struct file * file, char * buffer,
return count;
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse_fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse_fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -373,7 +373,7 @@ static int fasync_mouse(struct file *filp, int on)
static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse_active)
return 0;
MSE_UPDATE_OFF();
@@ -560,6 +560,7 @@ struct file_operations apollo_mouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
release_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 7818e8da3..c9c22f695 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -510,6 +510,7 @@ static struct file_operations dsp56k_fops = {
dsp56k_ioctl,
NULL, /* no special dsp56k_mmap */
dsp56k_open,
+ NULL, /* flush */
dsp56k_release,
NULL, /* no special dsp56k_fsync */
NULL, /* no special dsp56k_fasync */
diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c
index 0a4403fb6..d80d5e5b3 100644
--- a/drivers/char/fbmem.c
+++ b/drivers/char/fbmem.c
@@ -475,6 +475,7 @@ static struct file_operations fb_fops = {
fb_ioctl, /* ioctl */
fb_mmap, /* mmap */
fb_open, /* open */
+ NULL, /* flush */
fb_release, /* release */
NULL /* fsync */
};
diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c
index ebb6a3f04..ee21d92d4 100644
--- a/drivers/char/ftape/lowlevel/ftape-proc.c
+++ b/drivers/char/ftape/lowlevel/ftape-proc.c
@@ -94,6 +94,7 @@ static struct file_operations ftape_proc_fops =
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* no special open code */
+ NULL, /* flush */
NULL, /* no special release code */
NULL, /* can't fsync */
};
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index 78a857ace..1b5034939 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -134,6 +134,7 @@ static struct file_operations zft_cdev =
zft_ioctl, /* ioctl */
zft_mmap, /* mmap */
zft_open, /* open */
+ NULL, /* flush */
zft_close, /* release */
NULL, /* fsync */
};
diff --git a/drivers/char/h8.c b/drivers/char/h8.c
index 287698298..c76aeb79b 100644
--- a/drivers/char/h8.c
+++ b/drivers/char/h8.c
@@ -113,6 +113,7 @@ static struct file_operations h8_fops = {
NULL,
NULL, /* mmap */
NULL,
+ NULL, /* flush */
NULL,
NULL, /* fsync */
NULL /* fasync */
diff --git a/drivers/char/hfmodem/main.c b/drivers/char/hfmodem/main.c
index a0fc34463..de5ed5cc2 100644
--- a/drivers/char/hfmodem/main.c
+++ b/drivers/char/hfmodem/main.c
@@ -565,6 +565,7 @@ static struct file_operations hfmodem_fops = {
hfmodem_ioctl, /* hfmodem_ioctl */
NULL, /* hfmodem_mmap */
hfmodem_open, /* hfmodem_open */
+ NULL, /* flush */
hfmodem_close, /* hfmodem_close */
NULL, /* hfmodem_fsync */
NULL, /* hfmodem_fasync */
diff --git a/drivers/char/joystick.c b/drivers/char/joystick.c
index 25a7c2b47..4f940f4d5 100644
--- a/drivers/char/joystick.c
+++ b/drivers/char/joystick.c
@@ -771,6 +771,7 @@ static struct file_operations js_fops =
js_ioctl, /* js_ioctl */
NULL, /* js_mmap */
js_open, /* js_open */
+ NULL, /* js_flush */
js_release, /* js_release */
NULL /* js_sync */
};
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 1036f1046..b8d143fbe 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -13,7 +13,7 @@
* lp_read (Status readback) support added by Carsten Gross,
* carsten@sol.wohnheim.uni-ulm.de
* Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
- * Parport sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Parport sharing hacking by Andrea Arcangeli
* Fixed kernel_(to/from)_user memory copy to check for errors
* by Riccardo Facchetti <fizban@tin.it>
* Interrupt handling workaround for printers with buggy handshake
@@ -714,6 +714,7 @@ static struct file_operations lp_fops = {
lp_ioctl,
NULL, /* lp_mmap */
lp_open,
+ NULL, /* flush */
lp_release
};
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index 5079b2e62..dc0300751 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -467,6 +467,7 @@ static struct file_operations lp_fops = {
lp_ioctl,
NULL, /* lp_mmap */
lp_open,
+ NULL, /* flush */
lp_release
};
diff --git a/drivers/char/macmouse.c b/drivers/char/macmouse.c
index 2d7145203..b9236bb93 100644
--- a/drivers/char/macmouse.c
+++ b/drivers/char/macmouse.c
@@ -150,11 +150,11 @@ static void mac_mouse_interrupt(char *buf, int nb)
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -162,7 +162,7 @@ static int fasync_mouse(struct file *filp, int on)
static int release_mouse(struct inode *inode, struct file *file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
@@ -242,6 +242,7 @@ struct file_operations mac_mouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
release_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 2e1c46973..b8ff8c980 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -415,6 +415,7 @@ static struct file_operations mem_fops = {
NULL, /* mem_ioctl */
mmap_mem,
NULL, /* no special open code */
+ NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
};
@@ -428,6 +429,7 @@ static struct file_operations kmem_fops = {
NULL, /* kmem_ioctl */
mmap_kmem,
NULL, /* no special open code */
+ NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
};
@@ -441,6 +443,7 @@ static struct file_operations null_fops = {
NULL, /* null_ioctl */
NULL, /* null_mmap */
NULL, /* no special open code */
+ NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
};
@@ -454,6 +457,7 @@ static struct file_operations port_fops = {
NULL, /* port_ioctl */
NULL, /* port_mmap */
NULL, /* no special open code */
+ NULL, /* flush */
NULL, /* no special release code */
NULL /* fsync */
};
@@ -467,6 +471,7 @@ static struct file_operations zero_fops = {
NULL, /* zero_ioctl */
mmap_zero,
NULL, /* no special open code */
+ NULL, /* flush */
NULL /* no special release code */
};
@@ -479,6 +484,7 @@ static struct file_operations full_fops = {
NULL, /* full_ioctl */
NULL, /* full_mmap */
NULL, /* no special open code */
+ NULL, /* flush */
NULL /* no special release code */
};
@@ -526,6 +532,7 @@ static struct file_operations memory_fops = {
NULL, /* ioctl */
NULL, /* mmap */
memory_open, /* just a selector for the real open */
+ NULL, /* flush */
NULL, /* release */
NULL /* fsync */
};
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 8b4b16b99..8f3968639 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -142,6 +142,7 @@ static struct file_operations misc_fops = {
NULL, /* ioctl */
NULL, /* mmap */
misc_open,
+ NULL, /* flush */
NULL /* release */
};
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index 9ef067ccc..b49bfe9a6 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -89,11 +89,11 @@ static void ms_mouse_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
}
-static int fasync_mouse(struct file *filp, int on)
+static int fasync_mouse(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
if (retval < 0)
return retval;
return 0;
@@ -101,7 +101,7 @@ static int fasync_mouse(struct file *filp, int on)
static int release_mouse(struct inode * inode, struct file * file)
{
- fasync_mouse(file, 0);
+ fasync_mouse(-1, file, 0);
if (--mouse.active)
return 0;
MS_MSE_INT_OFF();
@@ -174,6 +174,7 @@ struct file_operations ms_bus_mouse_fops = {
NULL, /* mouse_ioctl */
NULL, /* mouse_mmap */
open_mouse,
+ NULL, /* flush */
release_mouse,
NULL,
fasync_mouse,
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
index 18cce49dd..6068ff3d7 100644
--- a/drivers/char/msp3400.c
+++ b/drivers/char/msp3400.c
@@ -1070,6 +1070,10 @@ static int msp3400c_command(struct i2c_device *device,
(int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
UNLOCK_I2C_BUS(msp->bus);
break;
+
+ case MSP_GET_UNIT:
+ *iarg = msp->mixer;
+ break;
default:
return -EINVAL;
diff --git a/drivers/char/msp3400.h b/drivers/char/msp3400.h
index e4029c03e..8b093ff05 100644
--- a/drivers/char/msp3400.h
+++ b/drivers/char/msp3400.h
@@ -20,4 +20,6 @@
#define MSP_GET_TREBLE _IOR('m',11,int)
#define MSP_SET_TREBLE _IOW('m',12,int)
+#define MSP_GET_UNIT _IOR('m',13,int)
+
#endif /* MSP3400_H */
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 1cf7e9d01..07272723d 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -842,22 +842,25 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
* buffer, and once to drain the space from the (physical) beginning of
* the buffer to head pointer.
*/
-static inline void copy_from_read_buf(struct tty_struct *tty,
+static inline int copy_from_read_buf(struct tty_struct *tty,
unsigned char **b,
size_t *nr)
{
+ int retval;
ssize_t n;
+ retval = 0;
n = MIN(*nr, MIN(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail));
- if (!n)
- return;
- /* N.B. copy_to_user may work only partially */
- n -= copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
- tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
- tty->read_cnt -= n;
- *b += n;
- *nr -= n;
+ if (n) {
+ retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
+ n -= retval;
+ tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
+ tty->read_cnt -= n;
+ *b += n;
+ *nr -= n;
+ }
+ return retval;
}
static ssize_t read_chan(struct tty_struct *tty, struct file *file,
@@ -996,9 +999,13 @@ do_it_again:
}
}
} else {
- /* N.B. check for errors writing to user space? */
- copy_from_read_buf(tty, &b, &nr);
- copy_from_read_buf(tty, &b, &nr);
+ int uncopied;
+ uncopied = copy_from_read_buf(tty, &b, &nr);
+ uncopied += copy_from_read_buf(tty, &b, &nr);
+ if (uncopied) {
+ retval = -EFAULT;
+ break;
+ }
}
/* If there is enough space in the read buffer now, let the
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index a3353f4af..11e7eadcf 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -402,6 +402,7 @@ static struct file_operations nvram_fops = {
nvram_ioctl,
NULL, /* No mmap */
nvram_open,
+ NULL, /* flush */
nvram_release
};
diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c
index 85ea0fbb4..247cfa181 100644
--- a/drivers/char/pc110pad.c
+++ b/drivers/char/pc110pad.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/busmouse.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/mm.h>
@@ -474,11 +473,11 @@ static void sample_ps2(int d[3])
-static int fasync_pad(struct file *filp, int on)
+static int fasync_pad(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &asyncptr);
+ retval = fasync_helper(fd, filp, on, &asyncptr);
if (retval < 0)
return retval;
return 0;
@@ -490,7 +489,7 @@ static int fasync_pad(struct file *filp, int on)
*/
static int close_pad(struct inode * inode, struct file * file)
{
- fasync_pad(file, 0);
+ fasync_pad(-1, file, 0);
if (--active)
return 0;
outb(0x30, current_params.io+2); /* switch off digitiser */
@@ -626,6 +625,7 @@ static struct file_operations pad_fops = {
pad_ioctl,
NULL, /* pad_mmap */
open_pad,
+ NULL, /* flush */
close_pad,
NULL, /* fsync */
fasync_pad,
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 67d652aab..e12ebc649 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -30,176 +30,6 @@
#include "pc_keyb.h"
-/*
- * In case we run on a non-x86 hardware we need to initialize both the keyboard
- * controller and the keyboard. On a x86, the BIOS will already have initialized
- * them.
- */
-
-/*
- * Some x86 BIOSes do not correctly initialize the keyboard, so the
- * "kbd-reset" command line options can be given to force a reset.
- * [Ranger]
- */
-#ifdef __i386__
-int kbd_startup_reset __initdata = 0;
-#else
-int kbd_startup_reset __initdata = 1;
-#endif
-
-static int kbd_wait_for_input(void)
-{
- int status, data;
- unsigned long start = jiffies;
-
- do {
- status = kbd_read_status();
-
- /*
- * Wait for input data to become available. This bit will
- * then be cleared by the following read of the DATA
- * register.
- */
- if (!(status & KBD_STAT_OBF))
- continue;
-
- data = kbd_read_input();
-
- /*
- * Check to see if a timeout error has occurred. This means
- * that transmission was started but did not complete in the
- * normal time cycle. PERR is set when a parity error occurred
- * in the last transmission.
- */
- if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) {
- continue;
- }
- return (data & 0xff);
- } while (jiffies - start < KBD_INIT_TIMEOUT);
- return -1; /* timed-out if fell through to here... */
-}
-
-static char *initialize_kbd2(void)
-{
- int status;
-
- /* Flush any pending input. */
-
- while (kbd_wait_for_input() != -1)
- ;
-
- /*
- * Test the keyboard interface.
- * This seems to be the only way to get it going.
- * If the test is successful a x55 is placed in the input buffer.
- */
-
- kbd_write_command(KBD_CCMD_SELF_TEST);
- if (kbd_wait_for_input() != 0x55)
- return "Keyboard failed self test";
-
- /*
- * Perform a keyboard interface test. This causes the controller
- * to test the keyboard clock and data lines. The results of the
- * test are placed in the input buffer.
- */
-
- kbd_write_command(KBD_CCMD_KBD_TEST);
- if (kbd_wait_for_input() != 0x00)
- return "Keyboard interface failed self test";
-
- /* Enable the keyboard by allowing the keyboard clock to run. */
-
- kbd_write_command(KBD_CCMD_KBD_ENABLE);
-
- /*
- * Reset keyboard. If the read times out
- * then the assumption is that no keyboard is
- * plugged into the machine.
- * This defaults the keyboard to scan-code set 2.
- *
- * Set up to try again if the keyboard asks for RESEND.
- */
-
- do {
- kbd_write_output(KBD_CMD_RESET);
- status = kbd_wait_for_input();
- if (status == KBD_REPLY_ACK)
- break;
- else if (status != KBD_REPLY_RESEND)
- return "Keyboard reset failed, no ACK";
- } while (1);
-
- if (kbd_wait_for_input() != KBD_REPLY_POR)
- return "Keyboard reset failed, no POR";
-
- /*
- * Set keyboard controller mode. During this, the keyboard should be
- * in the disabled state.
- *
- * Set up to try again if the keyboard asks for RESEND.
- */
-
- do {
- kbd_write_output(KBD_CMD_DISABLE);
- status = kbd_wait_for_input();
- if (status == KBD_REPLY_ACK)
- break;
- else if (status != KBD_REPLY_RESEND)
- return "Disable keyboard: no ACK";
- } while (1);
-
- kbd_write_command(KBD_CCMD_WRITE_MODE);
- kbd_write_output(KBD_MODE_KBD_INT
- | KBD_MODE_SYS
- | KBD_MODE_DISABLE_MOUSE
- | KBD_MODE_KCC);
-
- /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
- kbd_write_command(KBD_CCMD_READ_MODE);
- if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
- /*
- * If the controller does not support conversion,
- * Set the keyboard to scan-code set 1.
- */
- kbd_write_output(0xF0);
- kbd_wait_for_input();
- kbd_write_output(0x01);
- kbd_wait_for_input();
- }
-
- kbd_write_output(KBD_CMD_ENABLE);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Enable keyboard: no ACK";
-
- /*
- * Finally, set the typematic rate to maximum.
- */
-
- kbd_write_output(KBD_CMD_SET_RATE);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Set rate: no ACK";
- kbd_write_output(0x00);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Set rate: no ACK";
-
- return NULL;
-}
-
-void initialize_kbd(void)
-{
- char *msg;
-
- disable_irq(KEYBOARD_IRQ);
- msg = initialize_kbd2();
- enable_irq(KEYBOARD_IRQ);
-
- if (msg)
- printk(KERN_WARNING "initialize_kbd: %s\n", msg);
-}
-
-
-
unsigned char pckbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
/* used only by send_data - set by keyboard_interrupt */
@@ -415,7 +245,7 @@ static int do_acknowledge(unsigned char scancode)
int pckbd_pretranslate(unsigned char scancode, char raw_mode)
{
if (scancode == 0xff) {
- /* in scancode mode 1, my ESC key generates 0xff */
+ /* in scancode mode 1, my ESC key generates 0xff */
/* the calculator keys on a FOCUS 9000 generate 0xff */
#ifndef KBD_IS_FOCUS_9000
#ifdef KBD_REPORT_ERR
@@ -523,7 +353,7 @@ char pckbd_unexpected_up(unsigned char keycode)
return 0200;
}
-static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char status;
@@ -600,15 +430,198 @@ void pckbd_leds(unsigned char leds)
send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */
}
-__initfunc(void pckbd_init_hw(void))
-{
- request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
- keyboard_setup();
- if (kbd_startup_reset) initialize_kbd();
-}
+/*
+ * In case we run on a non-x86 hardware we need to initialize both the
+ * keyboard controller and the keyboard. On a x86, the BIOS will
+ * already have initialized them.
+ *
+ * Some x86 BIOSes do not correctly initialize the keyboard, so the
+ * "kbd-reset" command line options can be given to force a reset.
+ * [Ranger]
+ */
+#ifdef __i386__
+ int kbd_startup_reset __initdata = 0;
+#else
+ int kbd_startup_reset __initdata = 1;
+#endif
/* for "kbd-reset" cmdline param */
-__initfunc(void kbd_reset_setup(char *str, int *ints))
+void __init kbd_reset_setup(char *str, int *ints)
{
kbd_startup_reset = 1;
}
+
+#define KBD_NO_DATA (-1) /* No data */
+#define KBD_BAD_DATA (-2) /* Parity or other error */
+
+static int __init kbd_read_data(void)
+{
+ int retval = KBD_NO_DATA;
+ unsigned char status;
+
+ status = kbd_read_status();
+ if (status & KBD_STAT_OBF) {
+ unsigned char data = kbd_read_input();
+
+ retval = data;
+ if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
+ retval = KBD_BAD_DATA;
+ }
+ return retval;
+}
+
+static void __init kbd_clear_input(void)
+{
+ int maxread = 100; /* Random number */
+
+ do {
+ if (kbd_read_data() == KBD_NO_DATA)
+ break;
+ } while (--maxread);
+}
+
+static int __init kbd_wait_for_input(void)
+{
+ long timeout = KBD_INIT_TIMEOUT;
+
+ do {
+ int retval = kbd_read_data();
+ if (retval >= 0)
+ return retval;
+ mdelay(1);
+ } while (--timeout);
+ return -1;
+}
+
+static void __init kbd_write_command_w(int data)
+{
+ int status;
+
+ do {
+ status = kbd_read_status();
+ } while (status & KBD_STAT_IBF);
+ kbd_write_command(data);
+}
+
+static void __init kbd_write_output_w(int data)
+{
+ int status;
+
+ do {
+ status = kbd_read_status();
+ } while (status & KBD_STAT_IBF);
+ kbd_write_output(data);
+}
+
+static char * __init initialize_kbd(void)
+{
+ int status;
+
+ /*
+ * Test the keyboard interface.
+ * This seems to be the only way to get it going.
+ * If the test is successful a x55 is placed in the input buffer.
+ */
+ kbd_write_command_w(KBD_CCMD_SELF_TEST);
+ if (kbd_wait_for_input() != 0x55)
+ return "Keyboard failed self test";
+
+ /*
+ * Perform a keyboard interface test. This causes the controller
+ * to test the keyboard clock and data lines. The results of the
+ * test are placed in the input buffer.
+ */
+ kbd_write_command_w(KBD_CCMD_KBD_TEST);
+ if (kbd_wait_for_input() != 0x00)
+ return "Keyboard interface failed self test";
+
+ /*
+ * Enable the keyboard by allowing the keyboard clock to run.
+ */
+ kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
+
+ /*
+ * Reset keyboard. If the read times out
+ * then the assumption is that no keyboard is
+ * plugged into the machine.
+ * This defaults the keyboard to scan-code set 2.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write_output_w(KBD_CMD_RESET);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ return "Keyboard reset failed, no ACK";
+ } while (1);
+
+ if (kbd_wait_for_input() != KBD_REPLY_POR)
+ return "Keyboard reset failed, no POR";
+
+ /*
+ * Set keyboard controller mode. During this, the keyboard should be
+ * in the disabled state.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
+ */
+ do {
+ kbd_write_output_w(KBD_CMD_DISABLE);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ if (status != KBD_REPLY_RESEND)
+ return "Disable keyboard: no ACK";
+ } while (1);
+
+ kbd_write_command_w(KBD_CCMD_WRITE_MODE);
+ kbd_write_output_w(KBD_MODE_KBD_INT
+ | KBD_MODE_SYS
+ | KBD_MODE_DISABLE_MOUSE
+ | KBD_MODE_KCC);
+
+ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+ kbd_write_command_w(KBD_CCMD_READ_MODE);
+ if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+ /*
+ * If the controller does not support conversion,
+ * Set the keyboard to scan-code set 1.
+ */
+ kbd_write_output_w(0xF0);
+ kbd_wait_for_input();
+ kbd_write_output_w(0x01);
+ kbd_wait_for_input();
+ }
+
+
+ kbd_write_output_w(KBD_CMD_ENABLE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Enable keyboard: no ACK";
+
+ /*
+ * Finally, set the typematic rate to maximum.
+ */
+ kbd_write_output_w(KBD_CMD_SET_RATE);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Set rate: no ACK";
+ kbd_write_output_w(0x00);
+ if (kbd_wait_for_input() != KBD_REPLY_ACK)
+ return "Set rate: no ACK";
+
+ return NULL;
+}
+
+void __init pckbd_init_hw(void)
+{
+ keyboard_setup();
+
+ /* Flush any pending input. */
+ kbd_clear_input();
+
+ if (kbd_startup_reset) {
+ char *msg = initialize_kbd();
+ if (msg)
+ printk(KERN_WARNING "initialize_kbd: %s\n", msg);
+ }
+}
diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
index 4357e099f..0a6df026c 100644
--- a/drivers/char/pc_keyb.h
+++ b/drivers/char/pc_keyb.h
@@ -15,7 +15,7 @@
#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */
#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
-#define KBD_INIT_TIMEOUT HZ /* Timeout in jiffies for initializing the keyboard */
+#define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */
#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index 4bd0f0f29..ded35916c 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -515,6 +515,7 @@ static struct file_operations pcwd_fops = {
pcwd_ioctl, /* IOctl */
NULL, /* MMAP */
pcwd_open, /* Open */
+ NULL, /* flush */
pcwd_close, /* Release */
NULL, /* Fsync */
NULL, /* Fasync */
diff --git a/drivers/char/pms.c b/drivers/char/pms.c
index 81c8fbb79..1b2da0bb7 100644
--- a/drivers/char/pms.c
+++ b/drivers/char/pms.c
@@ -255,20 +255,6 @@ static void pms_brightness(short brightness)
}
}
-static void pms_hstart(short start)
-{
- switch(decoder)
- {
- case PHILIPS1:
- i2c_write(0x8A, 0x05, start);
- i2c_write(0x8A, 0x18, start);
- break;
- case PHILIPS2:
- i2c_write(0x42, 0x05, start);
- i2c_write(0x42, 0x18, start);
- break;
- }
-}
static void pms_format(short format)
{
@@ -303,6 +289,29 @@ static void pms_format(short format)
}
}
+#ifdef FOR_FUTURE_EXPANSION
+
+/*
+ * These features of the PMS card are not currently exposes. They
+ * could become a private v4l ioctl for PMSCONFIG or somesuch if
+ * people need it. We also don't yet use the PMS interrupt.
+ */
+
+static void pms_hstart(short start)
+{
+ switch(decoder)
+ {
+ case PHILIPS1:
+ i2c_write(0x8A, 0x05, start);
+ i2c_write(0x8A, 0x18, start);
+ break;
+ case PHILIPS2:
+ i2c_write(0x42, 0x05, start);
+ i2c_write(0x42, 0x18, start);
+ break;
+ }
+}
+
/*
* Bandpass filters
*/
@@ -347,14 +356,6 @@ static void pms_vertnoise(short noise)
i2c_andor(0x42, 0x10, 0xFC, noise&3);
}
-static void pms_secamcross(short cross)
-{
- if(decoder==PHILIPS2)
- i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5);
- else if(decoder==PHILIPS1)
- i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5);
-}
-
static void pms_forcecolour(short colour)
{
if(decoder==PHILIPS2)
@@ -409,20 +410,6 @@ static void pms_killcolour(short colour)
}
}
-static void pms_swsense(short sense)
-{
- if(decoder==PHILIPS2)
- {
- i2c_write(0x8A, 0x0A, sense);
- i2c_write(0x8A, 0x0B, sense);
- }
- else if(decoder==PHILIPS1)
- {
- i2c_write(0x42, 0x0A, sense);
- i2c_write(0x42, 0x0B, sense);
- }
-}
-
static void pms_chromagain(short chroma)
{
if(decoder==PHILIPS2)
@@ -446,6 +433,38 @@ static void pms_spacialcomph(short data)
mvv_write(0x3A, data);
}
+static void pms_vstart(short start)
+{
+ mvv_write(0x16, start);
+ mvv_write(0x17, (start>>8)&0x01);
+}
+
+#endif
+
+static void pms_secamcross(short cross)
+{
+ if(decoder==PHILIPS2)
+ i2c_andor(0x8A, 0x0F, 0xDF, (cross&1)<<5);
+ else if(decoder==PHILIPS1)
+ i2c_andor(0x42, 0x0F, 0xDF, (cross&1)<<5);
+}
+
+
+static void pms_swsense(short sense)
+{
+ if(decoder==PHILIPS2)
+ {
+ i2c_write(0x8A, 0x0A, sense);
+ i2c_write(0x8A, 0x0B, sense);
+ }
+ else if(decoder==PHILIPS1)
+ {
+ i2c_write(0x42, 0x0A, sense);
+ i2c_write(0x42, 0x0B, sense);
+ }
+}
+
+
static void pms_framerate(short frr)
{
int fps=(standard==1)?30:25;
@@ -586,11 +605,6 @@ static void pms_resolution(short width, short height)
mvv_write(0x33, MVVMEMORYWIDTH);
}
-static void pms_vstart(short start)
-{
- mvv_write(0x16, start);
- mvv_write(0x17, (start>>8)&0x01);
-}
/*
* Set Input
diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c
index aa022cd81..f401a0f88 100644
--- a/drivers/char/psaux.c
+++ b/drivers/char/psaux.c
@@ -107,11 +107,11 @@ static inline int queue_empty(void)
return queue->head == queue->tail;
}
-static int fasync_aux(struct file *filp, int on)
+static int fasync_aux(int fd, struct file *filp, int on)
{
int retval;
- retval = fasync_helper(filp, on, &queue->fasync);
+ retval = fasync_helper(fd, filp, on, &queue->fasync);
if (retval < 0)
return retval;
return 0;
@@ -277,9 +277,12 @@ static void aux_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
static int release_aux(struct inode * inode, struct file * file)
{
- fasync_aux(file, 0);
+ fasync_aux(-1, file, 0);
if (--aux_count)
return 0;
+#ifdef CONFIG_VT
+ pckbd_read_mask = KBD_STAT_OBF;
+#endif
aux_start_atomic();
aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
poll_aux_status();
@@ -320,6 +323,10 @@ static int open_aux(struct inode * inode, struct file * file)
poll_aux_status();
aux_end_atomic();
+#ifdef CONFIG_VT
+ pckbd_read_mask = AUX_STAT_OBF;
+#endif
+
aux_ready = 0;
return 0;
}
@@ -413,7 +420,7 @@ static int release_qp(struct inode * inode, struct file * file)
{
unsigned char status;
- fasync_aux(file, 0);
+ fasync_aux(-1, file, 0);
if (!--qp_count) {
if (!poll_qp_status())
printk("Warning: Mouse device busy in release_qp()\n");
@@ -605,6 +612,7 @@ struct file_operations psaux_fops = {
NULL, /* ioctl */
NULL, /* mmap */
open_aux,
+ NULL, /* flush */
release_aux,
NULL,
fasync_aux,
@@ -639,9 +647,6 @@ __initfunc(int psaux_init(void))
#endif
printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
aux_present = 1;
-#ifdef CONFIG_VT
- pckbd_read_mask = AUX_STAT_OBF;
-#endif
} else {
return -EIO;
}
@@ -670,6 +675,7 @@ __initfunc(int psaux_init(void))
poll_aux_status();
aux_end_atomic();
}
+
return 0;
}
diff --git a/drivers/char/radio-aimslab.c b/drivers/char/radio-aimslab.c
index 014def0c4..59d95042e 100644
--- a/drivers/char/radio-aimslab.c
+++ b/drivers/char/radio-aimslab.c
@@ -216,6 +216,7 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.maxheight=0;
v.minwidth=0;
v.minheight=0;
+ strcpy(v.name, "RadioTrack");
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -261,6 +262,7 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
memset(&v,0, sizeof(v));
v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v.volume=rt->curvol * 6554;
+ v.step=6554;
strcpy(v.name, "Radio");
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
diff --git a/drivers/char/radio-aztech.c b/drivers/char/radio-aztech.c
index aaeaa7265..39d56a86f 100644
--- a/drivers/char/radio-aztech.c
+++ b/drivers/char/radio-aztech.c
@@ -167,6 +167,7 @@ static int az_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.maxheight=0;
v.minwidth=0;
v.minheight=0;
+ strcpy(v.name, "Aztech Radio");
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -218,6 +219,7 @@ static int az_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
else
v.mode=VIDEO_SOUND_MONO;
v.volume=az->curvol;
+ v.step=16384;
strcpy(v.name, "Radio");
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
diff --git a/drivers/char/radio-miropcm20.c b/drivers/char/radio-miropcm20.c
new file mode 100644
index 000000000..126a27771
--- /dev/null
+++ b/drivers/char/radio-miropcm20.c
@@ -0,0 +1,244 @@
+/* Miro PCM20 radio driver for Linux radio support
+ * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
+ * Thanks to Norberto Pellici for the ACI device interface specification
+ * The API part is based on the radiotrack driver by M. Kirkwood
+ * This driver relies on the aci mixer (drivers/sound/lowlevel/aci.c)
+ * Look there for further info...
+ */
+
+#include <linux/module.h> /* Modules */
+#include <linux/init.h> /* Initdata */
+#include <asm/uaccess.h> /* copy to/from user */
+#include <linux/videodev.h> /* kernel radio structs */
+#include "../sound/lowlevel/miroaci.h" /* ACI Control by acimixer */
+
+static int users = 0;
+
+struct pcm20_device
+{
+ int port;
+ int curvol;
+ unsigned long curfreq;
+ int muted;
+};
+
+
+/* local things */
+
+
+static void pcm20_mute(struct pcm20_device *dev)
+{
+
+ dev->muted = 1;
+ aci_write_cmd(0xa3,0x01);
+
+}
+
+static int pcm20_setvol(struct pcm20_device *dev, int vol)
+{
+
+ if(vol == dev->curvol) { /* requested volume = current */
+ if (dev->muted) { /* user is unmuting the card */
+ dev->muted = 0;
+ aci_write_cmd(0xa3,0x00); /* enable card */
+ }
+
+ return 0;
+ }
+
+ if(vol == 0) { /* volume = 0 means mute the card */
+ aci_write_cmd(0x3d, 0x20);
+ aci_write_cmd(0x35, 0x20);
+ return 0;
+ }
+
+ dev->muted = 0;
+ aci_write_cmd(0x3d, 32-vol); /* Right Channel */
+ aci_write_cmd(0x35, 32-vol); /* Left Channel */
+ dev->curvol = vol;
+
+ return 0;
+}
+
+static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
+{
+ unsigned char freql;
+ unsigned char freqh;
+
+ freq = (freq * 10) / 16;
+ freql = freq & 0xff;
+ freqh = freq >> 8;
+
+
+ aci_write_cmd_d(0xa7, freql, freqh); /* Tune to frequency */
+
+ return 0;
+}
+
+int pcm20_getsigstr(struct pcm20_device *dev)
+{
+ unsigned char buf;
+ aci_indexed_cmd(0xf0, 0x32, &buf);
+ if ((buf & 0x80) == 0x80)
+ return 0;
+ return 1; /* signal present */
+}
+
+static int pcm20_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct pcm20_device *pcm20=dev->priv;
+
+ switch(cmd)
+ {
+ case VIDIOCGCAP:
+ {
+ struct video_capability v;
+ v.type=VID_TYPE_TUNER;
+ strcpy(v.name, "Miro PCM20");
+ v.channels=1;
+ v.audios=1;
+ /* No we don't do pictures */
+ v.maxwidth=0;
+ v.maxheight=0;
+ v.minwidth=0;
+ v.minheight=0;
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner v;
+ if(copy_from_user(&v, arg,sizeof(v))!=0)
+ return -EFAULT;
+ if(v.tuner) /* Only 1 tuner */
+ return -EINVAL;
+ v.rangelow=(int)(87.5*16);
+ v.rangehigh=(int)(108.0*16);
+ v.flags=0;
+ v.mode=VIDEO_MODE_AUTO;
+ v.signal=0xFFFF*pcm20_getsigstr(pcm20);
+ 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;
+ if(v.tuner!=0)
+ return -EINVAL;
+ /* Only 1 tuner so no setting needed ! */
+ return 0;
+ }
+ case VIDIOCGFREQ:
+ if(copy_to_user(arg, &pcm20->curfreq, sizeof(pcm20->curfreq)))
+ return -EFAULT;
+ return 0;
+ case VIDIOCSFREQ:
+ if(copy_from_user(&pcm20->curfreq, arg,sizeof(pcm20->curfreq)))
+ return -EFAULT;
+ pcm20_setfreq(pcm20, pcm20->curfreq);
+ return 0;
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio v;
+ memset(&v,0, sizeof(v));
+ v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+ v.volume=pcm20->curvol * 2048;
+ strcpy(v.name, "Radio");
+ if(copy_to_user(arg,&v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSAUDIO:
+ {
+ struct video_audio v;
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ if(v.audio)
+ return -EINVAL;
+
+ if(v.flags&VIDEO_AUDIO_MUTE)
+ pcm20_mute(pcm20);
+ else
+ pcm20_setvol(pcm20,v.volume/2048);
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int pcm20_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void pcm20_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct pcm20_device pcm20_unit;
+
+static struct video_device pcm20_radio=
+{
+ "Miro PCM 20 radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_RTRACK,
+ pcm20_open,
+ pcm20_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL, /* Can't poll */
+ pcm20_ioctl,
+ NULL,
+ NULL
+};
+
+__initfunc(int pcm20_init(struct video_init *v))
+{
+
+ pcm20_radio.priv=&pcm20_unit;
+
+ if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ printk(KERN_INFO "Miro PCM20 radio card driver.\n");
+
+ /* mute card - prevents noisy bootups */
+
+ /* this ensures that the volume is all the way down */
+
+ pcm20_unit.curvol = 0;
+
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Ruurd Reitsma");
+MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+
+ return pcm20_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ video_unregister_device(&pcm20_radio);
+}
+
+#endif
diff --git a/drivers/char/radio-rtrack2.c b/drivers/char/radio-rtrack2.c
index 7daeb4e01..175c665f7 100644
--- a/drivers/char/radio-rtrack2.c
+++ b/drivers/char/radio-rtrack2.c
@@ -113,6 +113,7 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.maxheight=0;
v.minwidth=0;
v.minheight=0;
+ strcpy(v.name, "RadioTrack II");
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -158,6 +159,7 @@ static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
memset(&v,0, sizeof(v));
v.flags|=VIDEO_AUDIO_MUTABLE;
v.volume=1;
+ v.step=65535;
strcpy(v.name, "Radio");
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
diff --git a/drivers/char/radio-sf16fmi.c b/drivers/char/radio-sf16fmi.c
index 13659fd85..192fa5236 100644
--- a/drivers/char/radio-sf16fmi.c
+++ b/drivers/char/radio-sf16fmi.c
@@ -22,14 +22,12 @@
#include <linux/videodev.h> /* kernel radio structs */
#include <linux/config.h> /* CONFIG_RADIO_SF16MI_PORT */
-#include "rsf16fmi.h"
-
struct fmi_device
{
int port;
- int curvol;
- unsigned long curfreq;
- int flags;
+ int curvol; /* 1 or 0 */
+ unsigned long curfreq; /* RSF16_PREC * freq in MHz */
+ __u32 flags;
};
#ifndef CONFIG_RADIO_SF16FMI_PORT
@@ -39,11 +37,16 @@ struct fmi_device
static int io = CONFIG_RADIO_SF16FMI_PORT;
static int users = 0;
-/* local things */
-/* freq in 1/16kHz to internal number */
-#define RSF16_ENCODE(x) ((x/16+10700)/50)
+/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
+/* It is only usefull to give freq in intervall of 800 (=0.05Mhz),
+ * other bits will be truncated, e.g 92.7400016 -> 92.7, but
+ * 92.7400017 -> 92.75
+ */
+#define RSF16_ENCODE(x) ((x)/800+214)
+#define RSF16_MINFREQ 88*16000
+#define RSF16_MAXFREQ 108*16000
-static void outbits(int bits, int data, int port)
+static void outbits(int bits, unsigned int data, int port)
{
while(bits--) {
if(data & 1) {
@@ -73,7 +76,7 @@ static void fmi_unmute(int port)
static int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
{
- int myport = dev->port;
+ int myport = dev->port;
outbits(16, RSF16_ENCODE(freq), myport);
outbits(8, 0xC0, myport);
@@ -105,6 +108,7 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCGCAP:
{
struct video_capability v;
+ strcpy(v.name, "SF16-FMx radio");
v.type=VID_TYPE_TUNER;
v.channels=1;
v.audios=1;
@@ -120,17 +124,16 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCGTUNER:
{
struct video_tuner v;
+ int mult;
+
if(copy_from_user(&v, arg,sizeof(v))!=0)
return -EFAULT;
if(v.tuner) /* Only 1 tuner */
return -EINVAL;
- if (fmi->flags & VIDEO_TUNER_LOW) {
- v.rangelow = 87500 * 16;
- v.rangehigh = 108000 * 16;
- } else {
- v.rangelow=(int)(175*8 /* 87.5 *16 */);
- v.rangehigh=(int)(108*16);
- }
+ strcpy(v.name, "FM");
+ mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+ v.rangelow = RSF16_MINFREQ/mult;
+ v.rangehigh = RSF16_MAXFREQ/mult;
v.flags=fmi->flags;
v.mode=VIDEO_MODE_AUTO;
v.signal=0xFFFF*fmi_getsigstr(fmi);
@@ -165,6 +168,8 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
if (!(fmi->flags & VIDEO_TUNER_LOW))
tmp *= 1000;
+ if ( tmp<RSF16_MINFREQ || tmp>RSF16_MAXFREQ )
+ return -EINVAL;
fmi->curfreq = tmp;
fmi_setfreq(fmi, fmi->curfreq);
return 0;
@@ -172,11 +177,15 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCGAUDIO:
{
struct video_audio v;
- memset(&v,0, sizeof(v));
- v.flags|=VIDEO_AUDIO_MUTABLE;
- v.mode=VIDEO_SOUND_MONO;
- v.volume=fmi->curvol;
+ v.audio=0;
+ v.volume=0;
+ v.bass=0;
+ v.treble=0;
+ v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
strcpy(v.name, "Radio");
+ v.mode=VIDEO_SOUND_MONO;
+ v.balance=0;
+ v.step=0; /* No volume, just (un)mute */
if(copy_to_user(arg,&v, sizeof(v)))
return -EFAULT;
return 0;
@@ -188,15 +197,23 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
if(v.audio)
return -EINVAL;
- fmi->curvol=v.volume;
- if(v.flags&VIDEO_AUDIO_MUTE)
- fmi_mute(fmi->port);
- else if(fmi->curvol)
- fmi_unmute(fmi->port);
- else
- fmi_mute(fmi->port);
+ fmi->curvol= v.flags&VIDEO_AUDIO_MUTE ? 0 : 1;
+ fmi->curvol ?
+ fmi_unmute(fmi->port) : fmi_mute(fmi->port);
return 0;
}
+ case VIDIOCGUNIT:
+ {
+ struct video_unit v;
+ v.video=VIDEO_NO_UNIT;
+ v.vbi=VIDEO_NO_UNIT;
+ v.radio=dev->minor;
+ v.audio=0; /* How do we find out this??? */
+ v.teletext=VIDEO_NO_UNIT;
+ if(copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
default:
return -ENOIOCTLCMD;
}
@@ -221,7 +238,7 @@ static struct fmi_device fmi_unit;
static struct video_device fmi_radio=
{
- "SF16FMI radio",
+ "SF16FMx radio",
VID_TYPE_TUNER,
VID_HARDWARE_SF16MI,
fmi_open,
@@ -242,15 +259,17 @@ __initfunc(int fmi_init(struct video_init *v))
return -EBUSY;
}
- fmi_unit.port=io;
+ fmi_unit.port = io;
+ fmi_unit.curvol = 0;
+ fmi_unit.curfreq = 0;
fmi_unit.flags = VIDEO_TUNER_LOW;
- fmi_radio.priv=&fmi_unit;
+ fmi_radio.priv = &fmi_unit;
if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1)
return -EINVAL;
request_region(io, 2, "fmi");
- printk(KERN_INFO "SF16FMI radio card driver.\n");
+ printk(KERN_INFO "SF16FMx radio card driver at 0x%x.\n", io);
printk(KERN_INFO "(c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz.\n");
/* mute card - prevents noisy bootups */
fmi_mute(io);
diff --git a/drivers/char/radio-zoltrix.c b/drivers/char/radio-zoltrix.c
index c820c8a36..115606ac3 100644
--- a/drivers/char/radio-zoltrix.c
+++ b/drivers/char/radio-zoltrix.c
@@ -176,6 +176,7 @@ static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.maxheight = 0;
v.minwidth = 0;
v.minheight = 0;
+ strcpy(v.name, "Zoltrix Radio");
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0;
@@ -220,7 +221,8 @@ static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_audio v;
memset(&v, 0, sizeof(v));
v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
- v.volume = rt->curvol * 4095;
+ v.volume = rt->curvol * 4096;
+ v.step = 4096;
strcpy(v.name, "Radio");
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index b7ed4e10b..5db97f906 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1526,6 +1526,7 @@ struct file_operations random_fops = {
random_ioctl,
NULL, /* random_mmap */
NULL, /* no special open code */
+ NULL, /* flush */
NULL /* no special release code */
};
@@ -1538,6 +1539,7 @@ struct file_operations urandom_fops = {
random_ioctl,
NULL, /* urandom_mmap */
NULL, /* no special open code */
+ NULL, /* flush */
NULL /* no special release code */
};
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 20e818ce6..c661f8238 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -100,8 +100,8 @@
#include "version.h"
#else
#include <linux/rocket.h>
-#define ROCKET_VERSION "1.14b"
-#define ROCKET_DATE "29-Jun-98"
+#define ROCKET_VERSION "1.14c"
+#define ROCKET_DATE "24-Aug-98"
#endif /* LOCAL_ROCKET_H */
#define ROCKET_PARANOIA_CHECK
@@ -1935,7 +1935,8 @@ static void rp_flush_buffer(struct tty_struct *tty)
#ifdef ENABLE_PCI
#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
/* For compatibility */
-static struct pci_dev *pci_find_slot(char bus, char device_fn)
+static struct pci_dev *pci_find_slot(unsigned char bus,
+ unsigned char device_fn)
{
unsigned short vendor_id, device_id;
int ret, error;
@@ -1962,7 +1963,7 @@ static struct pci_dev *pci_find_slot(char bus, char device_fn)
}
#endif
-__initfunc(int register_PCI(int i, char bus, char device_fn))
+__initfunc(int register_PCI(int i, unsigned int bus, unsigned int device_fn))
{
int num_aiops, aiop, max_num_aiops, num_chan, chan;
unsigned int aiopio[MAX_AIOPS_PER_BOARD];
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index b7c117c31..3bb5a77d0 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -507,6 +507,7 @@ static struct file_operations rtc_fops = {
rtc_ioctl,
NULL, /* No mmap */
rtc_open,
+ NULL, /* flush */
rtc_release
};
diff --git a/drivers/char/saa5249.c b/drivers/char/saa5249.c
index 252fcabbe..f3185252f 100644
--- a/drivers/char/saa5249.c
+++ b/drivers/char/saa5249.c
@@ -172,6 +172,9 @@ static int saa5249_attach(struct i2c_device *device)
kfree(vd);
return -ENOMEM;
}
+
+ memset(t, 0, sizeof(*t));
+
for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
{
memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
@@ -680,6 +683,7 @@ static struct video_device saa_template=
saa5249_release,
saa5249_read,
saa5249_write,
+ NULL, /* poll */
saa5249_ioctl,
NULL,
NULL,
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 5a94d2fee..9c5ecd8ef 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -2591,15 +2591,21 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
MOD_INC_USE_COUNT;
line = MINOR(tty->device) - tty->driver.minor_start;
- if ((line < 0) || (line >= NR_PORTS))
+ if ((line < 0) || (line >= NR_PORTS)) {
+ MOD_DEC_USE_COUNT;
return -ENODEV;
+ }
retval = get_async_struct(line, &info);
- if (retval)
+ if (retval) {
+ MOD_DEC_USE_COUNT;
return retval;
+ }
tty->driver_data = info;
info->tty = tty;
- if (serial_paranoia_check(info, tty->device, "rs_open"))
+ if (serial_paranoia_check(info, tty->device, "rs_open")) {
+ MOD_DEC_USE_COUNT;
return -ENODEV;
+ }
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
@@ -2609,8 +2615,10 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
if (!tmp_buf) {
page = get_free_page(GFP_KERNEL);
- if (!page)
+ if (!page) {
+ MOD_DEC_USE_COUNT;
return -ENOMEM;
+ }
if (tmp_buf)
free_page(page);
else
@@ -2624,6 +2632,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
(info->flags & ASYNC_CLOSING)) {
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
+ MOD_DEC_USE_COUNT;
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
@@ -2636,11 +2645,14 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
* Start up serial port
*/
retval = startup(info);
- if (retval)
+ if (retval) {
+ MOD_DEC_USE_COUNT;
return retval;
+ }
retval = block_til_ready(tty, filp, info);
if (retval) {
+ MOD_DEC_USE_COUNT;
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open returning after block_til_ready with %d\n",
retval);
diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c
index 60e1dccdf..c611b5344 100644
--- a/drivers/char/softdog.c
+++ b/drivers/char/softdog.c
@@ -168,6 +168,7 @@ static struct file_operations softdog_fops=
softdog_ioctl, /* Ioctl */
NULL, /* MMap */
softdog_open,
+ NULL, /* flush */
softdog_release,
NULL,
NULL /* Fasync */
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 7239923ec..81d389cad 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -672,6 +672,7 @@ static struct file_operations stl_fsiomem = {
stl_memioctl,
NULL,
stl_memopen,
+ NULL, /* flush */
stl_memclose,
NULL
};
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 461e58165..56e2099ba 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -2756,6 +2756,7 @@ static struct file_operations qic02_tape_fops = {
qic02_tape_ioctl, /* ioctl */
NULL, /* mmap not allowed */
qic02_tape_open, /* open */
+ NULL, /* flush */
qic02_tape_release, /* release */
NULL, /* fsync */
NULL, /* fasync */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index a26ce1311..d2ecd8183 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -128,7 +128,7 @@ static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
static int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
-static int tty_fasync(struct file * filp, int on);
+static int tty_fasync(int fd, struct file * filp, int on);
#ifdef CONFIG_8xx
extern long console_8xx_init(void);
extern int rs_8xx_init(void);
@@ -358,6 +358,7 @@ static struct file_operations tty_fops = {
tty_ioctl,
NULL, /* tty_mmap */
tty_open,
+ NULL, /* flush */
tty_release,
NULL, /* tty_fsync */
tty_fasync
@@ -372,6 +373,7 @@ static struct file_operations hung_up_tty_fops = {
hung_up_tty_ioctl,
NULL, /* hung_up_tty_mmap */
NULL, /* hung_up_tty_open */
+ NULL, /* flush */
tty_release, /* hung_up_tty_release */
NULL, /* hung_up_tty_fsync */
NULL /* hung_up_tty_fasync */
@@ -409,7 +411,7 @@ void do_tty_hangup(void *data)
continue;
if (filp->f_op != &tty_fops)
continue;
- tty_fasync(filp, 0);
+ tty_fasync(-1, filp, 0);
filp->f_op = &hung_up_tty_fops;
}
@@ -983,7 +985,7 @@ static void release_dev(struct file * filp)
check_tty_count(tty, "release_dev");
- tty_fasync(filp, 0);
+ tty_fasync(-1, filp, 0);
idx = MINOR(tty->device) - tty->driver.minor_start;
pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
@@ -1352,7 +1354,7 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait)
* to set up the fasync queue. It returns negative on error, 0 if it did
* no changes and positive if it added/deleted the entry.
*/
-int fasync_helper(struct file * filp, int on, struct fasync_struct **fapp)
+int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{
struct fasync_struct *fa, **fp;
unsigned long flags;
@@ -1363,13 +1365,16 @@ int fasync_helper(struct file * filp, int on, struct fasync_struct **fapp)
}
if (on) {
- if (fa)
+ if (fa) {
+ fa->fa_fd = fd;
return 0;
+ }
fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
if (!fa)
return -ENOMEM;
fa->magic = FASYNC_MAGIC;
fa->fa_file = filp;
+ fa->fa_fd = fd;
save_flags(flags);
cli();
fa->fa_next = *fapp;
@@ -1387,7 +1392,7 @@ int fasync_helper(struct file * filp, int on, struct fasync_struct **fapp)
return 1;
}
-static int tty_fasync(struct file * filp, int on)
+static int tty_fasync(int fd, struct file * filp, int on)
{
struct tty_struct * tty;
int retval;
@@ -1396,7 +1401,7 @@ static int tty_fasync(struct file * filp, int on)
if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync"))
return 0;
- retval = fasync_helper(filp, on, &tty->fasync);
+ retval = fasync_helper(fd, filp, on, &tty->fasync);
if (retval <= 0)
return retval;
@@ -1973,7 +1978,7 @@ int tty_unregister_driver(struct tty_driver *driver)
* Just do some early initializations, and do the complex setup
* later.
*/
-long console_init(long kmem_start, long kmem_end)
+long __init console_init(long kmem_start, long kmem_end)
{
/* Setup the default TTY line discipline. */
memset(ldiscs, 0, sizeof(ldiscs));
diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c
index 9eb3d3944..c640ff321 100644
--- a/drivers/char/tuner.c
+++ b/drivers/char/tuner.c
@@ -108,7 +108,7 @@ static void set_tv_freq(struct tuner *t, int freq)
else
config = tun->UHF;
- div=freq + (int)(16*38.9);
+ div=freq + tun->IFPCoff;
div&=0x7fff;
LOCK_I2C_BUS(t->bus);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 30de4d39b..bbdf7e4d5 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -258,6 +258,7 @@ static struct file_operations vcs_fops = {
NULL, /* ioctl */
NULL, /* mmap */
vcs_open, /* open */
+ NULL, /* flush */
NULL, /* release */
NULL /* fsync */
};
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index 868ba4eb9..2ba0bd030 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -62,6 +62,9 @@ extern int rtrack_init(struct video_init *);
#ifdef CONFIG_RADIO_SF16FMI
extern int fmi_init(struct video_init *);
#endif
+#ifdef CONFIG_RADIO_MIROPCM20
+extern int pcm20_init(struct video_init *);
+#endif
static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
@@ -88,6 +91,9 @@ static struct video_init video_init_list[]={
#endif
#ifdef CONFIG_RADIO_SF16FMI
{"SF16FMI", fmi_init},
+#endif
+#ifdef CONFIG_RADIO_MIROPCM20
+ {"PCM20", pcm20_init},
#endif
{"end", NULL}
};
@@ -315,6 +321,7 @@ static struct file_operations video_fops=
video_ioctl,
video_mmap,
video_open,
+ NULL, /* flush */
video_release
};
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index 86ce29744..a42c35fe3 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -327,6 +327,7 @@ static struct file_operations wdt_fops = {
wdt_ioctl,
NULL, /* No mmap */
wdt_open,
+ NULL, /* flush */
wdt_release
};