diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
commit | 03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch) | |
tree | 88db8dba75ae06ba3bad08e42c5e52efc162535c /drivers/char | |
parent | 257730f99381dd26e10b832fce4c94cae7ac1176 (diff) |
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'drivers/char')
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 }; |