summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-02-15 02:15:32 +0000
commit86464aed71025541805e7b1515541aee89879e33 (patch)
treee01a457a4912a8553bc65524aa3125d51f29f810 /drivers/char
parent88f99939ecc6a95a79614574cb7d95ffccfc3466 (diff)
Merge with Linux 2.2.1.
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Config.in40
-rw-r--r--drivers/char/Makefile16
-rw-r--r--drivers/char/README.epca8
-rw-r--r--drivers/char/bttv.c1295
-rw-r--r--drivers/char/bttv.h52
-rw-r--r--drivers/char/busmouse.c4
-rw-r--r--drivers/char/c-qcam.c202
-rw-r--r--drivers/char/c-qcam.h18
-rw-r--r--drivers/char/console.c29
-rw-r--r--drivers/char/consolemap.c13
-rw-r--r--drivers/char/cyclades.c89
-rw-r--r--drivers/char/epca.c9
-rw-r--r--drivers/char/ftape/RELEASE-NOTES4
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.c15
-rw-r--r--drivers/char/hfmodem/Config.in2
-rw-r--r--drivers/char/hfmodem/main.c2
-rw-r--r--drivers/char/i2c.c11
-rw-r--r--drivers/char/isicom.c1951
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/joystick/Config.in6
-rw-r--r--drivers/char/keyboard.c9
-rw-r--r--drivers/char/lp_m68k.c21
-rw-r--r--drivers/char/mac_SCC.c35
-rw-r--r--drivers/char/macmouse.c312
-rw-r--r--drivers/char/mem.c56
-rw-r--r--drivers/char/misc.c10
-rw-r--r--drivers/char/msbusmouse.c4
-rw-r--r--drivers/char/msp3400.c414
-rw-r--r--drivers/char/msp3400.h22
-rw-r--r--drivers/char/n_tty.c22
-rw-r--r--drivers/char/pc_keyb.c124
-rw-r--r--drivers/char/pcxx.c1
-rw-r--r--drivers/char/pms.c2
-rw-r--r--drivers/char/radio-aimslab.c1
-rw-r--r--drivers/char/radio-gemtek.c310
-rw-r--r--drivers/char/radio-zoltrix.c169
-rw-r--r--drivers/char/random.c12
-rw-r--r--drivers/char/riscom8.c6
-rw-r--r--drivers/char/rtc.c2
-rw-r--r--drivers/char/saa5249.c2
-rw-r--r--drivers/char/serial.c63
-rw-r--r--drivers/char/specialix.c8
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/tpqic02.c4
-rw-r--r--drivers/char/tty_io.c42
-rw-r--r--drivers/char/tty_ioctl.c4
-rw-r--r--drivers/char/tuner.c48
-rw-r--r--drivers/char/videodev.c70
-rw-r--r--drivers/char/vt.c1
49 files changed, 4284 insertions, 1260 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index a81a95013..6967c30e2 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -35,10 +35,13 @@ if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
fi
tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
tristate 'Specialix IO8+ card support' CONFIG_SPECIALIX
- if [ "$CONFIG_SPECIALIX" = "y" -o "$CONFIG_SPECIALIX" = "m" ]; then
+ if [ "$CONFIG_SPECIALIX" != "n" ]; then
bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
fi
tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate 'Multi-Tech multiport card support' CONFIG_ISI m
+ fi
fi
bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
@@ -53,12 +56,19 @@ fi
bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
if [ "$CONFIG_MOUSE" = "y" ]; then
+ mainmenu_option next_comment
+ comment 'Mice'
tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
tristate 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD
+ endmenu
+fi
+
+if [ "$CONFIG_SGI" = "y" ]; then
+ bool 'Support for SGI graphic devices' CONFIG_SGI_GRAPHICS
fi
tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
@@ -69,12 +79,14 @@ if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
else
comment ' Setting runtime QIC-02 configuration is done with qic02conf'
comment ' from the tpqic02-support package. It is available at'
- comment ' sunsite.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
+ comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
fi
fi
bool 'Watchdog Timer Support' CONFIG_WATCHDOG
if [ "$CONFIG_WATCHDOG" != "n" ]; then
+ mainmenu_option next_comment
+ comment 'Watchdog Cards'
bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
tristate ' WDT Watchdog timer' CONFIG_WDT
if [ "$CONFIG_WDT" != "n" ]; then
@@ -86,12 +98,19 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+ endmenu
fi
+
+
+tristate '/dev/nvram support' CONFIG_NVRAM
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
bool 'Tadpole ANA H8 Support' CONFIG_H8
fi
+mainmenu_option next_comment
+comment 'Video For Linux'
+
tristate 'Video For Linux' CONFIG_VIDEO_DEV
if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
dep_tristate 'AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
@@ -107,7 +126,13 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; 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
+ dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
+ hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+ fi
+ if [ "$CONFIG_PCI" != "n" ]; then
+ dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
+ fi
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV
dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV
@@ -128,11 +153,18 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
fi
fi
-tristate '/dev/nvram support' CONFIG_NVRAM
+
+endmenu
+
+mainmenu_option next_comment
+comment 'Joystick support'
+
tristate 'Joystick support' CONFIG_JOYSTICK
if [ "$CONFIG_JOYSTICK" != "n" ]; then
source drivers/char/joystick/Config.in
fi
+endmenu
+
mainmenu_option next_comment
comment 'Ftape, the floppy tape device driver'
tristate 'Ftape (QIC-80/Travan) support' CONFIG_FTAPE
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index af9983701..7544ffb4a 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -122,6 +122,14 @@ else
endif
endif
+ifeq ($(CONFIG_ISI),y)
+L_OBJS += isicom.o
+else
+ ifeq ($(CONFIG_ISI),m)
+ M_OBJS += isicom.o
+ endif
+endif
+
ifeq ($(CONFIG_ESPSERIAL),y)
L_OBJS += esp.o
else
@@ -384,6 +392,14 @@ else
endif
endif
+ifeq ($(CONFIG_RADIO_GEMTEK),y)
+L_OBJS += radio-gemtek.o
+else
+ ifeq ($(CONFIG_RADIO_GEMTEK),m)
+ M_OBJS += radio-gemtek.o
+ endif
+endif
+
ifeq ($(CONFIG_QIC02_TAPE),y)
L_OBJS += tpqic02.o
else
diff --git a/drivers/char/README.epca b/drivers/char/README.epca
index 0efccae58..ac91d56dd 100644
--- a/drivers/char/README.epca
+++ b/drivers/char/README.epca
@@ -155,7 +155,7 @@ The four user programs listed below are described in this document:
current digiConfig application does not provide this function for PCI cards
(Though it does build device nodes for non-PCI cards). To use this program
execute the following:first install the driver, and execute digiDload (See above). After digiDload
- has sucessfully loaded, execute the following:
+ has successfully loaded, execute the following:
buildPCI <arg1> <arg2>
@@ -295,7 +295,7 @@ Description (Verbose) : Made the following modifications:
Linux kernels support higher baud rates by using
0x1000 bit. When the returned value (ored with
0x1000) was used to reference our fbaud table a
- serious memory problem occured. This has been fixed.
+ serious memory problem occurred. This has been fixed.
4. Added a request_region call to post_fep_init. This
should cause the i/o ports being used to be
@@ -401,8 +401,8 @@ Description (Verbose) : Made the following modifications:
found in epcaconfig.h; if so it DOESN'T load
epcaconfig data depending on epca_setup to handle
board configuration. pc_open has been modified
- such that it checks to insure that no errors
- occured during the LILO boot process. If a
+ such that it checks to ensure that no errors
+ occurred during the LILO boot process. If a
user attempts to boot the driver (via. LILO)
with incorrect data, the open will fail.
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index de2d25b0e..90c117467 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -17,66 +17,87 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Modified to put the RISC code writer in the kernel and to fit a
- common (and I hope safe) kernel interface. When we have an X extension
- all will now be really sweet.
-
- TODO:
-
- * move norm from tuner to channel struct!?
- composite source from a satellite tuner can deliver different norms
- depending on tuned channel
- * mmap VBI data?
- * fix RAW Composite grabbing for NTSC
- * fix VBI reading double frames when grabbing is active
- * allow for different VDELAYs
- * extra modules for tda9850, tda8425, any volunteers???
*/
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/malloc.h>
-#include <linux/vmalloc.h>
#include <linux/mm.h>
+#if LINUX_VERSION_CODE >= 0x020100
+#include <linux/poll.h>
+#endif
#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
+#include <linux/ioport.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
#include <asm/segment.h>
#include <linux/types.h>
#include <linux/wrapper.h>
-
-#include <linux/videodev.h>
+#include <linux/interrupt.h>
#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x020100
#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#else
+#include <linux/bios32.h>
+#define mdelay(x) udelay((x)*1000)
+#define signal_pending(current) (current->signal & ~current->blocked)
+#define sigfillset(set)
+
+static inline int time_before(unsigned long a, unsigned long b)
+{
+ return((long)((a) - (b)) < 0L);
+}
+static inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+ memcpy_tofs(to,from,n);
+ return 0;
+}
+
+static inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+ memcpy_fromfs(to,from,n);
+ return 0;
+}
+#define ioremap vremap
+#define iounmap vfree
+#endif
+
+#include <linux/videodev.h>
#include <linux/i2c.h>
#include "bttv.h"
#include "tuner.h"
-#define DEBUG(x) /* Debug driver */
+#define DEBUG(x) /* Debug driver */
#define IDEBUG(x) /* Debug interrupt handler */
+#if LINUX_VERSION_CODE >= 0x020117
MODULE_PARM(vidmem,"i");
MODULE_PARM(triton1,"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);
+#endif
/* Anybody who uses more than four? */
#define BTTV_MAX 4
+static int find_vga(void);
+static void bt848_set_risc_jmps(struct bttv *btv);
+
static unsigned int vidmem=0; /* manually set video mem address */
static int triton1=0;
#ifndef USE_PLL
@@ -103,9 +124,11 @@ static struct bttv bttvs[BTTV_MAX];
{ btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
#define I2C_GET() (btread(BT848_I2C)&1)
-#define EEPROM_WRITE_DELAY 20000
+#define EEPROM_WRITE_DELAY 20000
#define BURSTOFFSET 76
+
+
/*******************************/
/* Memory management functions */
/*******************************/
@@ -190,6 +213,8 @@ static void rvfree(void * mem, unsigned long size)
}
}
+
+
/*
* Create the giant waste of buffer space we need for now
* until we get DMA to user space sorted out (probably 2.3.x)
@@ -387,7 +412,9 @@ static struct i2c_bus bttv_i2c_bus_template =
I2C_BUSID_BT848,
NULL,
+#if LINUX_VERSION_CODE >= 0x020100
SPIN_LOCK_UNLOCKED,
+#endif
attach_inform,
detach_inform,
@@ -399,6 +426,70 @@ static struct i2c_bus bttv_i2c_bus_template =
};
/* ----------------------------------------------------------------------- */
+/* some hauppauge specific stuff */
+
+static unsigned char eeprom_data[256];
+static struct HAUPPAUGE_TUNER
+{
+ int id;
+ char *name;
+}
+hauppauge_tuner[] =
+{
+ { TUNER_ABSENT, "" },
+ { TUNER_ABSENT, "External" },
+ { TUNER_ABSENT, "Unspecified" },
+ { TUNER_ABSENT, "Philips FI1216" },
+ { TUNER_ABSENT, "Philips FI1216MF" },
+ { TUNER_PHILIPS_NTSC, "Philips FI1236" },
+ { TUNER_ABSENT, "Philips FI1246" },
+ { TUNER_ABSENT, "Philips FI1256" },
+ { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" },
+ { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
+ { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" },
+ { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
+ { TUNER_ABSENT, "Philips FI1256 MK2" },
+ { TUNER_ABSENT, "Temic 4032FY5" },
+ { TUNER_TEMIC_PAL, "Temic 4002FH5" },
+ { TUNER_TEMIC_PAL_I, "Temic 4062FY5" },
+ { TUNER_ABSENT, "Philips FR1216 MK2" },
+ { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
+ { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" },
+ { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
+ { TUNER_ABSENT, "Philips FR1256 MK2" },
+ { TUNER_PHILIPS_PAL, "Philips FM1216" },
+ { TUNER_ABSENT, "Philips FM1216MF" },
+ { TUNER_PHILIPS_NTSC, "Philips FM1236" },
+};
+
+static void
+hauppauge_eeprom(struct i2c_bus *bus)
+{
+ struct bttv *btv = (struct bttv*)bus->data;
+
+ readee(bus, eeprom_data);
+ if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER))
+ {
+ btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;
+ printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
+ hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
+ }
+}
+
+static void
+hauppauge_msp_reset(struct bttv *btv)
+{
+ /* 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); */
+}
+
+/* ----------------------------------------------------------------------- */
struct tvcard
@@ -436,25 +527,19 @@ static struct tvcard tvcards[] =
{0, 0xc00, 0x800, 0x400, 0xc00, 0}},
/* TurboTV */
{ 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}},
- /* Newer Hauppauge (bt878) */
+ /* Newer Hauppauge (bt878) */
{ 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4}},
- /* MIRO PCTV pro */
- { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}},
+ /* MIRO PCTV pro */
+ { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}},
/* ADS Technologies Channel Surfer TV (and maybe TV+FM) */
- {
- 3, 4, 0, 2, 0x0F,
- { 0x02, 0x03, 0x01, 0x01},
- { 0x0D, 0x0E, 0x0B, 0x07, 0x00, 0x00},
- 0x00
- },
+ { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0},
+ /* AVerMedia TVCapture 98 */
+ { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0},
+ /* Aimslab VHX */
+ { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
};
#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
-
-/*
- * Tuner, Radio, internal, external and mute
- */
-
static void audio(struct bttv *btv, int mode)
{
btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask,
@@ -542,16 +627,16 @@ static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout)
fout*=12;
fi=fout/fin;
- fout=(fout-fin*fi)*256;
+ fout=(fout%fin)*256;
fh=fout/fin;
- fout=(fout-fin*fh)*256;
+ fout=(fout%fin)*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);
+ 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)
@@ -593,7 +678,7 @@ static int set_pll(struct bttv *btv)
}
while(time_before(jiffies,tv));
- for (i=0; i<100; i++)
+ for (i=0; i<10; i++)
{
if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
btwrite(0,BT848_DSTATUS);
@@ -614,13 +699,14 @@ static int set_pll(struct bttv *btv)
static void bt848_muxsel(struct bttv *btv, unsigned int input)
{
btaor(tvcards[btv->type].gpiomask2,~tvcards[btv->type].gpiomask2,
- BT848_GPIO_OUT_EN);
+ BT848_GPIO_OUT_EN);
/* This seems to get rid of some synchronization problems */
btand(~(3<<5), BT848_IFORM);
mdelay(10);
-
- input %= tvcards[btv->type].video_inputs;
+
+
+ input %= tvcards[btv->type].video_inputs;
if (input==tvcards[btv->type].svhs)
{
btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
@@ -638,13 +724,83 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input)
~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);
}
+/*
+ * Set the registers for the size we have specified. Don't bother
+ * trying to understand this without the BT848 manual in front of
+ * you [AC].
+ *
+ * PS: The manual is free for download in .pdf format from
+ * www.brooktree.com - nicely done those folks.
+ */
+
+struct tvnorm
+{
+ u32 Fsc;
+ u16 swidth, sheight; /* scaled standard width, height */
+ u16 totalwidth;
+ u8 adelay, bdelay, iform;
+ u32 scaledtwidth;
+ u16 hdelayx1, hactivex1;
+ u16 vdelay;
+ u8 vbipack;
+};
-#define VBIBUF_SIZE 65536
-
-/* Maximum sample number per VBI line is 2044, NTSC delivers 1600
- Note that we write 2048-aligned to keep alignment to memory pages
- VBI_RISC is written so that it applies to either 2044 or 1600
+static struct tvnorm tvnorms[] = {
+ /* PAL-BDGHI */
+ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */
+ /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
+#ifdef VIDEODAT
+ { 35468950,
+ 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 1135, 186, 924, 0x20, 255},
+#else
+ { 35468950,
+ 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 1135, 186, 924, 0x20, 255},
+#endif
+/*
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20, 255},
*/
+ /* NTSC */
+ { 28636363,
+ 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+ 910, 128, 910, 0x1a, 144},
+/*
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+ 780, 122, 754, 0x1a, 144},
+*/
+#if 0
+ /* SECAM EAST */
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20, 255},
+#else
+ /* SECAM L */
+ { 35468950,
+ 924, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+ 1135, 186, 922, 0x20, 255},
+#endif
+ /* PAL-NC */
+ { 28636363,
+ 640, 576, 910, 0x68, 0x5d, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+ 780, 130, 734, 0x1a, 144},
+ /* PAL-M */
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+ 780, 135, 754, 0x1a, 144},
+ /* PAL-N */
+ { 35468950,
+ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20, 144},
+ /* NTSC-Japan */
+ { 28636363,
+ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16, 144},
+};
+#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
#define VBI_SPL 2044
/* RISC command to write one VBI data line */
@@ -660,7 +816,7 @@ static void make_vbitab(struct bttv *btv)
DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even));
DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
-
+
*(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0;
for (i=0; i<16; i++)
{
@@ -696,12 +852,14 @@ int palette2fmt[] = {
BT848_COLOR_FMT_RGB15,
BT848_COLOR_FMT_YUY2,
BT848_COLOR_FMT_BtYUV,
- 0,
- 0,
- 0,
+ -1,
+ -1,
+ -1,
BT848_COLOR_FMT_RAW,
BT848_COLOR_FMT_YCrCb422,
BT848_COLOR_FMT_YCrCb411,
+ BT848_COLOR_FMT_YCrCb422,
+ BT848_COLOR_FMT_YCrCb411,
};
#define PALETTEFMT_MAX (sizeof(palette2fmt)/sizeof(int))
@@ -737,11 +895,120 @@ static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
}
-static int make_vrisctab(struct bttv *btv, unsigned int *ro,
+static int make_prisctab(struct bttv *btv, unsigned int *ro,
unsigned int *re,
unsigned int *vbuf, unsigned short width,
unsigned short height, unsigned short fmt)
{
+ unsigned long line, lmask;
+ unsigned long bl, blcr, blcb, rcmd;
+ unsigned long todo;
+ unsigned int **rp;
+ int inter;
+ unsigned long cbadr, cradr;
+ unsigned long vadr=(unsigned long) vbuf;
+ int shift, csize;
+
+
+ switch(fmt)
+ {
+ case VIDEO_PALETTE_YUV422P:
+ csize=(width*height)>>1;
+ shift=1;
+ lmask=0;
+ break;
+
+ case VIDEO_PALETTE_YUV411P:
+ csize=(width*height)>>2;
+ shift=2;
+ lmask=0;
+ break;
+
+ case VIDEO_PALETTE_YUV420P:
+ csize=(width*height)>>2;
+ shift=1;
+ lmask=1;
+ break;
+
+ case VIDEO_PALETTE_YUV410P:
+ csize=(width*height)>>4;
+ shift=2;
+ lmask=3;
+ break;
+
+ default:
+ return -1;
+ }
+ cbadr=vadr+(width*height);
+ cradr=cbadr+csize;
+ inter = (height>btv->win.cropheight/2) ? 1 : 0;
+
+ *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(ro++)=0;
+ *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3; *(re++)=0;
+
+ for (line=0; line < (height<<(1^inter)); line++)
+ {
+ if(line==height)
+ {
+ vadr+=csize<<1;
+ cbadr=vadr+(width*height);
+ cradr=cbadr+csize;
+ }
+ if (inter)
+ rp= (line&1) ? &re : &ro;
+ else
+ rp= (line>=height) ? &re : &ro;
+
+
+ if(line&lmask)
+ rcmd=BT848_RISC_WRITE1S23|BT848_RISC_SOL;
+ else
+ rcmd=BT848_RISC_WRITE123|BT848_RISC_SOL;
+
+ todo=width;
+ while(todo)
+ {
+ bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
+ blcr=(PAGE_SIZE-((PAGE_SIZE-1)&cradr))<<shift;
+ blcb=(PAGE_SIZE-((PAGE_SIZE-1)&cbadr))<<shift;
+ bl=(blcr<bl) ? blcr : bl;
+ bl=(blcb<bl) ? blcb : bl;
+ bl=(bl>todo) ? todo : bl;
+ blcr=bl>>shift;
+ blcb=blcr;
+ /* bl now containts the longest row that can be written */
+ todo-=bl;
+ if(!todo) rcmd|=BT848_RISC_EOL; /* if this is the last EOL */
+
+ *((*rp)++)=rcmd|bl;
+ *((*rp)++)=blcb|(blcr<<16);
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=bl;
+ if((rcmd&(15<<28))==BT848_RISC_WRITE123)
+ {
+ *((*rp)++)=kvirt_to_bus(cbadr);
+ cbadr+=blcb;
+ *((*rp)++)=kvirt_to_bus(cradr);
+ cradr+=blcr;
+ }
+
+ rcmd&=~BT848_RISC_SOL; /* only the first has SOL */
+ }
+ }
+
+ *(ro++)=BT848_RISC_JUMP;
+ *(ro++)=btv->bus_vbi_even;
+ *(re++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16);
+ *(re++)=btv->bus_vbi_odd;
+
+ return 0;
+}
+
+static int make_vrisctab(struct bttv *btv, unsigned int *ro,
+ unsigned int *re,
+ unsigned int *vbuf, unsigned short width,
+ unsigned short height, unsigned short palette)
+{
unsigned long line;
unsigned long bpl; /* bytes per line */
unsigned long bl;
@@ -750,11 +1017,14 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
int inter;
unsigned long vadr=(unsigned long) vbuf;
- if (btv->gfmt==BT848_COLOR_FMT_RAW)
+ if (palette==VIDEO_PALETTE_RAW)
return make_rawrisctab(btv, ro, re, vbuf);
+ if (palette>=VIDEO_PALETTE_PLANAR)
+ return make_prisctab(btv, ro, re, vbuf, width, height, palette);
+
inter = (height>btv->win.cropheight/2) ? 1 : 0;
- bpl=width*fmtbppx2[fmt&0xf]/2;
+ bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2;
*(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
*(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
@@ -764,7 +1034,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
if (inter)
rp= (line&1) ? &re : &ro;
else
- rp= (line>height) ? &re : &ro;
+ rp= (line>=height) ? &re : &ro;
bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
if (bpl<=bl)
@@ -802,16 +1072,62 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
return 0;
}
+static unsigned char lmaskt[8] =
+{ 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
+static unsigned char rmaskt[8] =
+{ 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
+
static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h)
{
- int i, j;
+ unsigned char lmask, rmask, *p;
+ int W, l, r;
+ int i;
/* bitmap is fixed width, 128 bytes (1024 pixels represented) */
- if (x < 0 || y < 0 || w < 0 || h < 0) /* catch bad clips */
+ if (x<0)
+ {
+ w+=x;
+ x=0;
+ }
+ if (y<0)
+ {
+ h+=y;
+ y=0;
+ }
+ if (w < 0 || h < 0) /* catch bad clips */
return;
/* out of range data should just fall through */
- for (i = y; i < y + h && i < 625; i++)
- for (j = x; j < x + w && j < 1024; j++)
- clipmap[(i<<7)+(j>>3)] |= (1<<(j&7));
+ if (y+h>=625)
+ h=625-y;
+ if (x+w>=1024)
+ w=1024-x;
+
+ l=x>>3;
+ r=(x+w)>>3;
+ W=r-l-1;
+ lmask=lmaskt[x&7];
+ rmask=rmaskt[(x+w)&7];
+ p=clipmap+128*y+l;
+
+ if (W>0)
+ {
+ for (i=0; i<h; i++, p+=128)
+ {
+ *p|=lmask;
+ memset(p+1, 0xff, W);
+ p[W+1]|=rmask;
+ }
+ } else if (!W) {
+ for (i=0; i<h; i++, p+=128)
+ {
+ p[0]|=lmask;
+ p[1]|=rmask;
+ }
+ } else {
+ for (i=0; i<h; i++, p+=128)
+ p[0]|=lmask&rmask;
+ }
+
+
}
static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
@@ -903,73 +1219,6 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
*(re++)=btv->bus_vbi_odd;
}
-
-/*
- * Set the registers for the size we have specified. Don't bother
- * trying to understand this without the BT848 manual in front of
- * you [AC].
- *
- * PS: The manual is free for download in .pdf format from
- * www.brooktree.com - nicely done those folks.
- */
-
-struct tvnorm
-{
- u32 Fsc;
- u16 swidth, sheight; /* scaled standard width, height */
- u16 totalwidth;
- u8 adelay, bdelay, iform;
- u32 scaledtwidth;
- u16 hdelayx1, hactivex1;
- u16 vdelay;
- u8 vbipack;
-};
-
-static struct tvnorm tvnorms[] = {
- /* PAL-BDGHI */
- /* max pal/secam is actually 922, but 924 is divisible by 4 and 3! */
- /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */
- { 35468950,
- 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- 1135, 178, 924, 0x20, 255},
-/*
- { 35468950,
- 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
- 944, 178, 922, 0x20, 255},
-*/
- /* NTSC */
- { 28636363,
- 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
- 910, 128, 754, 0x1a, 144},
-/*
- { 28636363,
- 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
- 780, 122, 754, 0x1a, 144},
-*/
- /* SECAM - phase means nothing in SECAM, bdelay is useless */
- { 35468950,
- 924, 576,1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
- 1135, 178, 924, 0x20, 255},
- /* PAL-M */
- { 28636363,
- 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
- 780, 122, 754, 0x1a, 144},
- /* PAL-N */
- { 35468950,
- 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
- 944, 178, 922, 0x20, 255},
- /* PAL-NC */
- { 35468950,
- 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
- 944, 178, 922, 0x20, 255},
- /* NTSC-Japan */
- { 28636363,
- 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
- 780, 122, 754, 0x1a, 144},
-};
-#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
-
-
/* set geometry for even/odd frames
just if you are wondering:
handling of even and odd frames will be separated, e.g. for grabbing
@@ -1030,10 +1279,11 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
btwrite(tvn->adelay, BT848_ADELAY);
btwrite(tvn->bdelay, BT848_BDELAY);
btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
- btwrite(1, BT848_VBI_PACK_DEL);
btwrite(tvn->vbipack, BT848_VBI_PACK_SIZE);
-
- set_pll(btv);
+ btwrite(1, BT848_VBI_PACK_DEL);
+
+ btv->pll.pll_ofreq = tvn->Fsc;
+ set_pll(btv);
btwrite(fmt, BT848_COLOR_FMT);
hactive=width;
@@ -1064,7 +1314,6 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
hdelay, vdelay, crop);
bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
hdelay, vdelay, crop);
-
}
@@ -1104,35 +1353,34 @@ static void set_freq(struct bttv *btv, unsigned short freq)
{
int fixme = freq; /* XXX */
- if (btv->radio)
- {
- if (btv->have_tuner)
+ /* mute */
+ if (btv->have_msp3400)
+ i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+ MSP_SWITCH_MUTE,0);
+
+ /* switch channel */
+ if (btv->have_tuner) {
+ if (btv->radio) {
i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
TUNER_SET_RADIOFREQ,&fixme);
-
- if (btv->have_msp3400) {
- i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
- MSP_SET_RADIO,0);
- i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
- MSP_NEWCHANNEL,0);
- }
- }
- else
- {
- if (btv->have_tuner)
+ } else {
i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
TUNER_SET_TVFREQ,&fixme);
+ }
+ }
- if (btv->have_msp3400) {
+ if (btv->have_msp3400) {
+ if (btv->radio) {
+ i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
+ MSP_SET_RADIO,0);
+ } else {
i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
MSP_SET_TVNORM,&(btv->win.norm));
i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400,
MSP_NEWCHANNEL,0);
- }
- }
-
+ }
+ }
}
-
/*
* Grab into virtual memory.
@@ -1171,12 +1419,12 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
*/
if (mp->format >= PALETTEFMT_MAX)
return -EINVAL;
- if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2
- > BTTV_MAX_FBUF)
+ if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2
+ > BTTV_MAX_FBUF)
return -EINVAL;
- if (!palette2fmt[mp->format])
+ if(-1 == palette2fmt[mp->format])
return -EINVAL;
-
+
/*
* FIXME: Check the format of the grab here. This is probably
* also less restrictive than the normal overlay grabs. Stuff
@@ -1192,7 +1440,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
return -EAGAIN;*/
ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
re=ro+2048;
- make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, palette2fmt[mp->format]);
+ make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format);
/* bt848_set_risc_jmps(btv); */
btv->frame_stat[mp->frame] = GBUFFER_GRABBING;
if (btv->grabbing) {
@@ -1210,8 +1458,13 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
btv->gre=virt_to_bus(re);
btv->grf=mp->frame;
}
- if (!(btv->grabbing++))
+ if (!(btv->grabbing++)) {
+ if(mp->format>=VIDEO_PALETTE_COMPONENT) {
+ btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
+ btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
+ }
btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
+ }
btor(3, BT848_CAP_CTL);
btor(3, BT848_GPIO_DMA_CTL);
/* interruptible_sleep_on(&btv->capq); */
@@ -1227,7 +1480,7 @@ static long bttv_read(struct video_device *v, char *buf, unsigned long count, in
{
struct bttv *btv= (struct bttv *)v;
int q,todo;
-
+ /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */
todo=count;
while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
{
@@ -1275,36 +1528,27 @@ static int bttv_open(struct video_device *dev, int flags)
struct bttv *btv = (struct bttv *)dev;
int users, i;
- switch (flags)
- {
- case 0:
- if (btv->user)
- return -EBUSY;
- btv->user++;
- audio(btv, AUDIO_UNMUTE);
- for (i=users=0; i<bttv_num; i++)
- users+=bttvs[i].user;
- if (users==1)
- find_vga();
- btv->fbuffer=NULL;
- if (!btv->fbuffer)
- btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
- if (!btv->fbuffer)
- {
- btv->user--;
- return -EINVAL;
- }
- 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;
- }
- MOD_INC_USE_COUNT;
- return 0;
+ if (btv->user)
+ return -EBUSY;
+ audio(btv, AUDIO_UNMUTE);
+ for (i=users=0; i<bttv_num; i++)
+ users+=bttvs[i].user;
+ if (users==1)
+ find_vga();
+ btv->fbuffer=NULL;
+ if (!btv->fbuffer)
+ btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
+ if (!btv->fbuffer)
+ return -EINVAL;
+ btv->grabbing = 0;
+ btv->grab = 0;
+ btv->lastgrab = 0;
+ for (i = 0; i < MAX_GBUFFERS; i++)
+ btv->frame_stat[i] = GBUFFER_UNUSED;
+
+ btv->user++;
+ MOD_INC_USE_COUNT;
+ return 0;
}
static void bttv_close(struct video_device *dev)
@@ -1393,8 +1637,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
VID_TYPE_SCALES;
b.channels = tvcards[btv->type].video_inputs;
b.audios = tvcards[btv->type].audio_inputs;
- b.maxwidth = 768;
- b.maxheight = 576;
+ b.maxwidth = tvnorms[btv->win.norm].swidth;
+ b.maxheight = tvnorms[btv->win.norm].sheight;
b.minwidth = 32;
b.minheight = 32;
if(copy_to_user(arg,&b,sizeof(b)))
@@ -1420,7 +1664,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.tuners=1;
}
else if(v.channel==tvcards[btv->type].svhs)
- strcpy(v.name,"SVHS");
+ strcpy(v.name,"S-Video");
else
sprintf(v.name,"Composite%d",v.channel);
@@ -1437,14 +1681,14 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- if (v.channel>=tvcards[btv->type].video_inputs)
+ if (v.channel>tvcards[btv->type].video_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;
- make_vbitab(btv);
+ make_vbitab(btv);
bt848_set_winsize(btv);
btv->channel=v.channel;
return 0;
@@ -1460,6 +1704,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.rangelow=0;
v.rangehigh=0xFFFFFFFF;
v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
+ if (btv->audio_chip == TDA9840) {
+ v.flags |= VIDEO_AUDIO_VOLUME;
+ v.mode = VIDEO_SOUND_MONO|VIDEO_SOUND_STEREO;
+ v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2;
+ }
+ if (btv->audio_chip == TDA9850) {
+ unsigned char ALR1;
+ ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1);
+ if (ALR1 & 32)
+ v.flags |= VIDEO_TUNER_STEREO_ON;
+ }
v.mode = btv->win.norm;
v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
if(copy_to_user(arg,&v,sizeof(v)))
@@ -1472,7 +1727,6 @@ 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)))
return -EFAULT;
-
/* Only one channel has a tuner */
if(v.tuner!=tvcards[btv->type].tuner)
return -EINVAL;
@@ -1536,13 +1790,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
- if(vw.flags || vw.width < 16 || vw.height < 16) {
- bt848_cap(btv,0);
+ if(vw.flags || vw.width < 16 || vw.height < 16)
+ {
+ bt848_cap(btv,0);
return -EINVAL;
- }
- if (btv->win.bpp < 4) { /* adjust and align writes */
+ }
+ if (btv->win.bpp < 4)
+ { /* 32-bit align start and adjust width */
+ int i = vw.x;
vw.x = (vw.x + 3) & ~3;
- vw.width = (vw.width - 3) & ~3;
+ i = vw.x - i;
+ vw.width -= i;
}
btv->win.x=vw.x;
btv->win.y=vw.y;
@@ -1584,7 +1842,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
make_clip_tab(btv, vcp, vw.clipcount);
if (vw.clipcount != 0)
vfree(vcp);
- if(on && btv->win.vidadr != 0)
+ if(on && btv->win.vidadr!=0)
bt848_cap(btv,1);
return 0;
}
@@ -1638,7 +1896,11 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCSFBUF:
{
struct video_buffer v;
+#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN))
+#else
+ if(!suser())
+#endif
return -EPERM;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
@@ -1646,7 +1908,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.depth!=24 && v.depth!=32 && v.width > 16 &&
v.height > 16 && v.bytesperline > 16)
return -EINVAL;
- btv->win.vidadr=(unsigned long)v.base;
+ if (v.base)
+ {
+ if ((unsigned long)v.base&1)
+ btv->win.vidadr=(unsigned long)(PAGE_OFFSET|uvirt_to_bus((unsigned long)v.base));
+ else
+ btv->win.vidadr=(unsigned long)v.base;
+ }
btv->win.sheight=v.height;
btv->win.swidth=v.width;
btv->win.bpp=((v.depth+7)&0x38)/8;
@@ -1687,6 +1955,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);
v.flags|=VIDEO_AUDIO_MUTABLE;
strcpy(v.name,"TV");
+ if (btv->audio_chip == TDA9850) {
+ unsigned char ALR1;
+ ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1);
+ v.mode = VIDEO_SOUND_MONO;
+ v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0;
+ v.mode |= (ALR1 & 64) ? VIDEO_SOUND_LANG1:0;
+ }
if (btv->have_msp3400)
{
v.flags|=VIDEO_AUDIO_VOLUME |
@@ -1719,13 +1994,21 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
audio(btv, AUDIO_MUTE);
/* One audio source per tuner */
/* if(v.audio!=0) */
- /* Nope... I have three on my ADSTech TV card. The*/
- /* ADSTech TV+FM prolly has 4 <rriggs@tesser.com> */
- if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs)
+ /* ADSTech TV card has more than one */
+ if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs)
return -EINVAL;
bt848_muxsel(btv,v.audio);
if(!(v.flags&VIDEO_AUDIO_MUTE))
audio(btv, AUDIO_UNMUTE);
+ if (btv->audio_chip == TDA9850) {
+ unsigned char con3 = 0;
+ if (v.mode & VIDEO_SOUND_LANG1)
+ con3 = 0x80; /* sap */
+ if (v.mode & VIDEO_SOUND_STEREO)
+ con3 = 0x40; /* stereo */
+ I2CWrite(&(btv->i2c), I2C_TDA9850,
+ TDA9850_CON3, con3, 1);
+ }
if (btv->have_msp3400)
{
i2c_control_device(&(btv->i2c),
@@ -1748,13 +2031,18 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCSYNC:
if(copy_from_user((void *)&i,arg,sizeof(int)))
return -EFAULT;
- if (i>1 || i<0)
- return -EINVAL;
+/* 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);
+ while(btv->frame_stat[i]==GBUFFER_GRABBING) {
+ interruptible_sleep_on(&btv->capq);
+ if(signal_pending(current))
+ return -EINTR;
+ }
/* fall */
case GBUFFER_DONE:
btv->frame_stat[i] = GBUFFER_UNUSED;
@@ -1763,7 +2051,11 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
case BTTV_WRITEE:
+#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN))
+#else
+ if(!suser())
+#endif
return -EPERM;
if(copy_from_user((void *) eedata, (void *) arg, 256))
return -EFAULT;
@@ -1771,32 +2063,39 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
case BTTV_READEE:
+#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN))
+#else
+ if(!suser())
+#endif
return -EPERM;
readee(&(btv->i2c), eedata);
if(copy_to_user((void *) arg, (void *) eedata, 256))
return -EFAULT;
break;
- case BTTV_FIELDNR:
+ 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;
+
+ case BTTV_PLLSET: {
+ struct bttv_pll_info p;
+#if LINUX_VERSION_CODE >= 0x020100
if(!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if(copy_from_user(&p , (void *) arg, sizeof(btv->pll)))
+#else
+ if(!suser())
+#endif
+ 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;
- }
+ 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;
@@ -1840,7 +2139,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
return 0;
}
-
+
case BTTV_BURST_ON:
{
tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2;
@@ -1855,9 +2154,14 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
}
+ case BTTV_VERSION:
+ {
+ return BTTV_VERSION_CODE;
+ }
+
case BTTV_PICNR:
{
- /* return picture */
+ /* return picture;*/
return 0;
}
@@ -1916,7 +2220,9 @@ static struct video_device bttv_template=
bttv_close,
bttv_read,
bttv_write,
+#if LINUX_VERSION_CODE >= 0x020100
NULL, /* poll */
+#endif
bttv_ioctl,
bttv_mmap,
bttv_init_done,
@@ -1970,6 +2276,7 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count,
return count;
}
+#if LINUX_VERSION_CODE >= 0x020100
static unsigned int vbi_poll(struct video_device *dev, struct file *file,
poll_table *wait)
{
@@ -1983,6 +2290,7 @@ static unsigned int vbi_poll(struct video_device *dev, struct file *file,
return mask;
}
+#endif
static int vbi_open(struct video_device *dev, int flags)
{
@@ -2021,7 +2329,9 @@ static struct video_device vbi_template=
vbi_close,
vbi_read,
bttv_write,
+#if LINUX_VERSION_CODE >= 0x020100
vbi_poll,
+#endif
vbi_ioctl,
NULL, /* no mmap yet */
bttv_init_done,
@@ -2131,7 +2441,9 @@ static struct video_device radio_template=
radio_close,
radio_read, /* just returns -EINVAL */
bttv_write, /* just returns -EINVAL */
+#if LINUX_VERSION_CODE >= 0x020100
NULL, /* no poll */
+#endif
radio_ioctl,
NULL, /* no mmap */
bttv_init_done, /* just returns 0 */
@@ -2149,14 +2461,14 @@ struct vidbases
};
static struct vidbases vbs[] = {
- { PCI_VENDOR_ID_ALLIANCE, PCI_DEVICE_ID_ALLIANCE_AT3D,
- "Alliance AT3D", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_ALLIANCE, PCI_DEVICE_ID_ALLIANCE_AT3D,
+ "Alliance AT3D", PCI_BASE_ADDRESS_0},
{ 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,
- "ATI MACH64 GT", PCI_BASE_ADDRESS_0},
+ "ATI MACH64 GT", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
"DEC DC21030", PCI_BASE_ADDRESS_0},
@@ -2167,6 +2479,7 @@ static struct vidbases vbs[] = {
{ PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP,
"Matrox Millennium II AGP", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
+ { PCI_VENDOR_ID_MATROX, 0x0521, "Matrox G200", PCI_BASE_ADDRESS_0},
{ 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,
@@ -2192,6 +2505,8 @@ static uint dec_offsets[4] = {
/* Scan for PCI display adapter
if more than one card is present the last one is used for now */
+#if LINUX_VERSION_CODE >= 0x020100
+
static int find_vga(void)
{
unsigned short badr;
@@ -2271,6 +2586,99 @@ static int find_vga(void)
return found;
}
+#else
+static int find_vga(void)
+{
+ unsigned int devfn, class, vendev;
+ unsigned short vendor, device, badr;
+ int found=0, bus=0, i, tga_type;
+ unsigned int vidadr=0;
+
+
+ for (devfn = 0; devfn < 0xff; devfn++)
+ {
+ if (PCI_FUNC(devfn) != 0)
+ continue;
+ pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendev);
+ if (vendev == 0xffffffff || vendev == 0x00000000)
+ continue;
+ pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &device);
+ pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class);
+ class = class >> 16;
+/* if (class == PCI_CLASS_DISPLAY_VGA) {*/
+ if ((class>>8) == PCI_BASE_CLASS_DISPLAY ||
+ /* Number 9 GXE64Pro needs this */
+ class == PCI_CLASS_NOT_DEFINED_VGA)
+ {
+ badr=0;
+ printk(KERN_INFO "bttv: PCI display adapter: ");
+ for (i=0; i<NR_CARDS; i++)
+ {
+ if (vendor==vbs[i].vendor)
+ {
+ if (vbs[i].device)
+ if (vbs[i].device!=device)
+ continue;
+ printk("%s.\n", vbs[i].name);
+ badr=vbs[i].badr;
+ break;
+ }
+ }
+ if (NR_CARDS == i)
+ printk("UNKNOWN.\n");
+ if (!badr)
+ {
+ printk(KERN_ERR "bttv: Unknown video memory base address.\n");
+ continue;
+ }
+ pcibios_read_config_dword(bus, devfn, badr, &vidadr);
+ if (vidadr & PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ printk(KERN_ERR "bttv: Memory seems to be I/O memory.\n");
+ printk(KERN_ERR "bttv: Check entry for your card type in bttv.c vidbases struct.\n");
+ continue;
+ }
+ vidadr &= PCI_BASE_ADDRESS_MEM_MASK;
+ if (!vidadr)
+ {
+ printk(KERN_ERR "bttv: Memory @ 0, must be something wrong!\n");
+ continue;
+ }
+
+ if (vendor==PCI_VENDOR_ID_DEC)
+ if (device==PCI_DEVICE_ID_DEC_TGA)
+ {
+ tga_type = (readl((unsigned long)vidadr) >> 12) & 0x0f;
+ if (tga_type != 0 && tga_type != 1 && tga_type != 3)
+ {
+ printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type);
+ found--;
+ }
+ vidadr+=dec_offsets[tga_type];
+ }
+
+ DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr));
+ DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", devfn));
+ found++;
+ }
+ }
+
+ if (vidmem)
+ {
+ if (vidmem < 0x1000)
+ vidadr=vidmem<<20;
+ else
+ vidadr=vidmem;
+ printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr);
+ found=1;
+ }
+ for (i=0; i<BTTV_MAX; i++)
+ bttvs[i].win.vidadr=vidadr;
+
+ return found;
+}
+#endif
#define TRITON_PCON 0x50
@@ -2279,6 +2687,9 @@ static int find_vga(void)
#define TRITON_WRITE_BURST (1<<2)
#define TRITON_PEER_CONCURRENCY (1<<3)
+
+#if LINUX_VERSION_CODE >= 0x020100
+
static void handle_chipset(void)
{
struct pci_dev *dev = NULL;
@@ -2342,6 +2753,78 @@ static void handle_chipset(void)
#endif
}
}
+#else
+static void handle_chipset(void)
+{
+ int index;
+
+ for (index = 0; index < 8; index++)
+ {
+ unsigned char bus, devfn;
+ unsigned char b;
+
+ /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */
+
+ if (!pcibios_find_device(PCI_VENDOR_ID_SI,
+ PCI_DEVICE_ID_SI_496,
+ index, &bus, &devfn))
+ {
+ printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n");
+ }
+
+ if (!pcibios_find_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82441,
+ index, &bus, &devfn))
+ {
+ pcibios_read_config_byte(bus, devfn, 0x53, &b);
+ DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
+ DEBUG(printk("bufcon=0x%02x\n",b));
+ }
+
+ if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437,
+ index, &bus, &devfn))
+ {
+ printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n");
+ triton1=BT848_INT_ETBF;
+
+#if 0
+ /* The ETBF bit SHOULD make all this unnecessary */
+ /* 430FX (Triton I) freezes with bus concurrency on -> switch it off */
+ {
+ unsigned char bo;
+
+ pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
+ bo=b;
+ DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
+
+ if(!(b & TRITON_BUS_CONCURRENCY))
+ {
+ printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n");
+ b |= TRITON_BUS_CONCURRENCY;
+ }
+
+ if(b & TRITON_PEER_CONCURRENCY)
+ {
+ printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n");
+ b &= ~TRITON_PEER_CONCURRENCY;
+ }
+ if(!(b & TRITON_STREAMING))
+ {
+ printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n");
+ b |= TRITON_STREAMING;
+ }
+
+ if (b!=bo)
+ {
+ pcibios_write_config_byte(bus, devfn, TRITON_PCON, b);
+ printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b);
+ }
+ }
+#endif
+ }
+ }
+}
+#endif
static void init_tda8425(struct i2c_bus *bus)
{
@@ -2349,9 +2832,13 @@ static void init_tda8425(struct i2c_bus *bus)
I2CWrite(bus, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */
I2CWrite(bus, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */
I2CWrite(bus, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB */
- I2CWrite(bus, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */
+ I2CWrite(bus, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */
}
+static void init_tda9840(struct i2c_bus *bus)
+{
+ I2CWrite(bus, I2C_TDA9840, TDA9840_SW, 0x2A, 1); /* Sound mode switching */
+}
static void init_tda9850(struct i2c_bus *bus)
{
@@ -2372,7 +2859,6 @@ static void idcard(int i)
{
struct bttv *btv = &bttvs[i];
- int tunertype;
btwrite(0, BT848_GPIO_OUT_EN);
DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA)));
@@ -2385,95 +2871,123 @@ static void idcard(int i)
*/
if (btv->type == BTTV_UNKNOWN)
{
- btv->type=BTTV_MIRO;
-
- if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) {
+ if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0)
+ {
if(btv->id>849)
btv->type=BTTV_HAUPPAUGE878;
else
- btv->type=BTTV_HAUPPAUGE;
+ btv->type=BTTV_HAUPPAUGE;
+
+ } else if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) {
+ btv->type=BTTV_STB;
+ } else
+ if (I2CRead(&(btv->i2c), I2C_VHX)>=0) {
+ btv->type=BTTV_VHX;
+ } else {
+ if (I2CRead(&(btv->i2c), 0x80)>=0) /* check for msp34xx */
+ btv->type = BTTV_MIROPRO;
+ else
+ btv->type=BTTV_MIRO;
}
- else
- if (I2CRead(&(btv->i2c), I2C_STBEE)>=0)
- btv->type=BTTV_STB;
-
- if (btv->type == BTTV_MIRO) {
- /* auto detect tuner for MIRO cards */
- btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
- }
}
+ /* board specific initialisations */
+ if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) {
+ /* auto detect tuner for MIRO cards */
+ btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+ }
+ if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) {
+ hauppauge_msp_reset(btv);
+ hauppauge_eeprom(&(btv->i2c));
+ if (btv->type == BTTV_HAUPPAUGE878) {
+ /* all bt878 hauppauge boards use this ... */
+ btv->pll.pll_ifreq=28636363;
+ btv->pll.pll_crystal=BT848_IFORM_XT0;
+ }
+ }
+ if(btv->type==BTTV_AVERMEDIA98)
+ {
+ btv->pll.pll_ifreq=28636363;
+ btv->pll.pll_crystal=BT848_IFORM_XT0;
+ }
+
+ if (btv->have_tuner && btv->tuner_type != -1)
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_TUNER,
+ TUNER_SET_TYPE,&btv->tuner_type);
+
+
+ if (I2CRead(&(btv->i2c), I2C_TDA9840) >=0)
+ {
+ btv->audio_chip = TDA9840;
+ printk(KERN_INFO "bttv%d: audio chip: TDA9840\n", btv->nr);
+ }
+
if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0)
{
- btv->audio_chip = TDA9850;
- printk(KERN_INFO "bttv%d: audio chip: TDA9850\n", i);
+ btv->audio_chip = TDA9850;
+ printk(KERN_INFO "bttv%d: audio chip: TDA9850\n",btv->nr);
}
if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0)
{
- btv->audio_chip = TDA8425;
- printk("bttv%d: audio chip: TDA8425\n", i);
+ btv->audio_chip = TDA8425;
+ printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",btv->nr);
}
switch(btv->audio_chip)
{
case TDA9850:
init_tda9850(&(btv->i2c));
- break;
- case TDA8425:
+ break;
+ case TDA9840:
+ init_tda9840(&(btv->i2c));
+ break;
+ case TDA8425:
init_tda8425(&(btv->i2c));
break;
}
+
+ printk(KERN_INFO "bttv%d: model: ",btv->nr);
- /* How do I detect the tuner type for other cards but Miro ??? */
- printk(KERN_INFO "bttv%d: model: ", btv->nr);
sprintf(btv->video_dev.name,"BT%d",btv->id);
switch (btv->type)
{
- case BTTV_MIRO:
- case BTTV_MIROPRO:
- printk("MIRO\n");
- 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)");
+ case BTTV_MIRO:
+ case BTTV_MIROPRO:
+ strcat(btv->video_dev.name,
+ (btv->type == BTTV_MIRO) ? "(Miro)" : "(Miro pro)");
break;
case BTTV_HAUPPAUGE:
+ strcat(btv->video_dev.name,"(Hauppauge old)");
+ break;
case BTTV_HAUPPAUGE878:
- printk("HAUPPAUGE\n");
- strcat(btv->video_dev.name,"(Hauppauge)");
+ strcat(btv->video_dev.name,"(Hauppauge new)");
break;
case BTTV_STB:
- printk("STB\n");
strcat(btv->video_dev.name,"(STB)");
break;
case BTTV_INTEL:
- printk("Intel\n");
strcat(btv->video_dev.name,"(Intel)");
break;
case BTTV_DIAMOND:
- printk("Diamond\n");
strcat(btv->video_dev.name,"(Diamond)");
break;
case BTTV_AVERMEDIA:
- printk("AVerMedia\n");
strcat(btv->video_dev.name,"(AVerMedia)");
break;
case BTTV_MATRIX_VISION:
- printk("MATRIX-Vision\n");
strcat(btv->video_dev.name,"(MATRIX-Vision)");
break;
- case BTTV_ADSTECH_TV:
- printk("ADSTech Channel Surfer TV\n");
- strcat(btv->video_dev.name,"(ADSTech Channel Surfer TV)");
- btv->tuner_type=8;
+ case BTTV_AVERMEDIA98:
+ strcat(btv->video_dev.name,"(AVerMedia TVCapture 98)");
break;
+ case BTTV_VHX:
+ strcpy(btv->video_dev.name,"BT848(Aimslab-VHX)");
+ break;
}
- audio(btv, AUDIO_INTERN);
+ printk("%s\n",btv->video_dev.name);
+ audio(btv, AUDIO_MUTE);
}
@@ -2522,7 +3036,7 @@ static void bt848_set_risc_jmps(struct bttv *btv)
btv->risc_jmp[12]=BT848_RISC_JUMP;
btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp);
- /* enable capturing and DMA */
+ /* enable cpaturing and DMA */
btaor(flags, ~0x0f, BT848_CAP_CTL);
if (flags&0x0f)
bt848_dma(btv, 3);
@@ -2530,7 +3044,6 @@ static void bt848_set_risc_jmps(struct bttv *btv)
bt848_dma(btv, 0);
}
-
static int init_bt848(int i)
{
struct bttv *btv = &bttvs[i];
@@ -2541,19 +3054,7 @@ static int init_bt848(int i)
btwrite(0, BT848_SRESET);
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 */
-
btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */
btv->win.interlace=1;
btv->win.x=0;
@@ -2582,7 +3083,10 @@ static int init_bt848(int i)
btv->grabcount=0;
btv->grab=0;
btv->lastgrab=0;
- btv->field=btv->last_field=0;
+ btv->field=btv->last_field=0;
+ /* cevans - prevents panic if initialization bails due to memory
+ * alloc failures!
+ */
btv->video_dev.minor = -1;
btv->vbi_dev.minor = -1;
btv->radio_dev.minor = -1;
@@ -2613,6 +3117,7 @@ static int init_bt848(int i)
memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random
memory to the user */
+
btv->fbuffer=NULL;
bt848_muxsel(btv, 1);
@@ -2621,7 +3126,7 @@ static int init_bt848(int i)
/* btwrite(0, BT848_TDEC); */
btwrite(0x10, BT848_COLOR_CTL);
btwrite(0x00, BT848_CAP_CTL);
- btwrite(0xfc, BT848_GPIO_DMA_CTL);
+ btwrite(0xac, BT848_GPIO_DMA_CTL);
/* select direct input */
btwrite(0x00, BT848_GPIO_REG_INP);
@@ -2671,6 +3176,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(i);
if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
@@ -2730,7 +3236,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (astat&BT848_INT_VSYNC)
{
IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr));
- btv->field++;
+ btv->field++;
}
if (astat&BT848_INT_SCERR) {
IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr));
@@ -2756,8 +3262,9 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
/* captured full frame */
if (stat&(2<<28))
{
+ wake_up_interruptible(&btv->capq);
btv->last_field=btv->field;
- btv->grab++;
+ btv->grab++;
btv->frame_stat[btv->grf] = GBUFFER_DONE;
if ((--btv->grabbing))
{
@@ -2774,7 +3281,9 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->gfmt);
} else {
bt848_set_risc_jmps(btv);
- bt848_set_geo(btv, btv->win.width,
+ btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI);
+ btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI);
+ bt848_set_geo(btv, btv->win.width,
btv->win.height,
btv->win.color_fmt);
}
@@ -2820,12 +3329,10 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
if (astat&BT848_INT_HLOCK)
{
-#if 0
if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
audio(btv, AUDIO_ON);
else
audio(btv, AUDIO_OFF);
-#endif
}
if (astat&BT848_INT_I2CDONE)
@@ -2834,7 +3341,8 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
count++;
if (count > 10)
- printk (KERN_WARNING "bttv%d: irq loop %d\n", btv->nr, count);
+ printk (KERN_WARNING "bttv%d: irq loop %d\n",
+ btv->nr,count);
if (count > 20)
{
btwrite(0, BT848_INT_MASK);
@@ -2850,17 +3358,16 @@ 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
*/
+#if LINUX_VERSION_CODE >= 0x020100
int configure_bt848(struct pci_dev *dev, int bttv_num)
{
int result;
- unsigned char bus, devfn, command;
+ unsigned char command;
struct bttv *btv;
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;
@@ -2896,15 +3403,14 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
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("bus: %d, devfn: %d, ",dev->bus->number, dev->devfn);
printk("irq: %d, ",btv->irq);
printk("memory: 0x%08x.\n", btv->bt848_adr);
-
- btv->pll.pll_ifreq=0;
- btv->pll.pll_ofreq=0;
- btv->pll.pll_crystal=0;
- btv->pll.pll_current=0;
+
+ btv->pll.pll_crystal = 0;
+ btv->pll.pll_ifreq = 0;
+ btv->pll.pll_ofreq = 0;
+ btv->pll.pll_current = 0;
if (!(btv->id==848 && btv->revision==0x11)) {
switch (pll[btv->nr]) {
case 0:
@@ -2922,10 +3428,10 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
break;
}
}
-
+
btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
- /* clear interrupt mask */
+ /* clear interrupt mask */
btwrite(0, BT848_INT_MASK);
result = request_irq(btv->irq, bttv_irq,
@@ -2988,7 +3494,170 @@ static int find_bt848(void)
printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num);
return bttv_num;
}
-
+#else
+static int find_bt848(void)
+{
+ short pci_index;
+ unsigned char command, latency;
+ int result;
+ unsigned char bus, devfn;
+ struct bttv *btv;
+
+ bttv_num=0;
+
+ if (!pcibios_present())
+ {
+ DEBUG(printk(KERN_DEBUG "bttv%d: PCI-BIOS not present or not accessable!\n",bttv_num));
+ return 0;
+ }
+
+ for (pci_index = 0;
+ !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
+ pci_index, &bus, &devfn);
+ ++pci_index)
+ {
+ btv=&bttvs[bttv_num];
+ btv->nr = bttv_num;
+ btv->bus=bus;
+ btv->devfn=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;
+
+ pcibios_read_config_word(btv->bus, btv->devfn, PCI_DEVICE_ID,
+ &btv->id);
+ pcibios_read_config_byte(btv->bus, btv->devfn,
+ PCI_INTERRUPT_LINE, &btv->irq);
+ pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
+ &btv->bt848_adr);
+ 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);
+ pcibios_write_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
+ remap[bttv_num]);
+ pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
+ &btv->bt848_adr);
+ }
+
+ btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
+ pcibios_read_config_byte(btv->bus, btv->devfn, 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_crystal = 0;
+ btv->pll.pll_ifreq = 0;
+ btv->pll.pll_ofreq = 0;
+ btv->pll.pll_current = 0;
+ if (!(btv->id==848 && btv->revision==0x11)) {
+ switch (pll[btv->nr]) {
+ case 0:
+ /* off */
+ break;
+ case 1:
+ /* 28 MHz crystal installed */
+ btv->pll.pll_ifreq=28636363;
+ btv->pll.pll_crystal=BT848_IFORM_XT0;
+ break;
+ case 2:
+ /* 35 MHz crystal installed */
+ btv->pll.pll_ifreq=35468950;
+ btv->pll.pll_crystal=BT848_IFORM_XT1;
+ break;
+ }
+ }
+
+ btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
+
+ 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;
+
+ /* Enable bus-mastering */
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
+ command|=PCI_COMMAND_MASTER;
+ pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
+ if (!(command&PCI_COMMAND_MASTER))
+ {
+ printk(KERN_ERR "bttv%d: PCI bus-mastering could not be enabled\n",bttv_num);
+ return -1;
+ }
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER,
+ &latency);
+ if (!latency)
+ {
+ latency=32;
+ pcibios_write_config_byte(btv->bus, btv->devfn,
+ PCI_LATENCY_TIMER, latency);
+ }
+ DEBUG(printk(KERN_DEBUG "bttv%d: latency: %02x\n",
+ bttv_num, latency));
+
+ btv->triton1=triton1 ? BT848_INT_ETBF : 0;
+ if (triton1 && btv->id >= 878)
+ {
+ triton1 = 0;
+ printk("bttv: Enabling 430FX compatibilty for bt878\n");
+ pcibios_read_config_byte(btv->bus, btv->devfn, BT878_DEVCTRL, &command);
+ command|=BT878_EN_TBFX;
+ pcibios_write_config_byte(btv->bus, btv->devfn, BT878_DEVCTRL, command);
+ pcibios_read_config_byte(btv->bus, btv->devfn, BT878_DEVCTRL, &command);
+ if (!(command&BT878_EN_TBFX))
+ {
+ printk("bttv: 430FX compatibility could not be enabled\n");
+ return -1;
+ }
+ }
+
+ bttv_num++;
+ }
+ if(bttv_num)
+ printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num);
+ return bttv_num;
+}
+#endif
static void release_bttv(void)
{
@@ -3013,10 +3682,17 @@ static void release_bttv(void)
i2c_unregister_bus((&btv->i2c));
/* disable PCI bus-mastering */
+#if LINUX_VERSION_CODE >= 0x020100
pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
/* Should this be &=~ ?? */
- command|=PCI_COMMAND_MASTER;
+ command&=~PCI_COMMAND_MASTER;
pci_write_config_byte(btv->dev, PCI_COMMAND, command);
+#else
+ pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
+ command&=~PCI_COMMAND_MASTER;
+ pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
+
+#endif
/* unmap and free memory */
if (btv->grisc)
@@ -3046,7 +3722,7 @@ static void release_bttv(void)
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)
+ if (radio[btv->nr] && btv->radio_dev.minor != -1)
video_unregister_device(&btv->radio_dev);
}
}
@@ -3074,6 +3750,7 @@ int init_bttv_cards(struct video_init *unused)
return -EIO;
}
}
+
return 0;
}
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index f780de12b..ba6c52af4 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -21,7 +21,7 @@
#ifndef _BTTV_H_
#define _BTTV_H_
-#define TEST_VBI
+#define BTTV_VERSION_CODE 0x000523
#include <linux/types.h>
#include <linux/wait.h>
@@ -31,8 +31,13 @@
#include "bt848.h"
#include <linux/videodev.h>
+#ifndef O_NONCAP
+#define O_NONCAP O_TRUNC
+#endif
+
#define MAX_GBUFFERS 2
#define RISCMEM_LEN (32744*2)
+#define VBIBUF_SIZE 65536
/* maximum needed buffer size for extended VBI frame mode capturing */
#define BTTV_MAX_FBUF 0x190000
@@ -56,11 +61,20 @@ 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 */
- unsigned int pll_current; /* Current programmed ofrq*/
+ unsigned int pll_ifreq; /* PLL input frequency */
+ unsigned int pll_ofreq; /* PLL output frequency */
+ unsigned int pll_crystal; /* Crystal used for input */
+ unsigned int pll_current; /* Currently programmed ofreq */
+};
+
+/* Per-open data for handling multiple opens on one device */
+struct device_open
+{
+ int isopen;
+ int noncapturing;
+ struct bttv *dev;
};
+#define MAX_OPENS 3
struct bttv
{
@@ -70,6 +84,10 @@ struct bttv
struct video_picture picture; /* Current picture params */
struct video_audio audio_dev; /* Current audio params */
+ int user;
+ int capuser;
+ struct device_open open_data[MAX_OPENS];
+
struct i2c_bus i2c;
int have_msp3400;
int have_tuner;
@@ -78,9 +96,12 @@ struct bttv
unsigned int nr;
unsigned short id;
+#if LINUX_VERSION_CODE < 0x020100
unsigned char bus; /* PCI bus the Bt848 is on */
unsigned char devfn;
+#else
struct pci_dev *dev;
+#endif
unsigned char irq; /* IRQ used by Bt848 card */
unsigned char revision;
unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */
@@ -92,7 +113,6 @@ struct bttv
struct bttv_window win;
int type; /* card type */
int audio; /* audio mode */
- int user;
int audio_chip;
int radio;
@@ -115,7 +135,7 @@ struct bttv
struct gbuffer *ogbuffers;
struct gbuffer *egbuffers;
u16 gwidth, gheight, gfmt;
- u16 gwidth_next, gheight_next, gfmt_next;
+ u16 gwidth_next, gheight_next, gfmt_next;
u32 *grisc;
unsigned long gro;
@@ -143,7 +163,6 @@ struct bttv
int i2c_command;
int triton1;
};
-
#endif
/*The following should be done in more portable way. It depends on define
@@ -165,12 +184,11 @@ 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_BURST_ON _IOR('v' , BASE_VIDIOCPRIVATE+4, int)
-#define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int)
-#define BTTV_NAGRAVERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
+#define BTTV_BURST_ON _IOR('v' , BASE_VIDIOCPRIVATE+4, int)
+#define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int)
+#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int)
#define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int)
@@ -187,6 +205,8 @@ struct bttv
#define BTTV_HAUPPAUGE878 0x0a
#define BTTV_MIROPRO 0x0b
#define BTTV_ADSTECH_TV 0x0c
+#define BTTV_AVERMEDIA98 0x0d
+#define BTTV_VHX 0x0e
#define AUDIO_TUNER 0x00
#define AUDIO_RADIO 0x01
@@ -199,12 +219,20 @@ struct bttv
#define TDA9850 0x01
#define TDA8425 0x02
+#define TDA9840 0x03
#define I2C_TSA5522 0xc2
+#define I2C_TDA9840 0x84
#define I2C_TDA9850 0xb6
#define I2C_TDA8425 0x82
#define I2C_HAUPEE 0xa0
#define I2C_STBEE 0xae
+#define I2C_VHX 0xc0
+
+#define TDA9840_SW 0x00
+#define TDA9840_LVADJ 0x02
+#define TDA9840_STADJ 0x03
+#define TDA9840_TEST 0x04
#define TDA9850_CON1 0x04
#define TDA9850_CON2 0x05
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 34651f9e9..d4fc2d7f9 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -56,6 +56,10 @@
static struct mouse_status mouse;
static int mouse_irq = MOUSE_IRQ;
+#ifdef MODULE
+MODULE_PARM(mouse_irq, "i");
+#endif
+
__initfunc(void bmouse_setup(char *str, int *ints))
{
if (ints[0] > 0)
diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c
index 6ffb80a54..5f9341eac 100644
--- a/drivers/char/c-qcam.c
+++ b/drivers/char/c-qcam.c
@@ -1,13 +1,9 @@
/*
- * Video4Linux: Colour QuickCam driver
+ * Video4Linux Colour QuickCam driver
+ * Copyright 1997-1998 Philip Blundell <philb@gnu.org>
*
- * Philip Blundell <philb@gnu.org>, December 30 1997
- *
- * Largely untested (seems to work at 24bpp with a bidirectional port,
- * though).
*/
-
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -22,27 +18,47 @@
#include <linux/videodev.h>
#include <asm/uaccess.h>
-#include "c-qcam.h"
+struct qcam_device {
+ struct video_device vdev;
+ struct pardevice *pdev;
+ struct parport *pport;
+ int width, height;
+ int ccd_width, ccd_height;
+ int mode;
+ int contrast, brightness, whitebal;
+ int top, left;
+ unsigned int bidirectional;
+};
+
+/* The three possible QuickCam modes */
+#define QC_MILLIONS 0x18
+#define QC_BILLIONS 0x10
+#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */
+
+/* The three possible decimations */
+#define QC_DECIMATION_1 0
+#define QC_DECIMATION_2 2
+#define QC_DECIMATION_4 4
-static __inline__ void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
+static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
{
/* note: the QC specs refer to the PCAck pin by voltage, not
software level. PC ports have builtin inverters. */
parport_frob_control(qcam->pport, 8, i?8:0);
}
-static __inline__ unsigned int qcam_ready1(struct qcam_device *qcam)
+static inline unsigned int qcam_ready1(struct qcam_device *qcam)
{
return (parport_read_status(qcam->pport) & 0x8)?1:0;
-
}
-static __inline__ unsigned int qcam_ready2(struct qcam_device *qcam)
+static inline unsigned int qcam_ready2(struct qcam_device *qcam)
{
return (parport_read_data(qcam->pport) & 0x1)?1:0;
}
-static inline unsigned int qcam_await_ready1(struct qcam_device *qcam, int value)
+static unsigned int qcam_await_ready1(struct qcam_device *qcam,
+ int value)
{
unsigned long oldjiffies = jiffies;
unsigned int i;
@@ -68,7 +84,7 @@ static inline unsigned int qcam_await_ready1(struct qcam_device *qcam, int value
return 1;
}
-static inline unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
+static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
{
unsigned long oldjiffies = jiffies;
unsigned int i;
@@ -95,7 +111,7 @@ static inline unsigned int qcam_await_ready2(struct qcam_device *qcam, int value
return 1;
}
-static inline int qcam_read_data(struct qcam_device *qcam)
+static int qcam_read_data(struct qcam_device *qcam)
{
unsigned int idata;
qcam_set_ack(qcam, 0);
@@ -179,11 +195,10 @@ static void qc_setup(struct qcam_device *q)
/* Set the brightness. */
qcam_set(q, 11, q->brightness);
- /* Set the height. */
- qcam_set(q, 17, q->height);
-
- /* Set the width. */
- qcam_set(q, 19, q->width/2);
+ /* Set the height and width. These refer to the actual
+ CCD area *before* applying the selected decimation. */
+ qcam_set(q, 17, q->ccd_height);
+ qcam_set(q, 19, q->ccd_width / 2);
/* Set top and left. */
qcam_set(q, 0xd, q->top);
@@ -236,53 +251,24 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u
if (qcam_await_ready1(q, 0)) return bytes;
lo = (parport_read_status(q->pport) & 0xf0);
qcam_set_ack(q, 0);
- /* flip some bits; cqcam gets this wrong */
- buf[bytes++] = (hi | lo) ^ 0x88;
+ /* flip some bits */
+ buf[bytes++] = (hi | (lo >> 4)) ^ 0x88;
}
}
return bytes;
}
-/* Convert the data the camera gives us into the desired output format.
- At the moment this is a no-op because read_bytes() does all the
- required stuff, for 24bpp at least. */
-static size_t qcam_munge_buffer(struct qcam_device *q, char *inbuf, size_t inlen, char *outbuf, size_t outlen)
-{
- size_t outptr = 0;
- switch (q->bpp)
- {
- case 24:
- while (inlen && (outptr <= (outlen-3)))
- {
- unsigned char r, g, b;
- r = inbuf[0];
- g = inbuf[1];
- b = inbuf[2];
- put_user(r, outbuf+(outptr++));
- put_user(g, outbuf+(outptr++));
- put_user(b, outbuf+(outptr++));
- inlen -= 3;
- inbuf += 3;
- }
- break;
- default:
- printk("c-qcam: can't convert this format (%d).\n", q->bpp);
- return 0;
- }
- return outptr;
-}
+#define BUFSZ 150
static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
{
- unsigned int tbpp = 0, tdecimation = 0, lines, pixelsperline, bitsperxfer;
+ unsigned lines, pixelsperline, bitsperxfer;
unsigned int is_bi_dir = q->bidirectional;
size_t wantlen, outptr = 0;
- char *tmpbuf = kmalloc(768, GFP_KERNEL);
- if (tmpbuf == NULL)
- {
- printk(KERN_ERR "cqcam: couldn't allocate a buffer.\n");
- return -ENOMEM;
- }
+ char tmpbuf[BUFSZ];
+
+ if (verify_area(VERIFY_WRITE, buf, len))
+ return -EFAULT;
/* Wait for camera to become ready */
for (;;)
@@ -290,33 +276,19 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
int i = qcam_get(q, 41);
if (i == -1) {
qc_setup(q);
- kfree(tmpbuf);
return -EIO;
}
- if (i & 0x80)
- schedule();
- else
+ if ((i & 0x80) == 0)
break;
+ else
+ schedule();
}
- switch (q->bpp)
- {
- case 24: tbpp = QC_24BPP; break;
- case 32: tbpp = QC_32BPP; break;
- case 16: tbpp = QC_16BPP; break;
- default: printk("qcam: Bad bpp.\n");
- }
- switch (q->transfer_scale) {
- case 1: tdecimation = QC_1_1; break;
- case 2: tdecimation = QC_2_1; break;
- case 4: tdecimation = QC_4_1; break;
- default: printk("qcam: Bad decimation.\n");
- }
+ if (qcam_set(q, 7, (q->mode | (is_bi_dir?1:0)) + 1))
+ return -EIO;
- qcam_set(q, 7, (tbpp | tdecimation) + ((is_bi_dir)?1:0) + 1);
-
- lines = q->height / q->transfer_scale;
- pixelsperline = q->width / q->transfer_scale;
+ lines = q->height;
+ pixelsperline = q->width;
bitsperxfer = (is_bi_dir) ? 24 : 8;
if (is_bi_dir)
@@ -326,33 +298,33 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
mdelay(3);
qcam_set_ack(q, 0);
if (qcam_await_ready1(q, 1)) {
- kfree(tmpbuf);
qc_setup(q);
return -EIO;
}
qcam_set_ack(q, 1);
if (qcam_await_ready1(q, 0)) {
- kfree(tmpbuf);
qc_setup(q);
return -EIO;
}
}
- wantlen = lines * pixelsperline * q->bpp / 8;
+ wantlen = lines * pixelsperline * 24 / 8;
while (wantlen)
{
- size_t t, s, o;
- s = (wantlen > 768)?768:wantlen;
+ size_t t, s;
+ s = (wantlen > BUFSZ)?BUFSZ:wantlen;
t = qcam_read_bytes(q, tmpbuf, s);
if (outptr < len)
{
- o = qcam_munge_buffer(q, tmpbuf, t, buf + outptr,
- len - outptr);
- outptr += o;
+ size_t sz = len - outptr;
+ if (sz > t) sz = t;
+ if (__copy_to_user(buf+outptr, tmpbuf, sz))
+ break;
+ outptr += sz;
}
wantlen -= t;
- if (t < s)
+ if (t < s)
break;
if (current->need_resched)
schedule();
@@ -366,7 +338,6 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
if (is_bi_dir)
parport_frob_control(q->pport, 0x20, 0);
qc_setup(q);
- kfree(tmpbuf);
return len;
}
@@ -386,7 +357,6 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
printk("qcam: no ack after EOF\n");
parport_frob_control(q->pport, 0x20, 0);
qc_setup(q);
- kfree(tmpbuf);
return len;
}
parport_frob_control(q->pport, 0x20, 0);
@@ -396,7 +366,6 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
{
printk("qcam: no ack to port turnaround\n");
qc_setup(q);
- kfree(tmpbuf);
return len;
}
}
@@ -413,10 +382,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
printk("qcam: bad EOF\n");
}
- kfree(tmpbuf);
-
qcam_write_data(q, 0);
-
return len;
}
@@ -526,7 +492,7 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
p.brightness=qcam->brightness<<8;
p.contrast=qcam->contrast<<8;
p.whiteness=qcam->whitebal<<8;
- p.depth=qcam->bpp;
+ p.depth=24;
p.palette=VIDEO_PALETTE_RGB24;
if(copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
@@ -538,7 +504,10 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
- if (p.palette != VIDEO_PALETTE_RGB24)
+ /*
+ * Sanity check args
+ */
+ if (p.depth != 24 || p.palette != VIDEO_PALETTE_RGB24)
return -EINVAL;
/*
@@ -547,7 +516,6 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
qcam->brightness = p.brightness>>8;
qcam->contrast = p.contrast>>8;
qcam->whitebal = p.whiteness>>8;
- qcam->bpp = p.depth;
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
@@ -557,6 +525,7 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCSWIN:
{
struct video_window vw;
+
if(copy_from_user(&vw, arg,sizeof(vw)))
return -EFAULT;
if(vw.flags)
@@ -568,21 +537,33 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(vw.width<80||vw.width>320)
return -EINVAL;
- qcam->width = 320;
- qcam->height = 240;
- qcam->transfer_scale = 4;
+ qcam->width = 80;
+ qcam->height = 60;
+ qcam->mode = QC_DECIMATION_4;
if(vw.width>=160 && vw.height>=120)
{
- qcam->transfer_scale = 2;
+ qcam->width = 160;
+ qcam->height = 120;
+ qcam->mode = QC_DECIMATION_2;
}
if(vw.width>=320 && vw.height>=240)
{
qcam->width = 320;
qcam->height = 240;
- qcam->transfer_scale = 1;
+ qcam->mode = QC_DECIMATION_1;
+ }
+ qcam->mode |= QC_MILLIONS;
+#if 0
+ if(vw.width>=640 && vw.height>=480)
+ {
+ qcam->width = 640;
+ qcam->height = 480;
+ qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
}
- /* Ok we figured out what to use from our wide choice */
+#endif
+ /* Ok we figured out what to use from our
+ wide choice */
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
parport_release(qcam->pdev);
@@ -593,8 +574,8 @@ static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_window vw;
vw.x=0;
vw.y=0;
- vw.width=qcam->width/qcam->transfer_scale;
- vw.height=qcam->height/qcam->transfer_scale;
+ vw.width=qcam->width;
+ vw.height=qcam->height;
vw.chromakey=0;
vw.flags=0;
if(copy_to_user(arg, &vw, sizeof(vw)))
@@ -677,10 +658,9 @@ static struct qcam_device *qcam_init(struct parport *port)
memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
- q->width = 320;
- q->height = 240;
- q->bpp = 32;
- q->transfer_scale = 1;
+ q->width = q->ccd_width = 320;
+ q->height = q->ccd_height = 240;
+ q->mode = QC_MILLIONS | QC_DECIMATION_1;
q->contrast = 192;
q->brightness = 240;
q->whitebal = 128;
@@ -723,7 +703,7 @@ int init_cqcam(struct parport *port)
parport_release(qcam->pdev);
- printk(KERN_INFO "Connectix Colour Quickcam on %s\n",
+ printk(KERN_INFO "Colour Quickcam found on %s\n",
qcam->pport->name);
if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1)
@@ -745,11 +725,15 @@ void close_cqcam(struct qcam_device *qcam)
kfree(qcam);
}
+#define BANNER "Connectix Colour Quickcam driver v0.02\n"
+
#ifdef MODULE
int init_module(void)
{
struct parport *port;
+ printk(BANNER);
+
for (port = parport_enumerate(); port; port=port->next)
init_cqcam(port);
@@ -767,6 +751,8 @@ __initfunc(int init_colour_qcams(struct video_init *unused))
{
struct parport *port;
+ printk(BANNER);
+
for (port = parport_enumerate(); port; port=port->next)
init_cqcam(port);
return 0;
diff --git a/drivers/char/c-qcam.h b/drivers/char/c-qcam.h
deleted file mode 100644
index b0dbe3015..000000000
--- a/drivers/char/c-qcam.h
+++ /dev/null
@@ -1,18 +0,0 @@
-struct qcam_device {
- struct video_device vdev;
- struct pardevice *pdev;
- struct parport *pport;
- int width, height;
- int bpp;
- int contrast, brightness, whitebal;
- int transfer_scale;
- int top, left;
- unsigned int bidirectional;
-};
-
-#define QC_1_1 0
-#define QC_2_1 2
-#define QC_4_1 4
-#define QC_16BPP 8
-#define QC_32BPP 16
-#define QC_24BPP 24
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 77d80f241..a589e4a9b 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -1029,7 +1029,7 @@ static void csi_m(int currcons)
*/
translate = set_translate(charset == 0
? G0_charset
- : G1_charset);
+ : G1_charset,currcons);
disp_ctrl = 0;
toggle_meta = 0;
break;
@@ -1037,7 +1037,7 @@ static void csi_m(int currcons)
* Select first alternate font, let's
* chars < 32 be displayed as ROM chars.
*/
- translate = set_translate(IBMPC_MAP);
+ translate = set_translate(IBMPC_MAP,currcons);
disp_ctrl = 1;
toggle_meta = 0;
break;
@@ -1045,7 +1045,7 @@ static void csi_m(int currcons)
* Select second alternate font, toggle
* high bit before displaying as ROM char.
*/
- translate = set_translate(IBMPC_MAP);
+ translate = set_translate(IBMPC_MAP,currcons);
disp_ctrl = 1;
toggle_meta = 1;
break;
@@ -1221,6 +1221,8 @@ static void setterm_command(int currcons)
break;
case 8: /* store colors as defaults */
def_color = attr;
+ if (hi_font_mask == 0x100)
+ def_color >>= 1;
default_attr(currcons);
update_attr(currcons);
break;
@@ -1328,7 +1330,7 @@ static void restore_cur(int currcons)
color = s_color;
G0_charset = saved_G0;
G1_charset = saved_G1;
- translate = set_translate(charset ? G1_charset : G0_charset);
+ translate = set_translate(charset ? G1_charset : G0_charset,currcons);
update_attr(currcons);
need_wrap = 0;
}
@@ -1343,7 +1345,7 @@ static void reset_terminal(int currcons, int do_clear)
bottom = video_num_lines;
vc_state = ESnormal;
ques = 0;
- translate = set_translate(LAT1_MAP);
+ translate = set_translate(LAT1_MAP,currcons);
G0_charset = LAT1_MAP;
G1_charset = GRAF_MAP;
charset = 0;
@@ -1426,12 +1428,12 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
return;
case 14:
charset = 1;
- translate = set_translate(G1_charset);
+ translate = set_translate(G1_charset,currcons);
disp_ctrl = 1;
return;
case 15:
charset = 0;
- translate = set_translate(G0_charset);
+ translate = set_translate(G0_charset,currcons);
disp_ctrl = 0;
return;
case 24: case 26:
@@ -1738,7 +1740,7 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
else if (c == 'K')
G0_charset = USER_MAP;
if (charset == 0)
- translate = set_translate(G0_charset);
+ translate = set_translate(G0_charset,currcons);
vc_state = ESnormal;
return;
case ESsetG1:
@@ -1751,7 +1753,7 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
else if (c == 'K')
G1_charset = USER_MAP;
if (charset == 1)
- translate = set_translate(G1_charset);
+ translate = set_translate(G1_charset,currcons);
vc_state = ESnormal;
return;
default:
@@ -1894,7 +1896,7 @@ static int do_con_write(struct tty_struct * tty, int from_user,
if (decim)
insert_char(currcons, 1);
scr_writew(himask ?
- ((attr & ~himask) << 8) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+ ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
(attr << 8) + tc,
(u16 *) pos);
if (DO_UPDATE && draw_x < 0) {
@@ -2231,6 +2233,12 @@ static int con_open(struct tty_struct *tty, struct file * filp)
return 0;
}
+static void con_close(struct tty_struct *tty, struct file * filp)
+{
+ if (tty->count == 1)
+ tty->driver_data = 0;
+}
+
static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
{
int j, k ;
@@ -2292,6 +2300,7 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
console_driver.termios_locked = console_termios_locked;
console_driver.open = con_open;
+ console_driver.close = con_close;
console_driver.write = con_write;
console_driver.write_room = con_write_room;
console_driver.put_char = con_put_char;
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 95bb6f204..7e97e1fe7 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -7,6 +7,8 @@
* aeb, 950210
*
* Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
+ *
+ * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
*/
#include <linux/kd.h>
@@ -167,7 +169,7 @@ static unsigned short translations[][256] = {
#define MAX_GLYPH 512 /* Max possible glyph value */
-static int inv_translate;
+static int inv_translate[MAX_NR_CONSOLES];
struct uni_pagedir {
u16 **uni_pgdir[32];
@@ -204,9 +206,9 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
}
}
-unsigned short *set_translate(int m)
+unsigned short *set_translate(int m,int currcons)
{
- inv_translate = m;
+ inv_translate[currcons] = m;
return translations[m];
}
@@ -220,14 +222,13 @@ unsigned short *set_translate(int m)
unsigned char inverse_translate(struct vc_data *conp, int glyph)
{
struct uni_pagedir *p;
-
if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
- !p->inverse_translations[inv_translate])
+ !p->inverse_translations[inv_translate[conp->vc_num]])
return glyph;
else
- return p->inverse_translations[inv_translate][glyph];
+ return p->inverse_translations[inv_translate[conp->vc_num]][glyph];
}
static void update_user_maps(void)
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 62e31d9c9..a023cdd55 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.8 $$Date: 1998/11/13 12:46:20 $";
+"$Revision: 2.2.1.10 $$Date: 1999/01/20 16:14:29 $";
/*
* linux/drivers/char/cyclades.c
@@ -31,6 +31,14 @@ static char rcsid[] =
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
+ * Revision 2.2.1.10 1999/01/20 16:14:29 ivan
+ * Removed all unnecessary page-alignement operations in ioremap calls
+ * (ioremap is currently safe for these operations).
+ *
+ * Revision 2.2.1.9 1998/12/30 18:18:30 ivan
+ * Changed access to PLX PCI bridge registers from I/O to MMIO, in
+ * order to make PLX9050-based boards work with certain motherboards.
+ *
* Revision 2.2.1.8 1998/11/13 12:46:20 ivan
* cy_close function now resets (correctly) the tty->closing flag;
* JIFFIES_DIFF macro fixed.
@@ -580,10 +588,8 @@ static char rcsid[] =
#include <linux/pci.h>
#include <linux/version.h>
-#ifdef CONFIG_PROC_FS
#include <linux/stat.h>
#include <linux/proc_fs.h>
-#endif
#define cy_put_user put_user
@@ -777,9 +783,7 @@ static void cyz_poll(unsigned long);
static void show_status(int);
#endif
-#ifdef CONFIG_PROC_FS
static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *);
-#endif
/* The Cyclades-Z polling cycle is defined by this variable */
static long cyz_polling_cycle = CZ_DEF_POLL;
@@ -1004,13 +1008,13 @@ check_wild_interrupts(void)
* occur during the bootup sequence
*/
timeout = jiffies+(HZ/10);
- while (timeout >= jiffies)
+ while (time_after_eq(timeout, jiffies))
;
cy_triggered = 0; /* Reset after letting things settle */
timeout = jiffies+(HZ/10);
- while (timeout >= jiffies)
+ while (time_after_eq(timeout, jiffies))
;
for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
@@ -1054,7 +1058,7 @@ get_auto_irq(volatile ucchar *address)
restore_flags(flags);
timeout = jiffies+(HZ/50);
- while (timeout >= jiffies) {
+ while (time_after_eq(timeout, jiffies)) {
if (cy_irq_triggered)
break;
}
@@ -2597,7 +2601,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
schedule_timeout(char_time);
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && time_before(orig_jiffies + timeout, jiffies))
break;
}
current->state = TASK_RUNNING;
@@ -3396,8 +3400,7 @@ get_serial_info(struct cyclades_port * info,
tmp.baud_base = info->baud;
tmp.custom_divisor = 0; /*!!!*/
tmp.hub6 = 0; /*!!!*/
- copy_to_user(retinfo,&tmp,sizeof(*retinfo));
- return 0;
+ return copy_to_user(retinfo,&tmp,sizeof(*retinfo))?-EFAULT:0;
} /* get_serial_info */
@@ -3768,7 +3771,8 @@ static int
get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
{
- copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor));
+ if(copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
+ return -EFAULT;
info->mon.int_count = 0;
info->mon.char_count = 0;
info->mon.char_max = 0;
@@ -4461,8 +4465,7 @@ cy_detect_isa(void))
/* probe for CD1400... */
#if !defined(__alpha__)
- cy_isa_address = ioremap((unsigned int)cy_isa_address,
- CyISA_Ywin);
+ cy_isa_address = ioremap((ulong)cy_isa_address, CyISA_Ywin);
#endif
cy_isa_nchan = CyPORTS_PER_CHIP *
cyy_init_card(cy_isa_address,0);
@@ -4545,7 +4548,6 @@ cy_detect_pci(void))
struct pci_dev *pdev = NULL;
unsigned char cyy_rev_id;
- 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, plx_ver;
@@ -4584,11 +4586,11 @@ cy_detect_pci(void))
pdev->bus->number, pdev->devfn);
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr1);
+ printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
+ (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
#endif
- cy_pci_addr1 &= PCI_BASE_ADDRESS_IO_MASK;
- cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
+ cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
+ cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
#if defined(__alpha__)
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
@@ -4596,20 +4598,21 @@ cy_detect_pci(void))
pdev->bus->number, pdev->devfn);
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr1);
+ printk("Cyclom-Y/PCI:found winaddr=0x%lx ctladdr=0x%lx\n",
+ (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
printk("Cyclom-Y/PCI not supported for low addresses in "
"Alpha systems.\n");
i--;
continue;
}
#else
- cy_pci_addr2 = (ulong) ioremap(cy_pci_addr2, CyPCI_Ywin);
+ cy_pci_addr0 = (ulong)ioremap(cy_pci_addr0, CyPCI_Yctl);
+ cy_pci_addr2 = (ulong)ioremap(cy_pci_addr2, CyPCI_Ywin);
#endif
#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI: relocate winaddr=0x%lx ioaddr=0x%lx\n",
- (u_long)cy_pci_addr2, (u_long)cy_pci_addr1);
+ printk("Cyclom-Y/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
+ (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
#endif
cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
cyy_init_card((volatile ucchar *)cy_pci_addr2, 1));
@@ -4652,7 +4655,7 @@ cy_detect_pci(void))
/* set cy_card */
cy_card[j].base_addr = (ulong)cy_pci_addr2;
- cy_card[j].ctl_addr = 0;
+ cy_card[j].ctl_addr = (ulong)cy_pci_addr0;
cy_card[j].irq = (int) cy_pci_irq;
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
@@ -4664,20 +4667,16 @@ cy_detect_pci(void))
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);
+ cy_writew(cy_pci_addr0+0x4c,
+ cy_readw(cy_pci_addr0+0x4c)|0x0040);
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);
+ cy_writew(cy_pci_addr0+0x68,
+ cy_readw(cy_pci_addr0+0x68)|0x0900);
break;
}
@@ -4712,20 +4711,14 @@ cy_detect_pci(void))
#endif
cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
#if !defined(__alpha__)
- cy_pci_addr0 = (unsigned int) ioremap(
- cy_pci_addr0 & PAGE_MASK,
- PAGE_ALIGN(CyPCI_Zctl))
- + (cy_pci_addr0 & (PAGE_SIZE-1));
+ cy_pci_addr0 = (ulong)ioremap(cy_pci_addr0, CyPCI_Zctl);
#endif
mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *)
cy_pci_addr0)->mail_box_0);
cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
if (mailbox == ZE_V1) {
#if !defined(__alpha__)
- cy_pci_addr2 = (unsigned int) ioremap(
- cy_pci_addr2 & PAGE_MASK,
- PAGE_ALIGN(CyPCI_Ze_win))
- + (cy_pci_addr2 & (PAGE_SIZE-1));
+ cy_pci_addr2 = (ulong)ioremap(cy_pci_addr2, CyPCI_Ze_win);
#endif
if (ZeIndex == NR_CARDS) {
printk("Cyclades-Ze/PCI found at 0x%lx ",
@@ -4741,10 +4734,7 @@ cy_detect_pci(void))
continue;
} else {
#if !defined(__alpha__)
- cy_pci_addr2 = (unsigned int) ioremap(
- cy_pci_addr2 & PAGE_MASK,
- PAGE_ALIGN(CyPCI_Zwin))
- + (cy_pci_addr2 & (PAGE_SIZE-1));
+ cy_pci_addr2 = (ulong)ioremap(cy_pci_addr2, CyPCI_Zwin);
#endif
}
@@ -4952,7 +4942,6 @@ show_version(void)
__DATE__, __TIME__);
} /* show_version */
-#ifdef CONFIG_PROC_FS
static int
cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
int *eof, void *data)
@@ -5009,7 +4998,6 @@ done:
len = 0;
return len;
}
-#endif
/* The serial driver boot-time initialization code!
@@ -5281,15 +5269,8 @@ cy_init(void))
#endif
}
-#ifdef CONFIG_PROC_FS
ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0);
ent->read_proc = cyclades_get_proc_info;
-#endif
-#if 0
-#ifdef CONFIG_PROC_FS
- proc_register(&proc_root, &cyclades_proc_entry);
-#endif
-#endif
return 0;
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index f4224bd55..8f3ae96e2 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -286,7 +286,8 @@ int pc_init(void);
#ifdef ENABLE_PCI
static int init_PCI(int);
-static int get_PCI_configuration(char, char, unsigned int *, unsigned int *,
+static int get_PCI_configuration(unsigned char, unsigned char,
+ unsigned int *, unsigned int *,
unsigned int *, unsigned int *,
unsigned int *, unsigned int *);
#endif /* ENABLE_PCI */
@@ -2362,10 +2363,10 @@ static void doevent(int crd)
eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));
}
- /* Get the channel the event occured on */
+ /* Get the channel the event occurred on */
channel = eventbuf[0];
- /* Get the actual event code that occured */
+ /* Get the actual event code that occurred */
event = eventbuf[1];
/* ----------------------------------------------------------------
@@ -4037,7 +4038,7 @@ void epca_setup(char *str, int *ints)
#ifdef ENABLE_PCI
/* --------------------- Begin get_PCI_configuration ---------------------- */
-int get_PCI_configuration(char bus, char device_fn,
+int get_PCI_configuration(unsigned char bus, unsigned char device_fn,
unsigned int *base_addr0, unsigned int *base_addr1,
unsigned int *base_addr2, unsigned int *base_addr3,
unsigned int *base_addr4, unsigned int *base_addr5)
diff --git a/drivers/char/ftape/RELEASE-NOTES b/drivers/char/ftape/RELEASE-NOTES
index dcc250808..03799dbc0 100644
--- a/drivers/char/ftape/RELEASE-NOTES
+++ b/drivers/char/ftape/RELEASE-NOTES
@@ -423,9 +423,7 @@ Another simple bugfix version.
This release is a simple bugfix version.
-- Linux/SMP: ftape *should* work, if you remember to add the symbol __SMP__
- to the Makefile (you know what I'm talking about, if you're playing with
- Linux/SMP :).
+- Linux/SMP: ftape *should* work.
- FC-10/20: Only accepts IRQs 3-7, or 9. If IRQ 9, properly tell the card
to use IRQ 2. Thanks to Greg Crider (gcrider@iclnet.org) for finding and
locating this bug and testing the patch.
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index 9fb9269f8..6890df0fa 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -1348,21 +1348,12 @@ int fdc_grab_irq_and_dma(void)
if (fdc.hook == &do_ftape) {
/* Get fast interrupt handler.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70)
if (request_irq(fdc.irq, ftape_interrupt,
SA_INTERRUPT, "ft", ftape_id)) {
TRACE_ABORT(-EIO, ft_t_bug,
"Unable to grab IRQ%d for ftape driver",
fdc.irq);
}
-#else
- if (request_irq(fdc.irq, ftape_interrupt, SA_INTERRUPT,
- ftape_id)) {
- TRACE_ABORT(-EIO, ft_t_bug,
- "Unable to grab IRQ%d for ftape driver",
- fdc.irq);
- }
-#endif
if (request_dma(fdc.dma, ftape_id)) {
#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70)
free_irq(fdc.irq, ftape_id);
@@ -1373,7 +1364,6 @@ int fdc_grab_irq_and_dma(void)
"Unable to grab DMA%d for ftape driver",
fdc.dma);
}
- enable_irq(fdc.irq);
}
if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {
/* Using same dma channel or irq as standard fdc, need
@@ -1395,12 +1385,7 @@ int fdc_release_irq_and_dma(void)
if (fdc.hook == &do_ftape) {
disable_dma(fdc.dma); /* just in case... */
free_dma(fdc.dma);
- disable_irq(fdc.irq);
-#if LINUX_VERSION_CODE >= KERNEL_VER(1,3,70)
free_irq(fdc.irq, ftape_id);
-#else
- free_irq(fdc.irq);
-#endif
}
if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) {
/* Using same dma channel as standard fdc, need to
diff --git a/drivers/char/hfmodem/Config.in b/drivers/char/hfmodem/Config.in
index a23281f3e..9d2799adb 100644
--- a/drivers/char/hfmodem/Config.in
+++ b/drivers/char/hfmodem/Config.in
@@ -1,5 +1,5 @@
comment 'Misc. hamradio protocols'
-tristate 'Shortwave radio modem driver' CONFIG_HFMODEM
+dep_tristate 'Shortwave radio modem driver' CONFIG_HFMODEM $CONFIG_PARPORT
if [ "$CONFIG_HFMODEM" != "n" ]; then
bool ' HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC
bool ' HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS
diff --git a/drivers/char/hfmodem/main.c b/drivers/char/hfmodem/main.c
index d940bd232..20347f32c 100644
--- a/drivers/char/hfmodem/main.c
+++ b/drivers/char/hfmodem/main.c
@@ -601,7 +601,7 @@ MODULE_PARM_DESC(dma, "dma number (>=4 for SB16/32/64/etc, <=3 for the rest)");
MODULE_PARM(serio, "i");
MODULE_PARM_DESC(serio, "address of serial port to output PTT");
MODULE_PARM(pario, "i");
-MODULE_PARM_DESC(pario, "address of parial port to output PTT");
+MODULE_PARM_DESC(pario, "address of parallel port to output PTT");
MODULE_PARM(midiio, "i");
MODULE_PARM_DESC(midiio, "address of midi (MPU401) port to output PTT");
diff --git a/drivers/char/i2c.c b/drivers/char/i2c.c
index 851929e94..c85b95bc3 100644
--- a/drivers/char/i2c.c
+++ b/drivers/char/i2c.c
@@ -24,9 +24,11 @@ static int scan = 0;
static int verbose = 0;
static int i2c_debug = 0;
+#if LINUX_VERSION_CODE >= 0x020117
MODULE_PARM(scan,"i");
MODULE_PARM(verbose,"i");
MODULE_PARM(i2c_debug,"i");
+#endif
/* ----------------------------------------------------------------------- */
@@ -34,8 +36,10 @@ static struct i2c_bus *busses[I2C_BUS_MAX];
static struct i2c_driver *drivers[I2C_DRIVER_MAX];
static int bus_count = 0, driver_count = 0;
+#ifdef CONFIG_VIDEO_BT848
extern int i2c_tuner_init(void);
extern int msp3400c_init(void);
+#endif
int i2c_init(void)
{
@@ -53,10 +57,10 @@ int i2c_init(void)
static void i2c_attach_device(struct i2c_bus *bus, struct i2c_driver *driver)
{
- unsigned long flags;
struct i2c_device *device;
int i,j,ack=1;
unsigned char addr;
+ LOCK_FLAGS;
/* probe for device */
LOCK_I2C_BUS(bus);
@@ -148,8 +152,8 @@ static void i2c_detach_device(struct i2c_device *device)
int i2c_register_bus(struct i2c_bus *bus)
{
- unsigned long flags;
int i,ack;
+ LOCK_FLAGS;
memset(bus->devices,0,sizeof(bus->devices));
bus->devcount = 0;
@@ -410,6 +414,7 @@ int i2c_write(struct i2c_bus *bus, unsigned char addr,
#ifdef MODULE
+#if LINUX_VERSION_CODE >= 0x020100
EXPORT_SYMBOL(i2c_register_bus);
EXPORT_SYMBOL(i2c_unregister_bus);
EXPORT_SYMBOL(i2c_register_driver);
@@ -424,7 +429,7 @@ EXPORT_SYMBOL(i2c_sendbyte);
EXPORT_SYMBOL(i2c_readbyte);
EXPORT_SYMBOL(i2c_read);
EXPORT_SYMBOL(i2c_write);
-
+#endif
int init_module(void)
{
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
new file mode 100644
index 000000000..58ce881b3
--- /dev/null
+++ b/drivers/char/isicom.c
@@ -0,0 +1,1951 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Original driver code supplied by Multi-Tech
+ *
+ * Changes
+ * 1/9/98 alan@redhat.com Merge to 2.0.x kernel tree
+ * Obtain and use official major/minors
+ * Loader switched to a misc device
+ * (fixed range check bug as a side effect)
+ * Printk clean up
+ * 9/12/98 alan@redhat.com Rough port to 2.1.x
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/termios.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/isicom.h>
+
+static int isicom_refcount = 0;
+static int prev_card = 3; /* start servicing isi_card[0] */
+static struct isi_board * irq_to_board[16] = { NULL, };
+static struct tty_driver isicom_normal, isicom_callout;
+static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, };
+static struct termios * isicom_termios[PORT_COUNT] = { NULL, };
+static struct termios * isicom_termios_locked[PORT_COUNT] = { NULL, };
+
+static struct isi_board isi_card[BOARD_COUNT];
+static struct isi_port isi_ports[PORT_COUNT];
+
+DECLARE_TASK_QUEUE(tq_isicom);
+
+static struct timer_list tx;
+static char re_schedule = 1;
+#ifdef ISICOM_DEBUG
+static unsigned long tx_count = 0;
+#endif
+
+static int ISILoad_open(struct inode *inode, struct file *filp);
+static int ISILoad_release(struct inode *inode, struct file *filp);
+static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
+
+static void isicom_tx(unsigned long _data);
+static void isicom_start(struct tty_struct * tty);
+
+static unsigned char * tmp_buf = 0;
+static struct semaphore tmp_buf_sem = MUTEX;
+
+/* baud index mappings from linux defns to isi */
+
+static char linuxb_to_isib[] = {
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17,
+ 18, 19
+};
+
+/*
+ * Firmware loader driver specific routines
+ *
+ */
+
+static struct file_operations ISILoad_fops = {
+ NULL, /* lseek */
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ ISILoad_ioctl,
+ NULL, /* mmap */
+ ISILoad_open,
+ NULL, /* flush */
+ ISILoad_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+};
+
+struct miscdevice isiloader_device = {
+ ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops
+};
+
+
+extern inline int WaitTillCardIsFree(unsigned short base)
+{
+ unsigned long count=0;
+ while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));
+ if (inw(base+0xe)&0x1)
+ return 0;
+ else
+ return 1;
+}
+
+static int ISILoad_open(struct inode *inode, struct file *filp)
+{
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n");
+#endif
+ return 0;
+}
+
+static int ISILoad_release(struct inode *inode, struct file *filp)
+{
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",);
+#endif
+ return 0;
+}
+
+static int ISILoad_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int card, i, j, signature, status;
+ unsigned short word_count, base;
+ bin_frame frame;
+ /* exec_record exec_rec; */
+
+ if(get_user(card, (int *)arg))
+ return -EFAULT;
+
+ if(card < 0 || card >= BOARD_COUNT)
+ return -ENXIO;
+
+ base=isi_card[card].base;
+
+ if(base==0)
+ return -ENXIO; /* disabled or not used */
+
+ switch(cmd) {
+ case MIOCTL_RESET_CARD:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base);
+
+ inw(base+0x8);
+
+ for(i=jiffies+HZ/100;time_before(jiffies, i););
+
+ outw(0,base+0x8); /* Reset */
+
+ for(j=1;j<=3;j++) {
+ for(i=jiffies+HZ;time_before(jiffies, i););
+ printk(".");
+ }
+ signature=(inw(base+0x4)) & 0xff;
+
+ if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {
+#ifdef ISICOM_DEBUG
+ printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));
+#endif
+ printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
+ return -EIO;
+ }
+
+ switch(signature) {
+ case 0xa5:
+ case 0xbb:
+ case 0xdd: isi_card[card].port_count = 8;
+ isi_card[card].shift_count = 12;
+ break;
+
+ case 0xcc: isi_card[card].port_count = 16;
+ isi_card[card].shift_count = 11;
+ break;
+
+ default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);
+#ifdef ISICOM_DEBUG
+ printk("Sig=0x%x\n",signature);
+#endif
+ return -EIO;
+ }
+ printk("-Done\n");
+ return put_user(signature,(unsigned int*)arg);
+
+ case MIOCTL_LOAD_FIRMWARE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if(copy_from_user(&frame, (void *) arg, sizeof(bin_frame)))
+ return -EFAULT;
+
+ if (WaitTillCardIsFree(base))
+ return -EIO;
+
+ outw(0xf0,base); /* start upload sequence */
+ outw(0x00,base);
+ outw((frame.addr), base);/* lsb of adderess */
+
+ word_count=(frame.count >> 1) + frame.count % 2;
+ outw(word_count, base);
+ InterruptTheCard(base);
+
+ for(i=0;i<=0x2f;i++); /* a wee bit of delay */
+
+ if (WaitTillCardIsFree(base))
+ return -EIO;
+
+ if ((status=inw(base+0x4))!=0) {
+ printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
+ card+1, frame.addr, frame.count, status);
+ return -EIO;
+ }
+ outsw(base, (void *) frame.bin_data, word_count);
+
+ InterruptTheCard(base);
+
+ for(i=0;i<=0x0f;i++); /* another wee bit of delay */
+
+ if (WaitTillCardIsFree(base))
+ return -EIO;
+
+ if ((status=inw(base+0x4))!=0) {
+ printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status);
+ return -EIO;
+ }
+ return 0;
+
+ case MIOCTL_READ_FIRMWARE:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if(copy_from_user(&frame, (void *) arg, sizeof(bin_header)))
+ return -EFAULT;
+
+ if (WaitTillCardIsFree(base))
+ return -EIO;
+
+ outw(0xf1,base); /* start download sequence */
+ outw(0x00,base);
+ outw((frame.addr), base);/* lsb of adderess */
+
+ word_count=(frame.count >> 1) + frame.count % 2;
+ outw(word_count+1, base);
+ InterruptTheCard(base);
+
+ for(i=0;i<=0xf;i++); /* a wee bit of delay */
+
+ if (WaitTillCardIsFree(base))
+ return -EIO;
+
+ if ((status=inw(base+0x4))!=0) {
+ printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n",
+ card+1, frame.addr, frame.count, status);
+ return -EIO;
+ }
+
+ inw(base);
+ insw(base, frame.bin_data, word_count);
+ InterruptTheCard(base);
+
+ for(i=0;i<=0x0f;i++); /* another wee bit of delay */
+
+ if (WaitTillCardIsFree(base))
+ return -EIO;
+
+ if ((status=inw(base+0x4))!=0) {
+ printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status);
+ return -EIO;
+ }
+
+ if(copy_to_user((void *) arg, &frame, sizeof(bin_frame)))
+ return -EFAULT;
+ return 0;
+
+ case MIOCTL_XFER_CTRL:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (WaitTillCardIsFree(base))
+ return -EIO;
+
+ outw(0xf2, base);
+ outw(0x800, base);
+ outw(0x0, base);
+ outw(0x0, base);
+ InterruptTheCard(base);
+
+ isi_card[card].status |= FIRMWARE_LOADED;
+ return 0;
+
+ default:
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd);
+#endif
+ return -ENOIOCTLCMD;
+
+ }
+
+}
+
+
+/*
+ * ISICOM Driver specific routines ...
+ *
+ */
+
+static inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev,
+ const char * routine)
+{
+#ifdef ISICOM_DEBUG
+ static const char * badmagic =
+ KERN_WARNING "ISICOM: Warning: bad isicom magic for dev %s in %s.\n";
+ static const char * badport =
+ KERN_WARNING "ISICOM: Warning: NULL isicom port for dev %s in %s.\n";
+ if (!port) {
+ printk(badport, kdevname(dev), routine);
+ return 1;
+ }
+ if (port->magic != ISICOM_MAGIC) {
+ printk(badmagic, kdevname(dev), routine);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+extern inline void schedule_bh(struct isi_port * port)
+{
+ queue_task(&port->bh_tqueue, &tq_isicom);
+ mark_bh(ISICOM_BH);
+}
+
+/* Transmitter */
+
+static void isicom_tx(unsigned long _data)
+{
+ short count = (BOARD_COUNT-1), card, base;
+ short txcount, wait, wrd, residue, word_count, cnt;
+ struct isi_port * port;
+ struct tty_struct * tty;
+ unsigned long flags;
+
+#ifdef ISICOM_DEBUG
+ ++tx_count;
+#endif
+
+ /* find next active board */
+ card = (prev_card + 1) & 0x0003;
+ while(count-- > 0) {
+ if (isi_card[card].status & BOARD_ACTIVE)
+ break;
+ card = (card + 1) & 0x0003;
+ }
+ if (!(isi_card[card].status & BOARD_ACTIVE))
+ goto sched_again;
+
+ prev_card = card;
+
+ count = isi_card[card].port_count;
+ port = isi_card[card].ports;
+ base = isi_card[card].base;
+ for (;count > 0;count--, port++) {
+ /* port not active or tx disabled to force flow control */
+ if (!(port->status & ISI_TXOK))
+ continue;
+
+ tty = port->tty;
+ save_flags(flags); cli();
+ txcount = MIN(TX_SIZE, port->xmit_cnt);
+ if ((txcount <= 0) || tty->stopped || tty->hw_stopped) {
+ restore_flags(flags);
+ continue;
+ }
+ wait = 200;
+ while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));
+ if (wait <= 0) {
+ restore_flags(flags);
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: isicom_tx:Card(0x%x) found busy.\n",
+ card);
+#endif
+ continue;
+ }
+ if (!(inw(base + 0x02) & (1 << port->channel))) {
+ restore_flags(flags);
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: isicom_tx: cannot tx to 0x%x:%d.\n",
+ base, port->channel + 1);
+#endif
+ continue;
+ }
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: txing %d bytes, port%d.\n",
+ txcount, port->channel+1);
+#endif
+ outw((port->channel << isi_card[card].shift_count) | txcount
+ , base);
+ residue = NO;
+ wrd = 0;
+ while (1) {
+ cnt = MIN(txcount, (SERIAL_XMIT_SIZE - port->xmit_tail));
+ if (residue == YES) {
+ residue = NO;
+ if (cnt > 0) {
+ wrd |= (port->xmit_buf[port->xmit_tail] << 8);
+ port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+ port->xmit_cnt--;
+ txcount--;
+ cnt--;
+ outw(wrd, base);
+ }
+ else {
+ outw(wrd, base);
+ break;
+ }
+ }
+ if (cnt <= 0) break;
+ word_count = cnt >> 1;
+ outsw(base, port->xmit_buf+port->xmit_tail, word_count);
+ port->xmit_tail = (port->xmit_tail + (word_count << 1)) &
+ (SERIAL_XMIT_SIZE - 1);
+ txcount -= (word_count << 1);
+ port->xmit_cnt -= (word_count << 1);
+ if (cnt & 0x0001) {
+ residue = YES;
+ wrd = port->xmit_buf[port->xmit_tail];
+ port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+ port->xmit_cnt--;
+ txcount--;
+ }
+ }
+/*
+ * Replaced the code below with hopefully a faster loop - sameer
+ */
+
+/*
+ while (1) {
+ wrd = port->xmit_buf[port->xmit_tail++];
+ port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+ port->xmit_cnt--;
+ if (--txcount > 0) {
+ wrd |= (port->xmit_buf[port->xmit_tail++] << 8);
+ port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);
+ port->xmit_cnt--;
+ outw(wrd, base);
+ if (--txcount <= 0) break;
+ }
+ else {
+ outw(wrd, base);
+ break;
+ }
+ }
+*/
+ InterruptTheCard(base);
+ if (port->xmit_cnt <= 0)
+ port->status &= ~ISI_TXOK;
+ if (port->xmit_cnt <= WAKEUP_CHARS)
+ schedule_bh(port);
+ restore_flags(flags);
+ }
+
+ /* schedule another tx for hopefully in about 10ms */
+sched_again:
+ if (!re_schedule)
+ return;
+ init_timer(&tx);
+ tx.expires = jiffies + HZ/100;
+ tx.data = 0;
+ tx.function = isicom_tx;
+ add_timer(&tx);
+
+ return;
+}
+
+/* Interrupt handlers */
+
+static void do_isicom_bh(void)
+{
+ run_task_queue(&tq_isicom);
+}
+
+
+
+static void isicom_bottomhalf(void * data)
+{
+ struct isi_port * port = (struct isi_port *) data;
+ struct tty_struct * tty = port->tty;
+
+ if (!tty)
+ return;
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+}
+
+/* main interrupt handler routine */
+static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+{
+ struct isi_board * card;
+ struct isi_port * port;
+ struct tty_struct * tty;
+ unsigned short base, header, word_count, count;
+ unsigned char channel;
+ short byte_count;
+
+ card = irq_to_board[irq];
+ if (!card || !(card->status & FIRMWARE_LOADED)) {
+ printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);
+ return;
+ }
+ base = card->base;
+
+ inw(base); /* get the dummy word out */
+ header = inw(base);
+ channel = (header & 0x7800) >> card->shift_count;
+ byte_count = header & 0xff;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM:Intr:(0x%x:%d).\n", base, channel+1);
+#endif
+ if ((channel+1) > card->port_count) {
+ printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n",
+ base, channel+1);
+ ClearInterrupt(base);
+ return;
+ }
+ port = card->ports + channel;
+ if (!(port->flags & ASYNC_INITIALIZED)) {
+ ClearInterrupt(base);
+ return;
+ }
+
+ tty = port->tty;
+
+ if (header & 0x8000) { /* Status Packet */
+ header = inw(base);
+ switch(header & 0xff) {
+ case 0: /* Change in EIA signals */
+
+ if (port->flags & ASYNC_CHECK_CD) {
+ if (port->status & ISI_DCD) {
+ if (!(header & ISI_DCD)) {
+ /* Carrier has been lost */
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n");
+#endif
+ port->status &= ~ISI_DCD;
+ if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->flags & ASYNC_CALLOUT_NOHUP)))
+ queue_task(&port->hangup_tq,
+ &tq_scheduler);
+ }
+ }
+ else {
+ if (header & ISI_DCD) {
+ /* Carrier has been detected */
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: interrupt: DCD->high.\n");
+#endif
+ port->status |= ISI_DCD;
+ wake_up_interruptible(&port->open_wait);
+ }
+ }
+ }
+ else {
+ if (header & ISI_DCD)
+ port->status |= ISI_DCD;
+ else
+ port->status &= ~ISI_DCD;
+ }
+
+ if (port->flags & ASYNC_CTS_FLOW) {
+ if (port->tty->hw_stopped) {
+ if (header & ISI_CTS) {
+ port->tty->hw_stopped = 0;
+ /* start tx ing */
+ port->status |= (ISI_TXOK | ISI_CTS);
+ schedule_bh(port);
+ }
+ }
+ else {
+ if (!(header & ISI_CTS)) {
+ port->tty->hw_stopped = 1;
+ /* stop tx ing */
+ port->status &= ~(ISI_TXOK | ISI_CTS);
+ }
+ }
+ }
+ else {
+ if (header & ISI_CTS)
+ port->status |= ISI_CTS;
+ else
+ port->status &= ~ISI_CTS;
+ }
+
+ if (header & ISI_DSR)
+ port->status |= ISI_DSR;
+ else
+ port->status &= ~ISI_DSR;
+
+ if (header & ISI_RI)
+ port->status |= ISI_RI;
+ else
+ port->status &= ~ISI_RI;
+
+ break;
+
+ case 1: /* Received Break !!! */
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ break;
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ /* dunno if this is right */
+ *tty->flip.char_buf_ptr++ = 0;
+ tty->flip.count++;
+ if (port->flags & ASYNC_SAK)
+ do_SAK(tty);
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ break;
+
+ case 2: /* Statistics */
+ printk(KERN_DEBUG "ISICOM: isicom_interrupt: stats!!!.\n");
+ break;
+
+ default:
+ printk(KERN_WARNING "ISICOM: Intr: Unknown code in status packet.\n");
+ break;
+ }
+ }
+ else { /* Data Packet */
+ count = MIN(byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count));
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n",
+ count, byte_count);
+#endif
+ word_count = count >> 1;
+ insw(base, tty->flip.char_buf_ptr, word_count);
+ tty->flip.char_buf_ptr += (word_count << 1);
+ byte_count -= (word_count << 1);
+ if (count & 0x0001) {
+ *tty->flip.char_buf_ptr++ = (char)(inw(base) & 0xff);
+ byte_count -= 2;
+ }
+ memset(tty->flip.flag_buf_ptr, 0, count);
+ tty->flip.flag_buf_ptr += count;
+ tty->flip.count += count;
+
+ if (byte_count > 0) {
+ printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n",
+ base, channel+1);
+ while(byte_count > 0) { /* drain out unread xtra data */
+ inw(base);
+ byte_count -= 2;
+ }
+ }
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ }
+ ClearInterrupt(base);
+ return;
+}
+
+ /* called with interrupts disabled */
+static void isicom_config_port(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ struct tty_struct * tty;
+ unsigned long baud;
+ unsigned short channel_setup, wait, base = card->base;
+ unsigned short channel = port->channel, shift_count = card->shift_count;
+ unsigned char flow_ctrl;
+
+ if (!(tty = port->tty) || !tty->termios)
+ return;
+ baud = C_BAUD(tty);
+ if (baud & CBAUDEX) {
+ baud &= ~CBAUDEX;
+
+ /* if CBAUDEX bit is on and the baud is set to either 50 or 75
+ * then the card is programmed for 57.6Kbps or 115Kbps
+ * respectively.
+ */
+
+ if (baud < 1 || baud > 2)
+ port->tty->termios->c_cflag &= ~CBAUDEX;
+ else
+ baud += 15;
+ }
+ if (baud == 15) {
+
+ /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
+ * by the set_serial_info ioctl ... this is done by
+ * the 'setserial' utility.
+ */
+
+ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ baud++; /* 57.6 Kbps */
+ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ baud +=2; /* 115 Kbps */
+ }
+ if (linuxb_to_isib[baud] == -1) {
+ /* hang up */
+ drop_dtr(port);
+ return;
+ }
+ else
+ raise_dtr(port);
+
+ wait = 100;
+ while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));
+ if (!wait) {
+ printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at channel setup.\n");
+ return;
+ }
+ outw(0x8000 | (channel << shift_count) |0x03, base);
+ outw(linuxb_to_isib[baud] << 8 | 0x03, base);
+ channel_setup = 0;
+ switch(C_CSIZE(tty)) {
+ case CS5:
+ channel_setup |= ISICOM_CS5;
+ break;
+ case CS6:
+ channel_setup |= ISICOM_CS6;
+ break;
+ case CS7:
+ channel_setup |= ISICOM_CS7;
+ break;
+ case CS8:
+ channel_setup |= ISICOM_CS8;
+ break;
+ }
+
+ if (C_CSTOPB(tty))
+ channel_setup |= ISICOM_2SB;
+
+ if (C_PARENB(tty))
+ channel_setup |= ISICOM_EVPAR;
+ if (C_PARODD(tty))
+ channel_setup |= ISICOM_ODPAR;
+ outw(channel_setup, base);
+ InterruptTheCard(base);
+
+ if (C_CLOCAL(tty))
+ port->flags &= ~ASYNC_CHECK_CD;
+ else
+ port->flags |= ASYNC_CHECK_CD;
+
+ /* flow control settings ...*/
+ flow_ctrl = 0;
+ port->flags &= ~ASYNC_CTS_FLOW;
+ if (C_CRTSCTS(tty)) {
+ port->flags |= ASYNC_CTS_FLOW;
+ flow_ctrl |= ISICOM_CTSRTS;
+ }
+ if (I_IXON(tty))
+ flow_ctrl |= ISICOM_RESPOND_XONXOFF;
+ if (I_IXOFF(tty))
+ flow_ctrl |= ISICOM_INITIATE_XONXOFF;
+
+ wait = 100;
+ while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));
+ if (!wait) {
+ printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at flow setup.\n");
+ return;
+ }
+ outw(0x8000 | (channel << shift_count) |0x04, base);
+ outw(flow_ctrl << 8 | 0x05, base);
+ outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
+ InterruptTheCard(base);
+
+ /* rx enabled -> enable port for rx on the card */
+ if (C_CREAD(tty)) {
+ card->port_status |= (1 << channel);
+ outw(card->port_status, base + 0x02);
+ }
+
+}
+
+/* open et all */
+
+extern inline void isicom_setup_board(struct isi_board * bp)
+{
+ int channel;
+ struct isi_port * port;
+ unsigned long flags;
+
+ if (bp->status & BOARD_ACTIVE)
+ return;
+ port = bp->ports;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts start, port_count %d...\n", bp->port_count);
+#endif
+ for(channel = 0; channel < bp->port_count; channel++, port++) {
+ save_flags(flags); cli();
+ drop_dtr_rts(port);
+ restore_flags(flags);
+ }
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts stop...\n");
+#endif
+
+ bp->status |= BOARD_ACTIVE;
+ MOD_INC_USE_COUNT;
+ return;
+}
+
+static int isicom_setup_port(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ unsigned long flags;
+
+ if (port->flags & ASYNC_INITIALIZED)
+ return 0;
+ if (!port->xmit_buf) {
+ unsigned long page;
+
+ if (!(page = get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ if (port->xmit_buf) {
+ free_page(page);
+ return -ERESTARTSYS;
+ }
+ port->xmit_buf = (unsigned char *) page;
+ }
+ save_flags(flags); cli();
+ if (port->tty)
+ clear_bit(TTY_IO_ERROR, &port->tty->flags);
+ if (port->count == 1)
+ card->count++;
+
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+
+ /* discard any residual data */
+ kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX);
+
+ isicom_config_port(port);
+ port->flags |= ASYNC_INITIALIZED;
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port)
+{
+ int do_clocal = 0, retval;
+ struct wait_queue wait = { current, NULL };
+
+ /* block if port is in the process of being closed */
+
+ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: block_til_ready: close in progress.\n");
+#endif
+ interruptible_sleep_on(&port->close_wait);
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+ }
+
+ /* trying to open a callout device... check for constraints */
+
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: bl_ti_rdy: callout open.\n");
+#endif
+ if (port->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->flags & ASYNC_SESSION_LOCKOUT) &&
+ (port->session != current->session))
+ return -EBUSY;
+
+ if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (port->flags & ASYNC_PGRP_LOCKOUT) &&
+ (port->pgrp != current->pgrp))
+ return -EBUSY;
+ port->flags |= ASYNC_CALLOUT_ACTIVE;
+ cli();
+ raise_dtr_rts(port);
+ sti();
+ return 0;
+ }
+
+ /* if non-blocking mode is set ... */
+
+ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n");
+#endif
+ if (port->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (port->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (port->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (C_CLOCAL(tty))
+ do_clocal = 1;
+ }
+#ifdef ISICOM_DEBUG
+ if (do_clocal)
+ printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n");
+#endif
+
+ /* block waiting for DCD to be asserted, and while
+ callout dev is busy */
+ retval = 0;
+ add_wait_queue(&port->open_wait, &wait);
+ cli();
+ if (!tty_hung_up_p(filp))
+ port->count--;
+ sti();
+ port->blocked_open++;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: block_til_ready: waiting for DCD...\n");
+#endif
+ while (1) {
+ cli();
+ if (!(port->flags & ASYNC_CALLOUT_ACTIVE))
+ raise_dtr_rts(port);
+
+ sti();
+ current->state = TASK_INTERRUPTIBLE;
+ if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+ if (port->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: block_til_ready: tty_hung_up_p || not init.\n");
+#endif
+ break;
+ }
+ if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(port->flags & ASYNC_CLOSING) &&
+ (do_clocal || (port->status & ISI_DCD))) {
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n");
+#endif
+ break;
+ }
+ if (signal_pending(current)) {
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: block_til_ready: sig blocked.\n");
+#endif
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&port->open_wait, &wait);
+ if (!tty_hung_up_p(filp))
+ port->count++;
+ port->blocked_open--;
+ if (retval)
+ return retval;
+ port->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static int isicom_open(struct tty_struct * tty, struct file * filp)
+{
+ struct isi_port * port;
+ struct isi_board * card;
+ unsigned int line, board;
+ unsigned long flags;
+ int error;
+
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: open start!!!.\n");
+#endif
+ line = MINOR(tty->device) - tty->driver.minor_start;
+
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "line = %d.\n", line);
+#endif
+
+ if ((line < 0) || (line > (PORT_COUNT-1)))
+ return -ENODEV;
+ board = BOARD(line);
+
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "board = %d.\n", board);
+#endif
+
+ card = &isi_card[board];
+ if (!(card->status & FIRMWARE_LOADED)) {
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board);
+#endif
+ return -ENODEV;
+ }
+
+ /* open on higher 8 dev files on a 8 port card !!! */
+ if (card->port_count == 8)
+ if (line > ((board * 16)+7)) {
+ printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n");
+ return -ENODEV;
+ }
+ port = &isi_ports[line];
+ if (isicom_paranoia_check(port, tty->device, "isicom_open"))
+ return -ENODEV;
+
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n");
+#endif
+ isicom_setup_board(card);
+
+ port->count++;
+ tty->driver_data = port;
+ port->tty = tty;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n");
+#endif
+ if ((error = isicom_setup_port(port))!=0)
+ return error;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: block_til_ready ...\n");
+#endif
+ if ((error = block_til_ready(tty, filp, port))!=0)
+ return error;
+
+ if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = port->normal_termios;
+ else
+ *tty->termios = port->callout_termios;
+ save_flags(flags); cli();
+ isicom_config_port(port);
+ restore_flags(flags);
+ }
+
+ port->session = current->session;
+ port->pgrp = current->pgrp;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: open end!!!.\n");
+#endif
+ return 0;
+}
+
+/* close et all */
+
+extern inline void isicom_shutdown_board(struct isi_board * bp)
+{
+ int channel;
+ struct isi_port * port;
+
+ if (!(bp->status & BOARD_ACTIVE))
+ return;
+ bp->status &= ~BOARD_ACTIVE;
+ port = bp->ports;
+ for(channel = 0; channel < bp->port_count; channel++, port++) {
+ drop_dtr_rts(port);
+ }
+ MOD_DEC_USE_COUNT;
+}
+
+static void isicom_shutdown_port(struct isi_port * port)
+{
+ struct isi_board * card = port->card;
+ struct tty_struct * tty;
+
+ if (!(port->flags & ASYNC_INITIALIZED))
+ return;
+ if (port->xmit_buf) {
+ free_page((unsigned long) port->xmit_buf);
+ port->xmit_buf = NULL;
+ }
+ if (!(tty = port->tty) || C_HUPCL(tty))
+ /* drop dtr on this port */
+ drop_dtr(port);
+
+ /* any other port uninits */
+
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
+ port->flags &= ~ASYNC_INITIALIZED;
+
+ if (--card->count < 0) {
+ printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n",
+ card->base, card->count);
+ card->count = 0;
+ }
+
+ /* last port was closed , shutdown that boad too */
+ if (!card->count)
+ isicom_shutdown_board(card);
+}
+
+static void isicom_close(struct tty_struct * tty, struct file * filp)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_board * card = port->card;
+ unsigned long flags;
+
+ if (!port)
+ return;
+ if (isicom_paranoia_check(port, tty->device, "isicom_close"))
+ return;
+
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: Close start!!!.\n");
+#endif
+
+ save_flags(flags); cli();
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+ if ((tty->count == 1) && (port->count != 1)) {
+ printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count"
+ "tty->count = 1 port count = %d.\n",
+ card->base, port->count);
+ port->count = 1;
+ }
+ if (--port->count < 0) {
+ printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for"
+ "channel%d = %d", card->base, port->channel,
+ port->count);
+ port->count = 0;
+ }
+
+ if (port->count) {
+ restore_flags(flags);
+ return;
+ }
+ port->flags |= ASYNC_CLOSING;
+ /*
+ * save termios struct since callout and dialin termios may be
+ * different.
+ */
+ if (port->flags & ASYNC_NORMAL_ACTIVE)
+ port->normal_termios = *tty->termios;
+ if (port->flags & ASYNC_CALLOUT_ACTIVE)
+ port->callout_termios = *tty->termios;
+
+ tty->closing = 1;
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, port->closing_wait);
+ /* indicate to the card that no more data can be received
+ on this port */
+ if (port->flags & ASYNC_INITIALIZED) {
+ card->port_status &= ~(1 << port->channel);
+ outw(card->port_status, card->base + 0x02);
+ }
+ isicom_shutdown_port(port);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ port->tty = 0;
+ if (port->blocked_open) {
+ if (port->close_delay) {
+ current->state = TASK_INTERRUPTIBLE;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: scheduling until time out.\n");
+#endif
+ schedule_timeout(port->close_delay);
+ }
+ wake_up_interruptible(&port->open_wait);
+ }
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
+ ASYNC_CLOSING);
+ wake_up_interruptible(&port->close_wait);
+ restore_flags(flags);
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: Close end!!!.\n");
+#endif
+}
+
+/* write et all */
+static int isicom_write(struct tty_struct * tty, int from_user,
+ const unsigned char * buf, int count)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ unsigned long flags;
+ int cnt, total = 0;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n",
+ port->channel+1, count);
+#endif
+ if (isicom_paranoia_check(port, tty->device, "isicom_write"))
+ return 0;
+
+ if (!tty || !port->xmit_buf || !tmp_buf)
+ return 0;
+ if (from_user)
+ down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */
+
+ save_flags(flags);
+ while(1) {
+ cli();
+ cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - port->xmit_head));
+ if (cnt <= 0)
+ break;
+
+ if (from_user) {
+ /* the following may block for paging... hence
+ enabling interrupts but tx routine may have
+ created more space in xmit_buf when the ctrl
+ gets back here */
+ sti();
+ copy_from_user(tmp_buf, buf, cnt);
+ cli();
+ cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - port->xmit_head));
+ memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt);
+ }
+ else
+ memcpy(port->xmit_buf + port->xmit_head, buf, cnt);
+ port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1);
+ port->xmit_cnt += cnt;
+ restore_flags(flags);
+ buf += cnt;
+ count -= cnt;
+ total += cnt;
+ }
+ if (from_user)
+ up(&tmp_buf_sem);
+ if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)
+ port->status |= ISI_TXOK;
+ restore_flags(flags);
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total);
+#endif
+ return total;
+}
+
+/* put_char et all */
+static void isicom_put_char(struct tty_struct * tty, unsigned char ch)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_put_char"))
+ return;
+
+ if (!tty || !port->xmit_buf)
+ return;
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch);
+#endif
+
+ save_flags(flags); cli();
+
+ if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) {
+ restore_flags(flags);
+ return;
+ }
+
+ port->xmit_buf[port->xmit_head++] = ch;
+ port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
+ port->xmit_cnt++;
+ restore_flags(flags);
+}
+
+/* flush_chars et all */
+static void isicom_flush_chars(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_flush_chars"))
+ return;
+
+ if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+ !port->xmit_buf)
+ return;
+
+ /* this tells the transmitter to consider this port for
+ data output to the card ... that's the best we can do. */
+ port->status |= ISI_TXOK;
+}
+
+/* write_room et all */
+static int isicom_write_room(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ int free;
+ if (isicom_paranoia_check(port, tty->device, "isicom_write_room"))
+ return 0;
+
+ free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
+ if (free < 0)
+ free = 0;
+ return free;
+}
+
+/* chars_in_buffer et all */
+static int isicom_chars_in_buffer(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ if (isicom_paranoia_check(port, tty->device, "isicom_chars_in_buffer"))
+ return 0;
+ return port->xmit_cnt;
+}
+
+/* ioctl et all */
+extern inline void isicom_send_break(struct isi_port * port, unsigned long length)
+{
+ struct isi_board * card = port->card;
+ short wait = 10;
+ unsigned short base = card->base;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));
+ if (!wait) {
+ printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n");
+ return;
+ }
+ outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
+ outw((length & 0xff) << 8 | 0x00, base);
+ outw((length & 0xff00), base);
+ InterruptTheCard(base);
+ restore_flags(flags);
+}
+
+static int isicom_get_modem_info(struct isi_port * port, unsigned int * value)
+{
+ /* just send the port status */
+ unsigned int info;
+ unsigned short status = port->status;
+
+ info = ((status & ISI_RTS) ? TIOCM_RTS : 0) |
+ ((status & ISI_DTR) ? TIOCM_DTR : 0) |
+ ((status & ISI_DCD) ? TIOCM_CAR : 0) |
+ ((status & ISI_DSR) ? TIOCM_DSR : 0) |
+ ((status & ISI_CTS) ? TIOCM_CTS : 0) |
+ ((status & ISI_RI ) ? TIOCM_RI : 0);
+ put_user(info, (unsigned long *) value);
+ return 0;
+}
+
+static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd,
+ unsigned int * value)
+{
+ unsigned int arg;
+ unsigned long flags;
+
+ if(get_user(arg, value))
+ return -EFAULT;
+
+ save_flags(flags); cli();
+
+ switch(cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ raise_rts(port);
+ if (arg & TIOCM_DTR)
+ raise_dtr(port);
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ drop_rts(port);
+ if (arg & TIOCM_DTR)
+ drop_dtr(port);
+ break;
+
+ case TIOCMSET:
+ if (arg & TIOCM_RTS)
+ raise_rts(port);
+ else
+ drop_rts(port);
+
+ if (arg & TIOCM_DTR)
+ raise_dtr(port);
+ else
+ drop_dtr(port);
+ break;
+
+ default:
+ restore_flags(flags);
+ return -EINVAL;
+ }
+ restore_flags(flags);
+ return 0;
+}
+
+static int isicom_set_serial_info(struct isi_port * port,
+ struct serial_struct * info)
+{
+ struct serial_struct newinfo;
+ unsigned long flags;
+ int reconfig_port;
+
+ if(copy_from_user(&newinfo, info, sizeof(newinfo)))
+ return -EFAULT;
+
+ reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
+ (newinfo.flags & ASYNC_SPD_MASK));
+
+ if (!suser()) {
+ if ((newinfo.close_delay != port->close_delay) ||
+ (newinfo.closing_wait != port->closing_wait) ||
+ ((newinfo.flags & ~ASYNC_USR_MASK) !=
+ (port->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ port->flags = ((port->flags & ~ ASYNC_USR_MASK) |
+ (newinfo.flags & ASYNC_USR_MASK));
+ }
+ else {
+ port->close_delay = newinfo.close_delay;
+ port->closing_wait = newinfo.closing_wait;
+ port->flags = ((port->flags & ~ASYNC_FLAGS) |
+ (newinfo.flags & ASYNC_FLAGS));
+ }
+ if (reconfig_port) {
+ save_flags(flags); cli();
+ isicom_config_port(port);
+ restore_flags(flags);
+ }
+ return 0;
+}
+
+static int isicom_get_serial_info(struct isi_port * port,
+ struct serial_struct * info)
+{
+ struct serial_struct out_info;
+
+ memset(&out_info, 0, sizeof(out_info));
+/* out_info.type = ? */
+ out_info.line = port - isi_ports;
+ out_info.port = port->card->base;
+ out_info.irq = port->card->irq;
+ out_info.flags = port->flags;
+/* out_info.baud_base = ? */
+ out_info.close_delay = port->close_delay;
+ out_info.closing_wait = port->closing_wait;
+ if(copy_to_user(info, &out_info, sizeof(out_info)))
+ return -EFAULT;
+ return 0;
+}
+
+static int isicom_ioctl(struct tty_struct * tty, struct file * filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ int retval;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_ioctl"))
+ return -ENODEV;
+
+ switch(cmd) {
+ case TCSBRK:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ isicom_send_break(port, HZ/4);
+ return 0;
+
+ case TCSBRKP:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
+ return 0;
+
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+
+ case TIOCSSOFTCAR:
+ if(get_user(arg, (unsigned long *) arg))
+ return -EFAULT;
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+
+ case TIOCMGET:
+ return isicom_get_modem_info(port, (unsigned int*) arg);
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return isicom_set_modem_info(port, cmd,
+ (unsigned int *) arg);
+
+ case TIOCGSERIAL:
+ return isicom_get_serial_info(port,
+ (struct serial_struct *) arg);
+
+ case TIOCSSERIAL:
+ return isicom_set_serial_info(port,
+ (struct serial_struct *) arg);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+/* set_termios et all */
+static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_set_termios"))
+ return;
+
+ if (tty->termios->c_cflag == old_termios->c_cflag &&
+ tty->termios->c_iflag == old_termios->c_iflag)
+ return;
+
+ save_flags(flags); cli();
+ isicom_config_port(port);
+ restore_flags(flags);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ isicom_start(tty);
+ }
+}
+
+/* throttle et all */
+static void isicom_throttle(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_board * card = port->card;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_throttle"))
+ return;
+
+ /* tell the card that this port cannot handle any more data for now */
+ save_flags(flags); cli();
+ card->port_status &= ~(1 << port->channel);
+ outw(card->port_status, card->base + 0x02);
+ restore_flags(flags);
+}
+
+/* unthrottle et all */
+static void isicom_unthrottle(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ struct isi_board * card = port->card;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_unthrottle"))
+ return;
+
+ /* tell the card that this port is ready to accept more data */
+ save_flags(flags); cli();
+ card->port_status |= (1 << port->channel);
+ outw(card->port_status, card->base + 0x02);
+ restore_flags(flags);
+}
+
+/* stop et all */
+static void isicom_stop(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_stop"))
+ return;
+
+ /* this tells the transmitter not to consider this port for
+ data output to the card. */
+ port->status &= ~ISI_TXOK;
+}
+
+/* start et all */
+static void isicom_start(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_start"))
+ return;
+
+ /* this tells the transmitter to consider this port for
+ data output to the card. */
+ port->status |= ISI_TXOK;
+}
+
+/* hangup et all */
+static void do_isicom_hangup(void * data)
+{
+ struct isi_port * port = (struct isi_port *) data;
+ struct tty_struct * tty;
+
+ tty = port->tty;
+ if (!tty)
+ return;
+
+ tty_hangup(tty);
+}
+
+static void isicom_hangup(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_hangup"))
+ return;
+
+ isicom_shutdown_port(port);
+ port->count = 0;
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
+ port->tty = 0;
+ wake_up_interruptible(&port->open_wait);
+}
+
+/* flush_buffer et all */
+static void isicom_flush_buffer(struct tty_struct * tty)
+{
+ struct isi_port * port = (struct isi_port *) tty->driver_data;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->device, "isicom_flush_buffer"))
+ return;
+
+ save_flags(flags); cli();
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ restore_flags(flags);
+
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+
+static int register_ioregion(void)
+{
+ int count, done=0;
+ for (count=0; count < BOARD_COUNT; count++ ) {
+ if (isi_card[count].base) {
+ if (check_region(isi_card[count].base,16)) {
+ printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n",
+ isi_card[count].base,isi_card[count].base+15,count+1);
+ isi_card[count].base=0;
+ }
+ else {
+ request_region(isi_card[count].base,16,ISICOM_NAME);
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);
+#endif
+ done++;
+ }
+ }
+ }
+ return done;
+}
+
+static void unregister_ioregion(void)
+{
+ int count;
+ for (count=0; count < BOARD_COUNT; count++ )
+ if (isi_card[count].base) {
+ release_region(isi_card[count].base,16);
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);
+#endif
+ }
+}
+
+static int register_drivers(void)
+{
+ int error;
+
+ /* tty driver structure initialization */
+ memset(&isicom_normal, 0, sizeof(struct tty_driver));
+ isicom_normal.magic = TTY_DRIVER_MAGIC;
+ isicom_normal.name = "ttyM";
+ isicom_normal.major = ISICOM_NMAJOR;
+ isicom_normal.minor_start = 0;
+ isicom_normal.num = PORT_COUNT;
+ isicom_normal.type = TTY_DRIVER_TYPE_SERIAL;
+ isicom_normal.subtype = SERIAL_TYPE_NORMAL;
+ isicom_normal.init_termios = tty_std_termios;
+ isicom_normal.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL |CLOCAL;
+ isicom_normal.flags = TTY_DRIVER_REAL_RAW;
+ isicom_normal.refcount = &isicom_refcount;
+
+ isicom_normal.table = isicom_table;
+ isicom_normal.termios = isicom_termios;
+ isicom_normal.termios_locked = isicom_termios_locked;
+
+ isicom_normal.open = isicom_open;
+ isicom_normal.close = isicom_close;
+ isicom_normal.write = isicom_write;
+ isicom_normal.put_char = isicom_put_char;
+ isicom_normal.flush_chars = isicom_flush_chars;
+ isicom_normal.write_room = isicom_write_room;
+ isicom_normal.chars_in_buffer = isicom_chars_in_buffer;
+ isicom_normal.ioctl = isicom_ioctl;
+ isicom_normal.set_termios = isicom_set_termios;
+ isicom_normal.throttle = isicom_throttle;
+ isicom_normal.unthrottle = isicom_unthrottle;
+ isicom_normal.stop = isicom_stop;
+ isicom_normal.start = isicom_start;
+ isicom_normal.hangup = isicom_hangup;
+ isicom_normal.flush_buffer = isicom_flush_buffer;
+
+ /* callout device */
+
+ isicom_callout = isicom_normal;
+ isicom_callout.name = "cum";
+ isicom_callout.major = ISICOM_CMAJOR;
+ isicom_callout.subtype = SERIAL_TYPE_CALLOUT;
+
+ if ((error=tty_register_driver(&isicom_normal))!=0) {
+ printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n",
+ error);
+ return error;
+ }
+ if ((error=tty_register_driver(&isicom_callout))!=0) {
+ tty_unregister_driver(&isicom_normal);
+ printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n",
+ error);
+ return error;
+ }
+ return 0;
+}
+
+static void unregister_drivers(void)
+{
+ int error;
+ if ((error=tty_unregister_driver(&isicom_callout))!=0)
+ printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error);
+ if (tty_unregister_driver(&isicom_normal))
+ printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error);
+}
+
+static int register_isr(void)
+{
+ int count, done=0;
+ for (count=0; count < BOARD_COUNT; count++ ) {
+ if (isi_card[count].base) {
+ if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) {
+ printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n",
+ isi_card[count].irq, count+1);
+ release_region(isi_card[count].base,16);
+ isi_card[count].base=0;
+ }
+ else {
+ printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n",
+ count+1, isi_card[count].base, isi_card[count].irq);
+
+ irq_to_board[isi_card[count].irq]=&isi_card[count];
+ done++;
+ }
+ }
+ }
+ return done;
+}
+
+static void unregister_isr(void)
+{
+ int count;
+ for (count=0; count < BOARD_COUNT; count++ )
+ if (isi_card[count].base) {
+ free_irq(isi_card[count].irq, NULL);
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);
+#endif
+ }
+}
+
+static int isicom_init(void)
+{
+ int card, channel, base;
+ struct isi_port * port;
+ unsigned long page;
+
+ if (!tmp_buf) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page) {
+#ifdef ISICOM_DEBUG
+ printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n");
+#else
+ printk(KERN_ERR "ISICOM: Not enough memory...\n");
+#endif
+ return 0;
+ }
+ tmp_buf = (unsigned char *) page;
+ }
+
+ if (!register_ioregion())
+ {
+ printk(KERN_ERR "ISICOM: All required I/O space found busy.\n");
+ free_page((unsigned long)tmp_buf);
+ return 0;
+ }
+ if (register_drivers())
+ {
+ unregister_ioregion();
+ free_page((unsigned long)tmp_buf);
+ return 0;
+ }
+ if (!register_isr())
+ {
+ unregister_drivers();
+ /* ioports already uregistered in register_isr */
+ free_page((unsigned long)tmp_buf);
+ return 0;
+ }
+
+ /* initialize bottom half */
+ init_bh(ISICOM_BH, do_isicom_bh);
+
+
+ memset(isi_ports, 0, sizeof(isi_ports));
+ for (card = 0; card < BOARD_COUNT; card++) {
+ port = &isi_ports[card * 16];
+ isi_card[card].ports = port;
+ base = isi_card[card].base;
+ for (channel = 0; channel < 16; channel++, port++) {
+ port->magic = ISICOM_MAGIC;
+ port->card = &isi_card[card];
+ port->channel = channel;
+ port->normal_termios = isicom_normal.init_termios;
+ port->callout_termios = isicom_callout.init_termios;
+ port->close_delay = 50 * HZ/100;
+ port->closing_wait = 3000 * HZ/100;
+ port->hangup_tq.routine = do_isicom_hangup;
+ port->hangup_tq.data = port;
+ port->bh_tqueue.routine = isicom_bottomhalf;
+ port->bh_tqueue.data = port;
+ port->status = 0;
+
+ /* . . . */
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Insmod can set static symbols so keep these static
+ */
+
+static int io[4];
+static int irq[4];
+
+MODULE_AUTHOR("MultiTech");
+MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
+MODULE_PARM(io, "1-4i");
+MODULE_PARM_DESC(io, "I/O ports for the cards");
+MODULE_PARM(irq, "1-4i");
+MODULE_PARM_DESC(irq, "Interrupts for the cards");
+
+int init_module(void)
+{
+ int retval, card;
+
+ for(card=0; card < BOARD_COUNT; card++)
+ {
+ isi_card[card].base=io[card];
+ isi_card[card].irq=irq[card];
+ }
+
+ for (card=0 ;card < BOARD_COUNT; card++) {
+ if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)||
+ (isi_card[card].irq==4)||(isi_card[card].irq==5)||
+ (isi_card[card].irq==7)||(isi_card[card].irq==10)||
+ (isi_card[card].irq==11)||(isi_card[card].irq==12)||
+ (isi_card[card].irq==15))) {
+
+ if (isi_card[card].base) {
+ printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n",
+ isi_card[card].irq, card+1);
+ isi_card[card].base=0;
+ }
+ }
+ }
+
+ if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) {
+ printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n");
+ return -EIO;
+ }
+ retval=misc_register(&isiloader_device);
+ if (retval<0) {
+ printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");
+ return -EIO;
+ }
+
+ if (!isicom_init()) {
+ if (misc_deregister(&isiloader_device))
+ printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
+ return -EIO;
+ }
+
+ init_timer(&tx);
+ tx.expires = jiffies + 1;
+ tx.data = 0;
+ tx.function = isicom_tx;
+ re_schedule = 1;
+ add_timer(&tx);
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ re_schedule = 0;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ);
+ disable_bh(ISICOM_BH);
+
+#ifdef ISICOM_DEBUG
+ printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count);
+#endif
+
+#ifdef ISICOM_DEBUG
+ printk("ISICOM: uregistering isr ...\n");
+#endif
+ unregister_isr();
+
+#ifdef ISICOM_DEBUG
+ printk("ISICOM: unregistering drivers ...\n");
+#endif
+ unregister_drivers();
+
+#ifdef ISICOM_DEBUG
+ printk("ISICOM: unregistering ioregion ...\n");
+#endif
+ unregister_ioregion();
+
+#ifdef ISICOM_DEBUG
+ printk("ISICOM: freeing tmp_buf ...\n");
+#endif
+ free_page((unsigned long)tmp_buf);
+
+#ifdef ISICOM_DEBUG
+ printk("ISICOM: unregistering firmware loader ...\n");
+#endif
+ if (misc_deregister(&isiloader_device))
+ printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");
+}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index f52f452b5..a1a6d93a1 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -2311,7 +2311,7 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout)
if (signal_pending(current))
break;
stli_delay(2);
- if (jiffies >= tend)
+ if (time_after_eq(jiffies, tend))
break;
}
}
diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in
index db5585cd1..a41eaac33 100644
--- a/drivers/char/joystick/Config.in
+++ b/drivers/char/joystick/Config.in
@@ -10,9 +10,9 @@ dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CO
dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK
- dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK
- dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK
+ dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
+ dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
+ dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
fi
if [ "$CONFIG_AMIGA" = "y" ]; then
dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 3eb454663..208e07b89 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -202,8 +202,13 @@ void handle_scancode(unsigned char scancode)
tty = ttytab? ttytab[fg_console]: NULL;
if (tty && (!tty->driver_data)) {
- /* This is to workaround ugly bug in tty_io.c, which
- does not do locking when it should */
+ /*
+ * We touch the tty structure via the the ttytab array
+ * without knowing whether or not tty is open, which
+ * is inherently dangerous. We currently rely on that
+ * fact that console_open sets tty->driver_data when
+ * it opens it, and clears it when it closes it.
+ */
tty = NULL;
}
kbd = kbd_table + fg_console;
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index 2660c2ca2..7eecf2965 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -41,11 +41,9 @@
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/timer.h>
#include <linux/init.h>
-#include <asm/irq.h>
-#ifdef CONFIG_KMOD
#include <linux/kmod.h>
-#endif
#ifdef CONFIG_AMIGA
#ifdef CONFIG_MULTIFACE_III_LP
@@ -58,6 +56,7 @@
#include <linux/malloc.h>
#include <linux/interrupt.h>
+#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -183,6 +182,7 @@ static ssize_t lp_write_interrupt(struct file *file, const char *buf,
struct inode *inode = file->f_dentry->d_inode;
unsigned long total_bytes_written = 0;
unsigned int flags;
+ long timeout;
int rc;
int dev = MINOR(inode->i_rdev);
@@ -211,12 +211,12 @@ static ssize_t lp_write_interrupt(struct file *file, const char *buf,
/* something blocked printing, so we don't want to sleep too long,
in case we have to rekick the interrupt */
- current->timeout = jiffies + LP_TIMEOUT_POLLED;
+ timeout = LP_TIMEOUT_POLLED;
} else {
- current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
+ timeout = LP_TIMEOUT_INTERRUPT;
}
- interruptible_sleep_on(&lp_table[dev]->lp_wait_q);
+ interruptible_sleep_on_timeout(&lp_table[dev]->lp_wait_q, timeout);
restore_flags(flags);
/* we're up again and running. we first disable lp_interrupt(), then
@@ -281,7 +281,7 @@ static ssize_t lp_write_polled(struct file *file, const char *buf,
int dev = MINOR(inode->i_rdev);
#ifdef LP_DEBUG
- if (jiffies-lp_last_call > lp_table[dev]->time) {
+ if (time_after(jiffies, lp_last_call + lp_table[dev]->time)) {
lp_total_chars = 0;
lp_max_count = 1;
}
@@ -336,8 +336,7 @@ static ssize_t lp_write_polled(struct file *file, const char *buf,
lp_total_chars = 0;
#endif
current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + timeout;
- schedule();
+ schedule_timeout(timeout);
}
}
return temp - buf;
@@ -373,14 +372,12 @@ static int lp_open(struct inode *inode, struct file *file)
if (dev >= MAX_LP)
goto out_err;
-#ifdef CONFIG_KMOD
if (!lp_table[dev]) {
char modname[30];
sprintf(modname, "char-major-%d-%d", LP_MAJOR, dev);
request_module(modname);
}
-#endif
if (!lp_table[dev])
goto out_err;
if (!(lp_table[dev]->flags & LP_EXIST))
@@ -530,7 +527,7 @@ void cleanup_module(void)
* (un-)register for hardware drivers
* tab is an inititalised lp_struct, dev the desired minor
* if dev < 0, let the driver choose the first free minor
- * if sucessful return the minor, else -1
+ * if successful return the minor, else -1
*/
int register_parallel(struct lp_struct *tab, int dev)
{
diff --git a/drivers/char/mac_SCC.c b/drivers/char/mac_SCC.c
index 159a8336e..c20e7a9f0 100644
--- a/drivers/char/mac_SCC.c
+++ b/drivers/char/mac_SCC.c
@@ -198,18 +198,6 @@ static SERIALSWITCH SCC_switch = {
};
/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char tmp_buf[4096]; /* This is cheating */
-static struct semaphore tmp_buf_sem = MUTEX;
-
-/*
* This is used to figure out the divisor speeds and the timeouts
*/
static int baud_table[] = {
@@ -771,7 +759,7 @@ static void SCC_init_port( struct m68k_async_struct *info, int type, int channel
/* If console serial line, then enable interrupts. */
if (info->private->is_cons) {
- printk("mac_SCC: console line %lx; enabling interrupt!\n", info);
+ printk("mac_SCC: console line %d; enabling interrupt!\n", info->line);
write_zsreg(info->private->zs_channel, R1,
(EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
write_zsreg(info->private->zs_channel, R9, (NV | MIE));
@@ -784,7 +772,7 @@ static void SCC_init_port( struct m68k_async_struct *info, int type, int channel
* client attached to us asynchronously.
*/
if (info->private->kgdb_channel) {
- printk("mac_SCC: kgdb line %lx; enabling interrupt!\n", info);
+ printk("mac_SCC: kgdb line %d; enabling interrupt!\n", info->line);
kgdb_chaninit(info, 1, info->private->zs_baud);
}
/* Report settings (in m68kserial.c) */
@@ -1141,8 +1129,6 @@ static void SCC_throttle(struct m68k_async_struct *info, int status)
static void SCC_get_serial_info(struct m68k_async_struct * info,
struct serial_struct * retinfo)
{
- struct serial_struct tmp;
-
retinfo->baud_base = info->baud_base;
retinfo->custom_divisor = info->custom_divisor;
}
@@ -1190,8 +1176,7 @@ static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
static int SCC_set_modem_info(struct m68k_async_struct *info,
int new_dtr, int new_rts)
{
- int error;
- unsigned int arg, bits;
+ unsigned int bits;
bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
@@ -1231,7 +1216,6 @@ static int SCC_ioctl(struct tty_struct *tty, struct file * file,
unsigned long arg)
{
int error;
- int retval;
switch (cmd) {
case TIOCSERGETLSR: /* Get line status register */
@@ -1315,9 +1299,9 @@ static void probe_sccs(void)
ZS_CONTROL+ZS_MOVE*n;
zs_channels[n].data = (volatile unsigned char *)ZS_DATA+ZS_MOVE*n;
#else
- zs_channels[n].control = (volatile unsigned char *)
+ zs_channels[n].control = (volatile unsigned char *) /* 2, 0 */
(mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
- zs_channels[n].data = (volatile unsigned char *)
+ zs_channels[n].data = (volatile unsigned char *) /* 6, 4 */
(mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
#endif
zs_soft[n].private = &zs_soft_private[n];
@@ -1405,8 +1389,8 @@ static inline void
rs_cons_check(struct m68k_async_struct *ss, int channel)
{
int i, o, io;
- static consout_registered = 0;
- static msg_printed = 0;
+ static int consout_registered = 0;
+ static int msg_printed = 0;
i = o = io = 0;
@@ -1458,10 +1442,9 @@ volatile int test_done;
/* rs_init inits the driver */
int mac_SCC_init(void)
{
- int channel, line, nr = 0, i;
+ int channel, line, nr = 0;
unsigned long flags;
struct serial_struct req;
- struct m68k_async_struct *info;
printk("Mac68K Z8530 serial driver version 1.01\n");
@@ -1486,7 +1469,7 @@ int mac_SCC_init(void)
for (channel = 0; channel < zs_channels_found; ++channel) {
req.line = channel;
req.type = SER_SCC_MAC;
- req.port = zs_soft[channel].private->zs_channel->control;
+ req.port = (int) zs_soft[channel].private->zs_channel->control;
if ((line = register_serial( &req )) >= 0) {
SCC_init_port( &rs_table[line], req.type, line );
diff --git a/drivers/char/macmouse.c b/drivers/char/macmouse.c
deleted file mode 100644
index b9236bb93..000000000
--- a/drivers/char/macmouse.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Macintosh ADB Mouse driver for Linux
- *
- * 27 Oct 1997 Michael Schmitz
- *
- * Apple mouse protocol according to:
- *
- * Device code shamelessly stolen from:
- */
-/*
- * Atari Mouse Driver for Linux
- * by Robert de Vries (robert@and.nl) 19Jul93
- *
- * 16 Nov 1994 Andreas Schwab
- * Compatibility with busmouse
- * Support for three button mouse (shamelessly stolen from MiNT)
- * third button wired to one of the joystick directions on joystick 1
- *
- * 1996/02/11 Andreas Schwab
- * Module support
- * Allow multiple open's
- */
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/mac_mouse.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
-static struct mouse_status mouse;
-static int mac_mouse_x_threshold = 2, mac_mouse_y_threshold = 2;
-static int mac_mouse_buttons = 0;
-
-extern void (*mac_mouse_interrupt_hook) (char *, int);
-extern int mac_emulate_button2;
-extern int mac_emulate_button3;
-
-extern int console_loglevel;
-
-/*
- * XXX: need to figure out what ADB mouse packets mean ...
- * This is the stuff stolen from the Atari driver ...
- */
-static void mac_mouse_interrupt(char *buf, int nb)
-{
- static int buttons = 7; /* all mouse buttons _up_ !! */
-
- /*
- Handler 1 -- 100cpi original Apple mouse protocol.
- Handler 2 -- 200cpi original Apple mouse protocol.
-
- For Apple's standard one-button mouse protocol the data array will
- contain the following values:
-
- BITS COMMENTS
- data[0] = 0000 0000 ADB packet identifer.
- data[1] = ???? ???? (?)
- data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
- data[3] = bxxx xxxx First button and x-axis motion.
- data[4] = byyy yyyy Second button and y-axis motion.
-
- NOTE: data[0] is confirmed by the parent function and need not be
- checked here.
- */
-
- /*
- Handler 4 -- Apple Extended mouse protocol.
-
- For Apple's 3-button mouse protocol the data array will contain the
- following values:
-
- BITS COMMENTS
- data[0] = 0000 0000 ADB packet identifer.
- data[1] = 0100 0000 Extended protocol register.
- Bits 6-7 are the device id, which should be 1.
- Bits 4-5 are resolution which is in "units/inch".
- The Logitech MouseMan returns these bits clear but it has
- 200/300cpi resolution.
- Bits 0-3 are unique vendor id.
- data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
- Bits 2-3 should be 8 + 4.
- Bits 4-7 should be 3 for a mouse device.
- data[3] = bxxx xxxx Left button and x-axis motion.
- data[4] = byyy yyyy Second button and y-axis motion.
- data[5] = byyy bxxx Third button and fourth button.
- Y is additiona. high bits of y-axis motion.
- X is additional high bits of x-axis motion.
-
- NOTE: data[0] and data[2] are confirmed by the parent function and
- need not be checked here.
- */
-
- /*
- * 'buttons' here means 'button down' states!
- * Button 1 (left) : bit 2, busmouse button 3
- * Button 2 (right) : bit 0, busmouse button 1
- * Button 3 (middle): bit 1, busmouse button 2
- */
-
- /* x/y and buttons swapped */
-
- if (buf[0] == 0) { /* real packet : use buttons? */
-#ifdef DEBUG_ADBMOUSE
- if (console_loglevel >= 8)
- printk("mac_mouse: real data; ");
-#endif
- /* button 1 (left, bit 2) : always significant ! */
- buttons = (buttons&3) | (buf[3] & 0x80 ? 4 : 0); /* 1+2 unchanged */
- /* button 2 (right, bit 0) present ? */
- if ( !mac_emulate_button2 )
- buttons = (buttons&6) | (buf[4] & 0x80 ? 1 : 0); /* 2+3 unchanged */
- /* button 2 (middle) present? */
- /* data valid only if extended mouse format ! (buf[3] = 0 else)*/
- if ( !mac_emulate_button3 && buf[1]&0x40 )
- buttons = (buttons&5) | (buf[5] & 0x80 ? 2 : 0); /* 1+3 unchanged */
- } else { /* fake packet : use 2+3 */
-#ifdef DEBUG_ADBMOUSE
- if (console_loglevel >= 8)
- printk("mac_mouse: fake data; ");
-#endif
- /* we only see state changes here, but the fake driver takes care
- * to preserve state... button 1 state must stay unchanged! */
- buttons = (buttons&4) | ((buf[4] & 0x80 ? 1 : 0) | (buf[5] & 0x80 ? 2 : 0));
- }
-
- add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
- mouse.buttons = buttons & 7;
- mouse.dx += ((buf[4]&0x7f) < 64 ? (buf[4]&0x7f) : (buf[4]&0x7f)-128 );
- mouse.dy -= ((buf[3]&0x7f) < 64 ? (buf[3]&0x7f) : (buf[3]&0x7f)-128 );
-
-#ifdef DEBUG_ADBMOUSE
- if (console_loglevel >= 8)
- printk(" %X %X %X buttons %x dx %d dy %d \n",
- buf[3], buf[4], buf[5], mouse.buttons, mouse.dx, mouse.dy);
-#endif
-
- mouse.ready = 1;
- wake_up_interruptible(&mouse.wait);
- if (mouse.fasyncptr)
- kill_fasync(mouse.fasyncptr, SIGIO);
-
-}
-
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
- int retval;
-
- retval = fasync_helper(fd, filp, on, &mouse.fasyncptr);
- if (retval < 0)
- return retval;
- return 0;
-}
-
-static int release_mouse(struct inode *inode, struct file *file)
-{
- fasync_mouse(-1, file, 0);
- if (--mouse.active)
- return 0;
-
- mac_mouse_interrupt_hook = NULL;
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int open_mouse(struct inode *inode, struct file *file)
-{
- if (mouse.active++)
- return 0;
-
- mouse.ready = 0;
-
- mouse.dx = mouse.dy = 0;
- mac_mouse_buttons = 0;
- MOD_INC_USE_COUNT;
- mac_mouse_interrupt_hook = mac_mouse_interrupt;
- return 0;
-}
-
-static ssize_t write_mouse(struct file *file, const char *buffer,
- size_t count, loff_t *ppos)
-{
- return -EINVAL;
-}
-
-static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
- loff_t *ppos)
-{
- int dx, dy, buttons;
-
- if (count < 3)
- return -EINVAL;
- if (!mouse.ready)
- return -EAGAIN;
- dx = mouse.dx;
- dy = mouse.dy;
- buttons = mouse.buttons;
- if (dx > 127)
- dx = 127;
- else if (dx < -128)
- dx = -128;
- if (dy > 127)
- dy = 127;
- else if (dy < -128)
- dy = -128;
- mouse.dx -= dx;
- mouse.dy -= dy;
- if (mouse.dx == 0 && mouse.dy == 0)
- mouse.ready = 0;
- if (put_user(buttons | 0x80, buffer++) ||
- put_user((char) dx, buffer++) ||
- put_user((char) dy, buffer++))
- return -EFAULT;
- if (count > 3)
- if (clear_user(buffer, count - 3))
- return -EFAULT;
- return count;
-}
-
-static unsigned int mouse_poll(struct file *file, poll_table *wait)
-{
- poll_wait(file, &mouse.wait, wait);
- if (mouse.ready)
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-struct file_operations mac_mouse_fops = {
- NULL, /* mouse_seek */
- read_mouse,
- write_mouse,
- NULL, /* mouse_readdir */
- mouse_poll,
- NULL, /* mouse_ioctl */
- NULL, /* mouse_mmap */
- open_mouse,
- NULL, /* flush */
- release_mouse,
- NULL,
- fasync_mouse,
-};
-
-#define ADB_MOUSE_MINOR 10
-
-static struct miscdevice mac_mouse = {
- ADB_MOUSE_MINOR, "adbmouse", &mac_mouse_fops
-};
-
-__initfunc(int mac_mouse_init(void))
-{
- mouse.active = 0;
- mouse.ready = 0;
- mouse.wait = NULL;
-
- if (!MACH_IS_MAC)
- return -ENODEV;
-
- printk(KERN_INFO "Macintosh ADB mouse installed.\n");
- misc_register(&mac_mouse);
- return 0;
-}
-
-
-#define MIN_THRESHOLD 1
-#define MAX_THRESHOLD 20 /* more seems not reasonable... */
-
-__initfunc(void mac_mouse_setup(char *str, int *ints))
-{
- if (ints[0] < 1) {
- printk( "mac_mouse_setup: no arguments!\n" );
- return;
- }
- else if (ints[0] > 2) {
- printk( "mac_mouse_setup: too many arguments\n" );
- }
-
- if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
- printk( "mac_mouse_setup: bad threshold value (ignored)\n" );
- else {
- mac_mouse_x_threshold = ints[1];
- mac_mouse_y_threshold = ints[1];
- if (ints[0] > 1) {
- if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
- printk("mac_mouse_setup: bad threshold value (ignored)\n" );
- else
- mac_mouse_y_threshold = ints[2];
- }
- }
-
-}
-
-#ifdef MODULE
-#include <asm/setup.h>
-
-int init_module(void)
-{
- return mac_mouse_init();
-}
-
-void cleanup_module(void)
-{
- misc_deregister(&mac_mouse);
-}
-#endif
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index f4cd55fdd..6eaa07d23 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -5,22 +5,17 @@
*/
#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/tty.h>
+#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/tpqic02.h>
#include <linux/ftape.h>
#include <linux/malloc.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
-#include <linux/mm.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/joystick.h>
+#include <linux/i2c.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -137,26 +132,49 @@ static ssize_t write_mem(struct file * file, const char * buf,
return do_write_mem(file, __va(p), p, buf, count, ppos);
}
+/*
+ * This should probably be per-architecture in <asm/pgtable.h>
+ */
+static inline unsigned long pgprot_noncached(unsigned long prot)
+{
+#if defined(__i386__)
+ if (boot_cpu_data.x86 > 3)
+ prot |= _PAGE_PCD;
+#elif defined(__powerpc__)
+ prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+#elif defined(__mc68000__)
+ if (CPU_IS_020_OR_030)
+ prot |= _PAGE_NOCACHE030;
+ /* Use no-cache mode, serialized */
+ if (CPU_IS_040_OR_060)
+ prot = (prot & _CACHEMASK040) | _PAGE_NOCACHE_S;
+#elif defined(__mips__)
+ prot = (prot & ~_CACHE_MASK) | _CACHE_UNCACHED;
+#endif
+
+ return prot;
+}
+
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
unsigned long offset = vma->vm_offset;
if (offset & ~PAGE_MASK)
return -ENXIO;
-#if defined(__i386__)
+
/*
- * hmm.. This disables high-memory caching, as the XFree86 team
- * wondered about that at one time.
- * The surround logic should disable caching for the high device
- * addresses anyway, but right now this seems still needed.
+ * Accessing memory above the top the kernel knows about or
+ * through a file pointer that was marked O_SYNC will be
+ * done non-cached.
+ *
+ * Set VM_IO, as this is likely a non-cached access to an
+ * I/O area, and we don't want to include that in a core
+ * file.
*/
- if (boot_cpu_data.x86 > 3 && offset >= __pa(high_memory))
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
-#ifdef __powerpc__
- if (offset >= __pa(high_memory))
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
-#endif
+ if (offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) {
+ pgprot_val(vma->vm_page_prot) = pgprot_noncached(pgprot_val(vma->vm_page_prot));
+ vma->vm_flags |= VM_IO;
+ }
if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index d449cf226..fe13a043c 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -49,9 +49,7 @@
#include <linux/tty.h>
#include <linux/selection.h>
-#ifdef CONFIG_KMOD
#include <linux/kmod.h>
-#endif
/*
* Head entry for the doubly linked miscdevice list
@@ -89,7 +87,6 @@ extern void hfmodem_init(void);
extern int pc110pad_init(void);
extern int pmu_device_init(void);
-#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
int len, int *eof, void *private)
{
@@ -102,7 +99,6 @@ static int misc_read_proc(char *buf, char **start, off_t offset,
return len > offset ? len - offset : 0;
}
-#endif /* PROC_FS */
static int misc_open(struct inode * inode, struct file * file)
{
@@ -113,7 +109,6 @@ static int misc_open(struct inode * inode, struct file * file)
while ((c != &misc_list) && (c->minor != minor))
c = c->next;
if (c == &misc_list) {
-#ifdef CONFIG_KMOD
char modname[20];
sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
request_module(modname);
@@ -121,7 +116,6 @@ static int misc_open(struct inode * inode, struct file * file)
while ((c != &misc_list) && (c->minor != minor))
c = c->next;
if (c == &misc_list)
-#endif
return -ENODEV;
}
@@ -188,17 +182,13 @@ int misc_deregister(struct miscdevice * misc)
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
-#if defined(CONFIG_PROC_FS)
static struct proc_dir_entry *proc_misc;
-#endif
int __init misc_init(void)
{
-#ifdef CONFIG_PROC_FS
proc_misc = create_proc_entry("misc", 0, 0);
if (proc_misc)
proc_misc->read_proc = misc_read_proc;
-#endif /* PROC_FS */
#ifdef CONFIG_BUSMOUSE
bus_mouse_init();
#endif
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index b49bfe9a6..07c733b5b 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -51,6 +51,10 @@
static struct mouse_status mouse;
static int mouse_irq = MOUSE_IRQ;
+#ifdef MODULE
+MODULE_PARM(mouse_irq, "i");
+#endif
+
__initfunc(void msmouse_setup(char *str, int *ints))
{
if (ints[0] > 0)
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
index 651d5b733..abf08764d 100644
--- a/drivers/char/msp3400.c
+++ b/drivers/char/msp3400.c
@@ -1,21 +1,21 @@
/*
* programming the msp34* sound processor family
*
- * (c) 1997,1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ * (c) 1997,1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
*
* what works and what doesn't:
*
- * AM mono
+ * AM-Mono
* probably doesn't (untested)
*
- * FM-mono
- * should work. FM stereo modes are backward-compatible to mono.
- * Therefore FM mono should always be available.
+ * FM-Mono
+ * should work. The stereo modes are backward compatible to FM-mono,
+ * therefore FM-Mono should be allways available.
*
- * FM stereo (B/G, used in Germany)
+ * FM-Stereo (B/G, used in germany)
* should work, with autodetect
*
- * FM stereo (satellite)
+ * FM-Stereo (satellite)
* should work, no autodetect (i.e. default is mono, but you can
* switch to stereo -- untested)
*
@@ -27,9 +27,14 @@
* TODO:
* - better SAT support
*
+ *
+ * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * using soundcore instead of OSS
+ *
*/
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -37,6 +42,10 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/malloc.h>
+#ifdef __SMP__
+#include <asm/pgtable.h>
+#include <linux/smp_lock.h>
+#endif
/* kernel_thread */
#define __KERNEL_SYSCALLS__
@@ -67,14 +76,14 @@ struct msp3400c {
int mode;
int norm;
int stereo;
+ int main, second; /* sound carrier */
- int mixer;
- int left, right; /* volume */
+ int left, right; /* volume */
int bass, treble;
/* thread */
struct task_struct *thread;
- struct semaphore *wait;
+ struct wait_queue *wq;
struct semaphore *notify;
int active,restart,rmmod;
@@ -88,7 +97,22 @@ struct msp3400c {
#define dprintk if (debug) printk
+#if LINUX_VERSION_CODE < 0x020100
+/* 2.0.x */
+#define signal_pending(current) (current->signal & ~current->blocked)
+#define sigfillset(set)
+#define mdelay(x) udelay(1000*x)
+#else
MODULE_PARM(debug,"i");
+#endif
+
+#if LINUX_VERSION_CODE < 0x02017f
+void schedule_timeout(int j)
+{
+ current->timeout = jiffies + j;
+ schedule();
+}
+#endif
/* ---------------------------------------------------------------------- */
@@ -211,9 +235,9 @@ static struct MSP_INIT_DATA_DEM {
/* FM Radio */
{ { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
MSP_CARRIER(10.7), MSP_CARRIER(10.7),
- 0x00d0, 0x0480, 0x0020, 0x3002 },
+ 0x00d0, 0x0480, 0x0020, 0x3000 },
- /* Terrestial FM-mono */
+ /* Terrestial FM-mono + FM-stereo */
{ { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 },
MSP_CARRIER(5.5), MSP_CARRIER(5.5),
0x00d0, 0x0480, 0x0030, 0x3000},
@@ -230,7 +254,7 @@ static struct MSP_INIT_DATA_DEM {
/* NICAM I */
{ { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ MSP_CARRIER(6.0), MSP_CARRIER(6.0),
0x00d0, 0x0040, 0x0120, 0x3000},
};
@@ -244,7 +268,7 @@ static struct CARRIER_DETECT carrier_detect_main[] = {
{ MSP_CARRIER(4.5), "4.5 NTSC" },
{ MSP_CARRIER(5.5), "5.5 PAL B/G" },
{ MSP_CARRIER(6.0), "6.0 PAL I" },
- { MSP_CARRIER(6.5), "6.5 PAL SAT / SECAM" }
+ { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" }
};
static struct CARRIER_DETECT carrier_detect_55[] = {
@@ -255,6 +279,9 @@ static struct CARRIER_DETECT carrier_detect_55[] = {
static struct CARRIER_DETECT carrier_detect_65[] = {
/* PAL SAT / SECAM */
+ { MSP_CARRIER(5.85), "5.85 PAL D/K NICAM" },
+ { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" },
+ { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" },
{ MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" },
{ MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" },
{ MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" },
@@ -270,6 +297,7 @@ static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2)
msp3400c_write(bus,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12);
msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff);
msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12);
+ msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
}
static void msp3400c_setvolume(struct i2c_bus *bus, int left, int right)
@@ -329,12 +357,14 @@ static void msp3400c_setmode(struct msp3400c *msp, int type)
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005,
msp_init_data[type].fir2[i]);
- msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */
msp_init_data[type].mode_reg);
msp3400c_setcarrier(msp->bus, msp_init_data[type].cdo1,
msp_init_data[type].cdo2);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/
+
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,
msp_init_data[type].dfp_src);
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,
@@ -357,9 +387,9 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode)
/* switch demodulator */
switch (msp->mode) {
case MSP_MODE_FM_TERRA:
- dprintk("msp3400: B/G setstereo: %d\n",mode);
+ dprintk("msp3400: FM setstereo: %d\n",mode);
msp->stereo = mode;
- msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.7421875),MSP_CARRIER(5.5));
+ msp3400c_setcarrier(msp->bus,msp->second,msp->main);
switch (mode) {
case VIDEO_SOUND_STEREO:
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001);
@@ -372,7 +402,7 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode)
}
break;
case MSP_MODE_FM_SAT:
- dprintk("msp3400: sat setstereo: %d\n",mode);
+ dprintk("msp3400: SAT setstereo: %d\n",mode);
msp->stereo = mode;
switch (mode) {
case VIDEO_SOUND_MONO:
@@ -390,9 +420,10 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode)
}
break;
case MSP_MODE_FM_NICAM1:
- dprintk("msp3400: NICAM1 setstereo: %d\n",mode);
+ case MSP_MODE_FM_NICAM2:
+ dprintk("msp3400: NICAM setstereo: %d\n",mode);
msp->stereo = mode;
- msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.85),MSP_CARRIER(5.5));
+ msp3400c_setcarrier(msp->bus,msp->second,msp->main);
nicam=0x0100;
break;
default:
@@ -406,7 +437,9 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode)
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0020|nicam);
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0020|nicam);
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0020|nicam);
+#if 0
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005,0x4000);
+#endif
break;
case VIDEO_SOUND_MONO:
case VIDEO_SOUND_LANG1:
@@ -422,6 +455,27 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode)
}
}
+static void
+msp3400c_print_mode(struct msp3400c *msp)
+{
+ if (msp->main == msp->second) {
+ printk("msp3400: mono sound carrier: %d.%03d MHz\n",
+ msp->main/910000,(msp->main/910)%1000);
+ } else {
+ printk("msp3400: main sound carrier: %d.%03d MHz\n",
+ msp->main/910000,(msp->main/910)%1000);
+ }
+ if (msp->mode == MSP_MODE_FM_NICAM1 ||
+ msp->mode == MSP_MODE_FM_NICAM2)
+ printk("msp3400: NICAM carrier : %d.%03d MHz\n",
+ msp->second/910000,(msp->second/910)%1000);
+ if (msp->mode == MSP_MODE_FM_TERRA &&
+ msp->main != msp->second) {
+ printk("msp3400: FM-stereo carrier : %d.%03d MHz\n",
+ msp->second/910000,(msp->second/910)%1000);
+ }
+}
+
/* ----------------------------------------------------------------------- */
struct REGISTER_DUMP {
@@ -446,21 +500,21 @@ static void msp3400c_stereo_wake(unsigned long data)
{
struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */
- if (!msp->active)
- up(msp->wait);
+ wake_up_interruptible(&msp->wq);
}
static int msp3400c_thread(void *data)
{
- unsigned long flags;
struct msp3400c *msp = data;
- struct semaphore sem = MUTEX_LOCKED;
struct CARRIER_DETECT *cd;
int count, max1,max2,val1,val2, val,this;
int newstereo;
+ LOCK_FLAGS;
- /* lock_kernel(); */
+#ifdef __SMP__
+ lock_kernel();
+#endif
exit_mm(current);
current->session = 1;
@@ -469,10 +523,12 @@ static int msp3400c_thread(void *data)
current->fs->umask = 0;
strcpy(current->comm,"msp3400");
- msp->wait = &sem;
+ msp->wq = NULL;
msp->thread = current;
- /* unlock_kernel(); */
+#ifdef __SMP__
+ unlock_kernel();
+#endif
dprintk("msp3400: thread: start\n");
if(msp->notify != NULL)
@@ -481,9 +537,11 @@ static int msp3400c_thread(void *data)
for (;;) {
if (msp->rmmod)
goto done;
- dprintk("msp3400: thread: sleep\n");
- down_interruptible(&sem);
- dprintk("msp3400: thread: wakeup\n");
+ if (debug > 1)
+ printk("msp3400: thread: sleep\n");
+ interruptible_sleep_on(&msp->wq);
+ if (debug > 1)
+ printk("msp3400: thread: wakeup\n");
if (msp->rmmod || signal_pending(current))
goto done;
@@ -510,6 +568,7 @@ static int msp3400c_thread(void *data)
}
break;
case MSP_MODE_FM_NICAM1:
+ case MSP_MODE_FM_NICAM2:
val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23);
switch ((val & 0x1e) >> 1) {
case 0:
@@ -553,7 +612,7 @@ static int msp3400c_thread(void *data)
msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
UNLOCK_I2C_BUS(msp->bus);
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/25);
if (signal_pending(current))
goto done;
@@ -587,7 +646,7 @@ static int msp3400c_thread(void *data)
msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
UNLOCK_I2C_BUS(msp->bus);
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/25);
if (signal_pending(current))
goto done;
@@ -603,34 +662,56 @@ static int msp3400c_thread(void *data)
dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
}
- /* program the msp3400 according to the results */
+ /* programm the msp3400 according to the results */
+ msp->main = carrier_detect_main[max1].cdo;
switch (max1) {
- case 0: /* 4.5 */
case 1: /* 5.5 */
- msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
- msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
- carrier_detect_main[max1].cdo);
if (max2 == 0) {
/* B/G FM-stereo */
+ msp->second = carrier_detect_55[max2].cdo;
+ msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
msp->watch_stereo = 1;
- }
- if (max2 == 1 && msp->nicam) {
+ } else if (max2 == 1 && msp->nicam) {
/* B/G NICAM */
+ msp->second = carrier_detect_55[max2].cdo;
msp3400c_setmode(msp, MSP_MODE_FM_NICAM1);
- /* msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); */
- msp3400c_setcarrier(msp->bus, MSP_CARRIER(5.85),
- MSP_CARRIER(5.5));
+ msp3400c_setcarrier(msp->bus, msp->second, msp->main);
msp->watch_stereo = 1;
+ } else {
+ goto no_second;
}
break;
case 2: /* 6.0 */
+ /* PAL I NICAM */
+ msp->second = MSP_CARRIER(6.552);
+ msp3400c_setmode(msp, MSP_MODE_FM_NICAM2);
+ msp3400c_setcarrier(msp->bus, msp->second, msp->main);
+ msp->watch_stereo = 1;
+ break;
case 3: /* 6.5 */
+ if (max2 == 1 || max2 == 2) {
+ /* D/K FM-stereo */
+ msp->second = carrier_detect_65[max2].cdo;
+ msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
+ msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+ msp->watch_stereo = 1;
+ } else if (max2 == 0 && msp->nicam) {
+ /* D/K NICAM */
+ msp->second = carrier_detect_65[max2].cdo;
+ msp3400c_setmode(msp, MSP_MODE_FM_NICAM1);
+ msp3400c_setcarrier(msp->bus, msp->second, msp->main);
+ msp->watch_stereo = 1;
+ } else {
+ goto no_second;
+ }
+ break;
+ case 0: /* 4.5 */
default:
+ no_second:
+ msp->second = carrier_detect_main[max1].cdo;
msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
- msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
- carrier_detect_main[max1].cdo);
- msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
+ msp3400c_setcarrier(msp->bus, msp->second, msp->main);
break;
}
@@ -640,15 +721,18 @@ static int msp3400c_thread(void *data)
if (msp->watch_stereo) {
del_timer(&msp->wake_stereo);
- msp->wake_stereo.expires = jiffies + HZ;
+ msp->wake_stereo.expires = jiffies + 2*HZ;
add_timer(&msp->wake_stereo);
}
+
+ if (debug)
+ msp3400c_print_mode(msp);
+
msp->active = 0;
}
done:
dprintk("msp3400: thread: exit\n");
- msp->wait = NULL;
msp->active = 0;
msp->thread = NULL;
@@ -690,6 +774,7 @@ static int msp3410d_thread(void *data)
goto done;
dprintk("msp3410: thread: sleep\n");
down_interruptible(&sem);
+ sem.owner = 0;
dprintk("msp3410: thread: wakeup\n");
if (msp->rmmod)
goto done;
@@ -713,7 +798,8 @@ static int msp3410d_thread(void *data)
/* wait 1 sec */
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ);
+ current->timeout = jiffies + HZ;
+ schedule();
if (signal_pending(current))
goto done;
if (msp->restart) {
@@ -752,9 +838,14 @@ done:
#ifdef REGISTER_MIXER
+#include <linux/sound.h>
#include <linux/soundcard.h>
-#include <../drivers/sound/sound_config.h>
-#include <../drivers/sound/dev_table.h>
+#include <asm/uaccess.h>
+
+static struct msp3400c *mspmix = NULL; /* ugly hack, should do something more sensible */
+static int mixer_num;
+static int mixer_modcnt = 0;
+static struct semaphore mixer_sem = MUTEX;
static int mix_to_v4l(int i)
{
@@ -787,16 +878,42 @@ static int v4l_to_mix2(int l, int r)
return (r << 8) | l;
}
-static int msp3400c_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+static int
+msp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct msp3400c *msp = mixer_devs[dev]->devc;
- unsigned long flags;
int ret,val = 0;
+ LOCK_FLAGS;
+
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strncpy(info.id, "MSP3400", sizeof(info.id));
+ strncpy(info.name, "MSP 3400", sizeof(info.name));
+ info.modify_counter = mixer_modcnt;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strncpy(info.id, "MSP3400", sizeof(info.id));
+ strncpy(info.name, "MSP 3400", sizeof(info.name));
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
if (_SIOC_DIR(cmd) & _SIOC_WRITE)
if (get_user(val, (int *)arg))
return -EFAULT;
+ down(&mixer_sem);
+ if (!mspmix) {
+ up(&mixer_sem);
+ return -ENODEV;
+ }
+
switch (cmd) {
case MIXER_READ(SOUND_MIXER_RECMASK):
case MIXER_READ(SOUND_MIXER_CAPS):
@@ -813,91 +930,97 @@ static int msp3400c_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
break;
case MIXER_WRITE(SOUND_MIXER_VOLUME):
- msp->left = mix_to_v4l(val);
- msp->right = mix_to_v4l(val >> 8);
- LOCK_I2C_BUS(msp->bus);
- msp3400c_setvolume(msp->bus,msp->left,msp->right);
- UNLOCK_I2C_BUS(msp->bus);
+ mspmix->left = mix_to_v4l(val);
+ mspmix->right = mix_to_v4l(val >> 8);
+ LOCK_I2C_BUS(mspmix->bus);
+ msp3400c_setvolume(mspmix->bus,mspmix->left,mspmix->right);
+ UNLOCK_I2C_BUS(mspmix->bus);
+ mixer_modcnt++;
/* fall */
case MIXER_READ(SOUND_MIXER_VOLUME):
- ret = v4l_to_mix2(msp->left, msp->right);
+ ret = v4l_to_mix2(mspmix->left, mspmix->right);
break;
case MIXER_WRITE(SOUND_MIXER_BASS):
- msp->bass = mix_to_v4l(val);
- LOCK_I2C_BUS(msp->bus);
- msp3400c_setbass(msp->bus,msp->bass);
- UNLOCK_I2C_BUS(msp->bus);
+ mspmix->bass = mix_to_v4l(val);
+ LOCK_I2C_BUS(mspmix->bus);
+ msp3400c_setbass(mspmix->bus,mspmix->bass);
+ UNLOCK_I2C_BUS(mspmix->bus);
+ mixer_modcnt++;
/* fall */
case MIXER_READ(SOUND_MIXER_BASS):
- ret = v4l_to_mix(msp->bass);
+ ret = v4l_to_mix(mspmix->bass);
break;
case MIXER_WRITE(SOUND_MIXER_TREBLE):
- msp->treble = mix_to_v4l(val);
- LOCK_I2C_BUS(msp->bus);
- msp3400c_settreble(msp->bus,msp->treble);
- UNLOCK_I2C_BUS(msp->bus);
+ mspmix->treble = mix_to_v4l(val);
+ LOCK_I2C_BUS(mspmix->bus);
+ msp3400c_settreble(mspmix->bus,mspmix->treble);
+ UNLOCK_I2C_BUS(mspmix->bus);
+ mixer_modcnt++;
/* fall */
case MIXER_READ(SOUND_MIXER_TREBLE):
- ret = v4l_to_mix(msp->treble);
+ ret = v4l_to_mix(mspmix->treble);
break;
default:
+ up(&mixer_sem);
return -EINVAL;
}
+ up(&mixer_sem);
if (put_user(ret, (int *)arg))
return -EFAULT;
return 0;
}
-struct mixer_operations msp3400c_mixer = {
- "video4linux",
- "TV card sound (msp3400)",
- msp3400c_mixer_ioctl
-};
-
-static int msp3400c_mixer_init(struct msp3400c *msp)
+static int
+msp3400c_mixer_open(struct inode *inode, struct file *file)
{
- int m;
-
- msp->mixer = m = sound_alloc_mixerdev();
- if (m == -1)
- return -1;
-
- mixer_devs[m] = (struct mixer_operations *)
- kmalloc(sizeof(struct mixer_operations), GFP_KERNEL);
- if (mixer_devs[m] == NULL) {
- printk(KERN_ERR "msp3400c: can't allocate memory\n");
- sound_unload_mixerdev(m);
- return -1;
- }
- memcpy(mixer_devs[m],&msp3400c_mixer,sizeof(struct mixer_operations));
- mixer_devs[m]->devc = msp;
- return 0;
+ MOD_INC_USE_COUNT;
+ return 0;
}
-static int msp3400c_mixer_close(struct msp3400c *msp)
+static int
+msp3400c_mixer_release(struct inode *inode, struct file *file)
{
- int m = msp->mixer;
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
- if (m != -1 ) {
- sound_unload_mixerdev(m);
- kfree(mixer_devs[m]);
- }
- return 0;
+static loff_t
+msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
}
+static /*const*/ struct file_operations msp3400c_mixer_fops = {
+ &msp3400c_mixer_llseek,
+ NULL, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ &msp3400c_mixer_ioctl,
+ NULL, /* mmap */
+ &msp3400c_mixer_open,
+ NULL,
+ &msp3400c_mixer_release,
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL, /* lock */
+};
+
#endif
/* ----------------------------------------------------------------------- */
static int msp3400c_attach(struct i2c_device *device)
{
- unsigned long flags;
struct semaphore sem = MUTEX_LOCKED;
struct msp3400c *msp;
int rev1,rev2;
+ LOCK_FLAGS;
device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL);
if (NULL == msp)
@@ -913,17 +1036,24 @@ static int msp3400c_attach(struct i2c_device *device)
if (-1 == msp3400c_reset(msp->bus)) {
UNLOCK_I2C_BUS(msp->bus);
kfree(msp);
- return -EIO;
+ dprintk("msp3400: no chip found\n");
+ return -1;
}
+ rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e);
+ rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f);
+ if (0 == rev1 && 0 == rev2) {
+ UNLOCK_I2C_BUS(msp->bus);
+ kfree(msp);
+ printk("msp3400: error while reading chip version\n");
+ return -1;
+ }
+
msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
msp3400c_setvolume(msp->bus, msp->left, msp->right);
msp3400c_setbass(msp->bus, msp->bass);
msp3400c_settreble(msp->bus, msp->treble);
- rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e);
- rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f);
-
#if 0
/* this will turn on a 1kHz beep - might be useful for debugging... */
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040);
@@ -932,7 +1062,7 @@ static int msp3400c_attach(struct i2c_device *device)
sprintf(device->name,"MSP34%02d%c-%c%d",
(rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);
- msp->nicam = (((rev2>>8)&0xff) == 10) ? 1 : 0;
+ msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0;
/* timer for stereo checking */
msp->wake_stereo.function = msp3400c_stereo_wake;
@@ -940,19 +1070,20 @@ static int msp3400c_attach(struct i2c_device *device)
/* startup control thread */
MOD_INC_USE_COUNT;
+ msp->wq = NULL;
msp->notify = &sem;
kernel_thread(msp3400c_thread, (void *)msp, 0);
down(&sem);
msp->notify = NULL;
- if (!msp->active)
- up(msp->wait);
+ wake_up_interruptible(&msp->wq);
printk(KERN_INFO "msp3400: init: chip=%s",device->name);
if (msp->nicam)
printk(", has NICAM support");
#ifdef REGISTER_MIXER
- if (0 == msp3400c_mixer_init(msp))
- printk(", registered as sound mixer");
+ down(&mixer_sem);
+ mspmix = msp;
+ up(&mixer_sem);
#endif
printk("\n");
return 0;
@@ -960,12 +1091,14 @@ static int msp3400c_attach(struct i2c_device *device)
static int msp3400c_detach(struct i2c_device *device)
{
- unsigned long flags;
struct semaphore sem = MUTEX_LOCKED;
struct msp3400c *msp = (struct msp3400c*)device->data;
+ LOCK_FLAGS;
#ifdef REGISTER_MIXER
- msp3400c_mixer_close(msp);
+ down(&mixer_sem);
+ mspmix = NULL;
+ up(&mixer_sem);
#endif
/* shutdown control thread */
@@ -974,8 +1107,7 @@ static int msp3400c_detach(struct i2c_device *device)
{
msp->notify = &sem;
msp->rmmod = 1;
- if (!msp->active)
- up(msp->wait);
+ wake_up_interruptible(&msp->wq);
down(&sem);
msp->notify = NULL;
}
@@ -992,9 +1124,10 @@ static int msp3400c_detach(struct i2c_device *device)
static int msp3400c_command(struct i2c_device *device,
unsigned int cmd, void *arg)
{
- unsigned long flags;
struct msp3400c *msp = (struct msp3400c*)device->data;
int *iarg = (int*)arg;
+ __u16 *sarg = arg;
+ LOCK_FLAGS;
switch (cmd) {
case MSP_SET_RADIO:
@@ -1004,74 +1137,79 @@ static int msp3400c_command(struct i2c_device *device,
LOCK_I2C_BUS(msp->bus);
msp3400c_setmode(msp,MSP_MODE_FM_RADIO);
msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
+ msp3400c_setvolume(msp->bus,msp->left, msp->right);
UNLOCK_I2C_BUS(msp->bus);
break;
case MSP_SET_TVNORM:
msp->norm = *iarg;
break;
+ case MSP_SWITCH_MUTE:
+ /* channels switching step one -- mute */
+ msp->watch_stereo=0;
+ del_timer(&msp->wake_stereo);
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setvolume(msp->bus,0,0);
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
case MSP_NEWCHANNEL:
+ /* channels switching step two -- trigger sound carrier scan */
msp->watch_stereo=0;
del_timer(&msp->wake_stereo);
- if (!msp->active)
- up(msp->wait);
- else
+ if (msp->active)
msp->restart = 1;
+ wake_up_interruptible(&msp->wq);
break;
case MSP_GET_VOLUME:
- *iarg = (msp->left > msp->right) ? msp->left : msp->right;
+ *sarg = (msp->left > msp->right) ? msp->left : msp->right;
break;
case MSP_SET_VOLUME:
- msp->left = msp->right = *iarg;
+ msp->left = msp->right = *sarg;
LOCK_I2C_BUS(msp->bus);
msp3400c_setvolume(msp->bus,msp->left, msp->right);
UNLOCK_I2C_BUS(msp->bus);
break;
case MSP_GET_BASS:
- *iarg = msp->bass;
+ *sarg = msp->bass;
break;
case MSP_SET_BASS:
- msp->bass = *iarg;
+ msp->bass = *sarg;
LOCK_I2C_BUS(msp->bus);
msp3400c_setbass(msp->bus,msp->bass);
UNLOCK_I2C_BUS(msp->bus);
break;
case MSP_GET_TREBLE:
- *iarg = msp->treble;
+ *sarg = msp->treble;
break;
case MSP_SET_TREBLE:
- msp->treble = *iarg;
+ msp->treble = *sarg;
LOCK_I2C_BUS(msp->bus);
msp3400c_settreble(msp->bus,msp->treble);
UNLOCK_I2C_BUS(msp->bus);
break;
case MSP_GET_STEREO:
- *iarg = msp->stereo;
+ *sarg = msp->stereo;
break;
case MSP_SET_STEREO:
- if (*iarg) {
+ if (*sarg) {
msp->watch_stereo=0;
del_timer(&msp->wake_stereo);
LOCK_I2C_BUS(msp->bus);
- msp3400c_setstereo(msp,*iarg);
+ msp3400c_setstereo(msp,*sarg);
UNLOCK_I2C_BUS(msp->bus);
}
break;
case MSP_GET_DC:
LOCK_I2C_BUS(msp->bus);
- *iarg = (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) +
- (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
+ *sarg = ((int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) +
+ (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;
}
@@ -1090,8 +1228,6 @@ struct i2c_driver i2c_driver_msp = {
msp3400c_command
};
-EXPORT_NO_SYMBOLS;
-
#ifdef MODULE
int init_module(void)
#else
@@ -1099,6 +1235,10 @@ int init_module(void)
#endif
{
i2c_register_driver(&i2c_driver_msp);
+#ifdef REGISTER_MIXER
+ if ((mixer_num = register_sound_mixer(&msp3400c_mixer_fops, -1)) < 0)
+ printk(KERN_ERR "msp3400c: cannot allocate mixer device\n");
+#endif
return 0;
}
@@ -1106,6 +1246,10 @@ int init_module(void)
void cleanup_module(void)
{
i2c_unregister_driver(&i2c_driver_msp);
+#ifdef REGISTER_MIXER
+ if (mixer_num >= 0)
+ unregister_sound_mixer(mixer_num);
+#endif
}
#endif
diff --git a/drivers/char/msp3400.h b/drivers/char/msp3400.h
index 8b093ff05..7f0ba30e5 100644
--- a/drivers/char/msp3400.h
+++ b/drivers/char/msp3400.h
@@ -7,19 +7,19 @@
#define MSP_SET_RADIO _IO('m',2) /* Radio mode */
#define MSP_NEWCHANNEL _IO('m',3) /* indicate new channel */
-#define MSP_GET_VOLUME _IOR('m',4,int)
-#define MSP_SET_VOLUME _IOW('m',5,int)
+#define MSP_GET_VOLUME _IOR('m',4,__u16)
+#define MSP_SET_VOLUME _IOW('m',5,__u16)
-#define MSP_GET_STEREO _IOR('m',6,int)
-#define MSP_SET_STEREO _IOW('m',7,int)
+#define MSP_GET_STEREO _IOR('m',6,__u16)
+#define MSP_SET_STEREO _IOW('m',7,__u16)
-#define MSP_GET_DC _IOW('m',8,int)
+#define MSP_GET_DC _IOW('m',8,__u16)
-#define MSP_GET_BASS _IOR('m', 9,int)
-#define MSP_SET_BASS _IOW('m',10,int)
-#define MSP_GET_TREBLE _IOR('m',11,int)
-#define MSP_SET_TREBLE _IOW('m',12,int)
-
-#define MSP_GET_UNIT _IOR('m',13,int)
+#define MSP_GET_BASS _IOR('m', 9,__u16)
+#define MSP_SET_BASS _IOW('m',10,__u16)
+#define MSP_GET_TREBLE _IOR('m',11,__u16)
+#define MSP_SET_TREBLE _IOW('m',12,__u16)
+#define MSP_GET_UNIT _IOR('m',13,int)
+#define MSP_SWITCH_MUTE _IO('m',14)
#endif /* MSP3400_H */
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 5456640cb..4bf35716b 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -73,7 +73,8 @@ static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
*/
static void check_unthrottle(struct tty_struct * tty)
{
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ if (tty->count &&
+ test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->driver.unthrottle)
tty->driver.unthrottle(tty);
}
@@ -921,17 +922,21 @@ do_it_again:
}
}
- add_wait_queue(&tty->read_wait, &wait);
+ if (down_interruptible(&tty->atomic_read))
+ return -ERESTARTSYS;
- disable_bh(TQUEUE_BH);
+ add_wait_queue(&tty->read_wait, &wait);
+ set_bit(TTY_DONT_FLIP, &tty->flags);
while (nr) {
/* First test for status change. */
if (tty->packet && tty->link->ctrl_status) {
+ unsigned char cs;
if (b != buf)
break;
- put_user(tty->link->ctrl_status, b++);
- nr--;
+ cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
+ put_user(cs, b++);
+ nr--;
break;
}
/* This statement must be first before checking for input
@@ -960,9 +965,9 @@ do_it_again:
retval = -ERESTARTSYS;
break;
}
- enable_bh(TQUEUE_BH);
+ clear_bit(TTY_DONT_FLIP, &tty->flags);
timeout = schedule_timeout(timeout);
- disable_bh(TQUEUE_BH);
+ set_bit(TTY_DONT_FLIP, &tty->flags);
continue;
}
current->state = TASK_RUNNING;
@@ -1024,7 +1029,8 @@ do_it_again:
if (time)
timeout = time;
}
- enable_bh(TQUEUE_BH);
+ clear_bit(TTY_DONT_FLIP, &tty->flags);
+ up(&tty->atomic_read);
remove_wait_queue(&tty->read_wait, &wait);
if (!waitqueue_active(&tty->read_wait))
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index a795cf21c..f4a4d51f3 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -56,6 +56,7 @@ static void kbd_write_command_w(int data);
static void kbd_write_output_w(int data);
spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+static unsigned char handle_kbd_event(void);
/* used only by send_data - set by keyboard_interrupt */
static volatile unsigned char reply_expected = 0;
@@ -80,7 +81,7 @@ static int aux_count = 0;
#endif /* CONFIG_PSMOUSE */
/*
- * Wait for keyboard controller input buffer is empty.
+ * Wait for keyboard controller input buffer to drain.
*
* Don't use 'jiffies' so that we don't depend on
* interrupts..
@@ -98,17 +99,13 @@ static inline void kb_wait(void)
unsigned char status;
do {
- status = kbd_read_status();
- kbd_pause();
- if (status & KBD_STAT_OBF) {
- if (status & KBD_STAT_MOUSE_OBF)
- kbd_read_input(); /* Flush */
- kbd_pause();
- }
+ /*
+ * "handle_kbd_event()" will handle any incoming events
+ * while we wait - keypresses or mouse movement.
+ */
+ unsigned char status = handle_kbd_event();
- status = kbd_read_status();
- kbd_pause();
- if (!(status & KBD_STAT_IBF))
+ if (! (status & KBD_STAT_IBF))
return;
mdelay(1);
timeout--;
@@ -254,20 +251,6 @@ int pckbd_getkeycode(unsigned int scancode)
e0_keys[scancode - 128];
}
-#if DISABLE_KBD_DURING_INTERRUPTS
-static inline void send_cmd(unsigned char c)
-{
- kb_wait();
- kbd_write_command(c);
-}
-
-#define disable_keyboard() send_cmd(KBD_CCMD_KBD_DISABLE)
-#define enable_keyboard() send_cmd(KBD_CCMD_KBD_ENABLE)
-#else
-#define disable_keyboard() /* nothing */
-#define enable_keyboard() /* nothing */
-#endif
-
static int do_acknowledge(unsigned char scancode)
{
if (reply_expected) {
@@ -412,16 +395,17 @@ char pckbd_unexpected_up(unsigned char keycode)
return 0200;
}
-void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+/*
+ * This reads the keyboard status port, and does the
+ * appropriate action.
+ *
+ * It requires that we hold the keyboard controller
+ * spinlock.
+ */
+static unsigned char handle_kbd_event(void)
{
- unsigned long flags;
- unsigned char status;
-
- spin_lock_irqsave(&kbd_controller_lock, flags);
- disable_keyboard();
- kbd_pt_regs = regs;
+ unsigned char status = kbd_read_status();
- status = kbd_read_status();
while (status & KBD_STAT_OBF) {
unsigned char scancode;
@@ -452,7 +436,17 @@ void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = kbd_read_status();
}
- enable_keyboard();
+ return status;
+}
+
+static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ kbd_pt_regs = regs;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ handle_kbd_event();
spin_unlock_irqrestore(&kbd_controller_lock, flags);
}
@@ -718,6 +712,52 @@ void __init pckbd_init_hw(void)
}
#if defined CONFIG_PSMOUSE
+
+/*
+ * Check if this is a dual port controller.
+ */
+static int __init detect_auxiliary_port(void)
+{
+ unsigned long flags;
+ unsigned char status;
+ unsigned char val;
+ int loops = 5;
+ int retval = 0;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+
+ /* Put the value 0x5A in the output buffer using the "Write
+ * Auxiliary Device Output Buffer" command (0xD3). Poll the
+ * Status Register for a while to see if the value really
+ * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF
+ * bit is also set to 1 in the Status Register, we assume this
+ * controller has an Auxiliary Port (a.k.a. Mouse Port).
+ */
+ kb_wait();
+ kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF);
+
+ kb_wait();
+ kbd_write_output(0x5a); /* 0x5a is a random dummy value. */
+
+ status = kbd_read_status();
+ while (!(status & KBD_STAT_OBF) && loops--) {
+ mdelay(1);
+ status = kbd_read_status();
+ }
+
+ if (status & KBD_STAT_OBF) {
+ val = kbd_read_input();
+ if (val == 0x5a && (status & KBD_STAT_MOUSE_OBF)) {
+ printk(KERN_INFO "Detected PS/2 Mouse Port.\n");
+ retval = 1;
+ }
+ }
+
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+
+ return retval;
+}
+
/*
* Send a byte to the mouse.
*/
@@ -763,6 +803,11 @@ static int fasync_aux(int fd, struct file *filp, int on)
}
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
static int release_aux(struct inode * inode, struct file * file)
{
fasync_aux(-1, file, 0);
@@ -898,18 +943,9 @@ static struct miscdevice psaux_mouse = {
static int __init psaux_init(void)
{
-#if 0
- /*
- * Don't bother with the BIOS flag: even if we don't have
- * a mouse connected at bootup we may still want to connect
- * one later, and we don't want to just let the BIOS tell
- * us that it has no mouse..
- */
- if (aux_device_present != 0xaa)
+ if (!detect_auxiliary_port())
return -EIO;
- printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
-#endif
misc_register(&psaux_mouse);
queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
memset(queue, 0, sizeof(*queue));
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index b1c1bb3e3..26b1033c3 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -70,6 +70,7 @@
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/init.h>
+#include <linux/version.h>
#ifndef MODULE
#include <linux/ctype.h> /* We only need it for parsing the "digi="-line */
diff --git a/drivers/char/pms.c b/drivers/char/pms.c
index 8886b59be..252929f82 100644
--- a/drivers/char/pms.c
+++ b/drivers/char/pms.c
@@ -221,7 +221,7 @@ static void pms_colour(short colour)
pms_i2c_write(0x8A, 0x00, colour);
break;
case PHILIPS1:
- pms_i2c_write(0x42, 012, colour);
+ pms_i2c_write(0x42, 0x12, colour);
break;
}
}
diff --git a/drivers/char/radio-aimslab.c b/drivers/char/radio-aimslab.c
index 59d95042e..97d13882f 100644
--- a/drivers/char/radio-aimslab.c
+++ b/drivers/char/radio-aimslab.c
@@ -101,6 +101,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
outb(0x48, io); /* volume down but still "on" */
sleep_delay(2000000); /* make sure it's totally down */
outb(0xd0, io); /* volume steady, off */
+ dev->curvol = 0; /* track the volume state! */
return 0;
}
diff --git a/drivers/char/radio-gemtek.c b/drivers/char/radio-gemtek.c
new file mode 100644
index 000000000..1bfe30e30
--- /dev/null
+++ b/drivers/char/radio-gemtek.c
@@ -0,0 +1,310 @@
+/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi>
+ *
+ * GemTek hasn't released any specs on the card, so the protocol had to
+ * be reverse engineered with dosemu.
+ *
+ * Besides the protocol changes, this is mostly a copy of:
+ *
+ * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
+ *
+ * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
+ * Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
+ *
+ * TODO: Allow for more than one of these foolish entities :-)
+ *
+ */
+
+#include <linux/module.h> /* Modules */
+#include <linux/init.h> /* Initdata */
+#include <linux/ioport.h> /* check_region, request_region */
+#include <linux/delay.h> /* udelay */
+#include <asm/io.h> /* outb, outb_p */
+#include <asm/uaccess.h> /* copy to/from user */
+#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
+
+#ifndef CONFIG_RADIO_GEMTEK_PORT
+#define CONFIG_RADIO_GEMTEK_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_GEMTEK_PORT;
+static int users = 0;
+
+struct gemtek_device
+{
+ int port;
+ unsigned long curfreq;
+ int muted;
+};
+
+
+/* local things */
+
+/* the correct way to mute the gemtek may be to write the last written
+ * frequency || 0x10, but just writing 0x10 once seems to do it as well
+ */
+static void gemtek_mute(struct gemtek_device *dev)
+{
+ if(dev->muted)
+ return;
+ outb(0x10, io);
+ dev->muted = 1;
+}
+
+static void gemtek_unmute(struct gemtek_device *dev)
+{
+ if(dev->muted == 0)
+ return;
+ outb(0x20, io);
+ dev->muted = 0;
+}
+
+static void zero(void)
+{
+ outb_p(0x04, io);
+ udelay(5);
+ outb_p(0x05, io);
+ udelay(5);
+}
+
+static void one(void)
+{
+ outb_p(0x06, io);
+ udelay(5);
+ outb_p(0x07, io);
+ udelay(5);
+}
+
+static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+{
+ int i;
+
+/* freq = 78.25*((float)freq/16000.0 + 10.52); */
+
+ freq /= 16;
+ freq += 10520;
+ freq *= 7825;
+ freq /= 100000;
+
+ /* 2 start bits */
+ outb_p(0x03, io);
+ udelay(5);
+ outb_p(0x07, io);
+ udelay(5);
+
+ /* 28 frequency bits (lsb first) */
+ for (i = 0; i < 14; i++)
+ if (freq & (1 << i))
+ one();
+ else
+ zero();
+ /* 36 unknown bits */
+ for (i = 0; i < 11; i++)
+ zero();
+ one();
+ for (i = 0; i < 4; i++)
+ zero();
+ one();
+ zero();
+
+ /* 2 end bits */
+ outb_p(0x03, io);
+ udelay(5);
+ outb_p(0x07, io);
+ udelay(5);
+
+ return 0;
+}
+
+int gemtek_getsigstr(struct gemtek_device *dev)
+{
+ inb(io);
+ udelay(5);
+ if (inb(io) & 8) /* bit set = no signal present */
+ return 0;
+ return 1; /* signal present */
+}
+
+static int gemtek_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct gemtek_device *rt=dev->priv;
+
+ switch(cmd)
+ {
+ case VIDIOCGCAP:
+ {
+ struct video_capability v;
+ 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;
+ strcpy(v.name, "GemTek");
+ 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=87*16000;
+ v.rangehigh=108*16000;
+ v.flags=VIDEO_TUNER_LOW;
+ v.mode=VIDEO_MODE_AUTO;
+ v.signal=0xFFFF*gemtek_getsigstr(rt);
+ 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, &rt->curfreq, sizeof(rt->curfreq)))
+ return -EFAULT;
+ return 0;
+ case VIDIOCSFREQ:
+ if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq)))
+ return -EFAULT;
+ /* needs to be called twice in order for getsigstr to work */
+ gemtek_setfreq(rt, rt->curfreq);
+ gemtek_setfreq(rt, rt->curfreq);
+ return 0;
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio v;
+ 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;
+ 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)
+ gemtek_mute(rt);
+ else
+ gemtek_unmute(rt);
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int gemtek_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void gemtek_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct gemtek_device gemtek_unit;
+
+static struct video_device gemtek_radio=
+{
+ "GemTek radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_GEMTEK,
+ gemtek_open,
+ gemtek_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL, /* Can't poll */
+ gemtek_ioctl,
+ NULL,
+ NULL
+};
+
+__initfunc(int gemtek_init(struct video_init *v))
+{
+ if (check_region(io, 4))
+ {
+ printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+
+ gemtek_radio.priv=&gemtek_unit;
+
+ if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ request_region(io, 4, "gemtek");
+ printk(KERN_INFO "GemTek Radio Card driver.\n");
+
+ /* mute card - prevents noisy bootups */
+ outb(0x10, io);
+ udelay(5);
+ gemtek_unit.muted = 1;
+
+ /* this is _maybe_ unnecessary */
+ outb(0x01, io);
+
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Jonas Munsin");
+MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c\n");
+ return -EINVAL;
+ }
+ return gemtek_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ video_unregister_device(&gemtek_radio);
+ release_region(io,4);
+}
+
+#endif
+
+/*
+ Local variables:
+ compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
+ End:
+*/
diff --git a/drivers/char/radio-zoltrix.c b/drivers/char/radio-zoltrix.c
index 115606ac3..80a72d4b4 100644
--- a/drivers/char/radio-zoltrix.c
+++ b/drivers/char/radio-zoltrix.c
@@ -12,6 +12,15 @@
* to get fine volume control over the low volume range.
*
* Some code derived from code by Frans Brinkman
+ *
+ * 1999-01-05 - (C. van Schaik)
+ * - Changed tuning to 1/160Mhz accuracy
+ * - Added stereo support
+ * (card defaults to stereo)
+ * (can explicitly force mono on the card)
+ * (can detect if station is in stereo)
+ * - Added unmute function
+ * - Reworked ioctl functions
*/
#include <linux/module.h> /* Modules */
@@ -35,6 +44,7 @@ struct zol_device {
int curvol;
unsigned long curfreq;
int muted;
+ unsigned int stereo;
};
@@ -54,61 +64,63 @@ static void sleep_delay(long n)
}
}
+static int zol_setvol(struct zol_device *dev, int vol)
+{
+ dev->curvol = vol;
+ if (dev->muted)
+ return 0;
+
+ if (vol == 0) {
+ outb(0, io);
+ outb(0, io);
+ inb(io + 3); /* Zoltrix needs to be read to confirm */
+ return 0;
+ }
+
+ outb(dev->curvol-1, io);
+ sleep_delay(10000);
+ inb(io + 2);
+
+ return 0;
+}
+
static void zol_mute(struct zol_device *dev)
{
dev->muted = 1;
outb(0, io);
outb(0, io);
- inb(io + 3); /* Zoltrix needs to be read to confirm */
-}
-
-static void zol_on(int vol)
-{
- int l;
- outb(vol, io);
- sleep_delay(10000);
- l = inb(io + 2);
+ inb(io + 3); /* Zoltrix needs to be read to confirm */
}
-static int zol_setvol(struct zol_device *dev, int vol)
+static void zol_unmute(struct zol_device *dev)
{
- if (vol == dev->curvol) { /* requested volume = current */
- if (dev->muted) { /* user is unmuting the card */
- dev->muted = 0;
- zol_on(vol);
- }
- return 0;
- }
- if (vol == 0) { /* volume = 0 means mute the card */
- zol_mute(dev);
- return 0;
- }
dev->muted = 0;
- dev->curvol = vol;
-
- zol_on(vol);
-
- return 0;
+ zol_setvol(dev, dev->curvol);
}
static int zol_setfreq(struct zol_device *dev, unsigned long freq)
{
/* tunes the radio to the desired frequency */
unsigned long long bitmask, f, m;
+ unsigned int stereo = dev->stereo;
int i;
- m = (freq * 25 / 4 - 8800) * 2;
+ if (freq == 0)
+ return 1;
+ m = (freq / 160 - 8800) * 2;
f = (unsigned long long) m + 0x4d1c;
bitmask = 0xc480402c10080000ull;
i = 45;
- zol_mute(dev);
+ outb(0, io);
+ outb(0, io);
+ inb(io + 3); /* Zoltrix needs to be read to confirm */
outb(0x40, io);
outb(0xc0, io);
- bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( /*stereo */ 0 << 31));
+ bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31));
while (i--) {
if ((bitmask & 0x8000000000000000ull) != 0) {
outb(0x80, io);
@@ -131,7 +143,18 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
outb(0x80, io);
outb(0xc0, io);
outb(0x40, io);
- zol_on(dev->curvol);
+ sleep_delay(1000);
+ inb(io+2);
+
+ sleep_delay(1000);
+ if (dev->muted)
+ {
+ outb(0, io);
+ outb(0, io);
+ inb(io + 3);
+ sleep_delay(1000);
+ } else
+ zol_setvol(dev, dev->curvol);
return 0;
}
@@ -149,27 +172,42 @@ int zol_getsigstr(struct zol_device *dev)
sleep_delay(1000);
b = inb(io);
- if ((a == b) && (a == 0xdf)) /* I found this out by playing */
- /* with a binary scanner on the card io */
- return (1);
- else
+ if (a != b)
return (0);
- if (inb(io) & 2) /* bit set = no signal present */
- return 0;
- return 1; /* signal present */
+ if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
+ || (a == 0xef)) /* with a binary scanner on the card io */
+ return (1);
+ return (0);
+}
+
+int zol_is_stereo (struct zol_device *dev)
+{
+ int x1, x2;
+
+ outb(0x00, io);
+ outb(dev->curvol, io);
+ sleep_delay(20000);
+
+ x1 = inb(io);
+ sleep_delay(1000);
+ x2 = inb(io);
+
+ if ((x1 == x2) && (x1 == 0xcf))
+ return 1;
+ return 0;
}
static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
- struct zol_device *rt = dev->priv;
+ struct zol_device *zol = dev->priv;
switch (cmd) {
case VIDIOCGCAP:
{
struct video_capability v;
v.type = VID_TYPE_TUNER;
- v.channels = 1;
+ v.channels = 1 + zol->stereo;
v.audios = 1;
/* No we don't do pictures */
v.maxwidth = 0;
@@ -184,15 +222,21 @@ static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCGTUNER:
{
struct video_tuner v;
- if (copy_from_user(&v, arg, sizeof(v)) != 0)
+/*
+ if (copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
- if (v.tuner) /* Only 1 tuner */
+ if (v.tuner)
return -EINVAL;
- v.rangelow = (int) (88.0 * 16);
- v.rangehigh = (int) (108.0 * 16);
- v.flags = 0;
+*/
+ v.tuner = 0;
+ strcpy(v.name, "Zoltrix Radio");
+ v.rangelow = (int) (88.0 * 16000);
+ v.rangehigh = (int) (108.0 * 16000);
+ v.flags = zol_is_stereo(zol)
+ ? VIDEO_TUNER_STEREO_ON : 0;
+ v.flags |= VIDEO_TUNER_LOW;
v.mode = VIDEO_MODE_AUTO;
- v.signal = 0xFFFF * zol_getsigstr(rt);
+ v.signal = 0xFFFF * zol_getsigstr(zol);
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0;
@@ -208,22 +252,24 @@ static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return 0;
}
case VIDIOCGFREQ:
- if (copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq)))
+ if (copy_to_user(arg, &zol->curfreq, sizeof(zol->curfreq)))
return -EFAULT;
return 0;
case VIDIOCSFREQ:
- if (copy_from_user(&rt->curfreq, arg, sizeof(rt->curfreq)))
+ if (copy_from_user(&zol->curfreq, arg, sizeof(zol->curfreq)))
return -EFAULT;
- zol_setfreq(rt, rt->curfreq);
+ zol_setfreq(zol, zol->curfreq);
return 0;
case VIDIOCGAUDIO:
{
struct video_audio v;
memset(&v, 0, sizeof(v));
v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
- v.volume = rt->curvol * 4096;
+ v.mode != zol_is_stereo(zol)
+ ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ v.volume = zol->curvol * 4096;
v.step = 4096;
- strcpy(v.name, "Radio");
+ strcpy(v.name, "Zoltrix Radio");
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0;
@@ -237,9 +283,23 @@ static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EINVAL;
if (v.flags & VIDEO_AUDIO_MUTE)
- zol_mute(rt);
+ zol_mute(zol);
else
- zol_setvol(rt, v.volume / 4096);
+ zol_unmute(zol);
+
+ if (v.flags & VIDEO_AUDIO_VOLUME)
+ zol_setvol(zol, v.volume / 4096);
+
+ if (v.mode & VIDEO_SOUND_STEREO)
+ {
+ zol->stereo = 1;
+ zol_setfreq(zol, zol->curfreq);
+ }
+ if (v.mode & VIDEO_SOUND_MONO)
+ {
+ zol->stereo = 0;
+ zol_setfreq(zol, zol->curfreq);
+ }
return 0;
}
@@ -286,6 +346,10 @@ __initfunc(int zoltrix_init(struct video_init *v))
printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
return -EBUSY;
}
+ if ((io != 0x20c) && (io != 0x30c)) {
+ printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n");
+ return -ENXIO;
+ }
zoltrix_radio.priv = &zoltrix_unit;
if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1)
@@ -304,6 +368,7 @@ __initfunc(int zoltrix_init(struct video_init *v))
inb(io + 3);
zoltrix_unit.curvol = 0;
+ zoltrix_unit.stereo = 1;
return 0;
}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index c980d5192..f78974d69 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -232,6 +232,11 @@
* Eastlake, Steve Crocker, and Jeff Schiller.
*/
+/*
+ * Added a check for signal pending in the extract_entropy() loop to allow
+ * the read(2) syscall to be interrupted. Copyright (C) 1998 Andrea Arcangeli
+ */
+
#include <linux/utsname.h>
#include <linux/config.h>
#include <linux/kernel.h>
@@ -1269,7 +1274,14 @@ static ssize_t extract_entropy(struct random_bucket *r, char * buf,
buf += i;
add_timer_randomness(r, &extract_timer_state, nbytes);
if (to_user && current->need_resched)
+ {
+ if (signal_pending(current))
+ {
+ ret = -EINTR;
+ break;
+ }
schedule();
+ }
}
/* Wipe data just returned from memory */
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 7da0fa512..7764997b5 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -228,7 +228,7 @@ extern inline void rc_long_delay(unsigned long delay)
{
unsigned long i;
- for (i = jiffies + delay; i > jiffies; ) ;
+ for (i = jiffies + delay; time_after(i,jiffies); ) ;
}
/* Reset and setup CD180 chip */
@@ -1172,8 +1172,8 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
timeout = jiffies+HZ;
while(port->IER & IER_TXEMPTY) {
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(port->timeout);
- if (jiffies > timeout)
+ schedule_timeout(port->timeout);
+ if (time_after(jiffies, timeout))
break;
}
}
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 6a26bb088..5fde4639e 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -94,7 +94,7 @@ void mask_rtc_irq_bit(unsigned char bit);
static inline unsigned char rtc_is_updating(void);
/*
- * Bits in rtc_status. (7 bits of room for future expansion)
+ * Bits in rtc_status. (6 bits of room for future expansion)
*/
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
diff --git a/drivers/char/saa5249.c b/drivers/char/saa5249.c
index bc49cb80b..2e93553c5 100644
--- a/drivers/char/saa5249.c
+++ b/drivers/char/saa5249.c
@@ -460,7 +460,7 @@ static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg)
if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) && /* check FOUND-bit */
(memcmp(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits)) ||
- jiffies >= t->vdau[req.pgbuf].expire))
+ time_after_eq(jiffies, t->vdau[req.pgbuf].expire)))
{ /* check if new page arrived */
if (i2c_senddata(t, CCTWR, 8, 0, 0, 0, -1) ||
i2c_getdata(t, CCTRD, VTX_PAGESIZE, t->vdau[req.pgbuf].pgbuf, FALSE))
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index e352813cc..08fa90aa5 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -156,7 +156,7 @@
#endif
static char *serial_name = "Serial driver";
-static char *serial_version = "4.26";
+static char *serial_version = "4.27";
static DECLARE_TASK_QUEUE(tq_serial);
@@ -182,7 +182,7 @@ static struct console sercons;
static unsigned detect_uart_irq (struct serial_state * state);
static void autoconfig(struct serial_state * info);
-static void change_speed(struct async_struct *info);
+static void change_speed(struct async_struct *info, struct termios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
/*
@@ -196,7 +196,7 @@ static struct serial_uart_config uart_config[] = {
{ "16550", 1, 0 },
{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO },
{ "cirrus", 1, 0 },
- { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH },
+ { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH },
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
@@ -1132,7 +1132,7 @@ static int startup(struct async_struct * info)
/*
* and set the speed of the serial port
*/
- change_speed(info);
+ change_speed(info, 0);
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
@@ -1255,7 +1255,8 @@ static void shutdown(struct async_struct * info)
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static void change_speed(struct async_struct *info)
+static void change_speed(struct async_struct *info,
+ struct termios *old_termios)
{
unsigned short port;
int quot = 0, baud_base, baud;
@@ -1306,7 +1307,25 @@ static void change_speed(struct async_struct *info)
else if (baud)
quot = baud_base / baud;
}
- /* If the quotient is ever zero, default to 9600 bps */
+ /* If the quotient is zero refuse the change */
+ if (!quot && old_termios) {
+ info->tty->termios->c_cflag &= ~CBAUD;
+ info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ baud = tty_get_baud_rate(info->tty);
+ if (!baud)
+ baud = 9600;
+ if (baud == 38400 &&
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ quot = info->state->custom_divisor;
+ else {
+ if (baud == 134)
+ /* Special case since 134 is really 134.5 */
+ quot = (2*baud_base / 269);
+ else if (baud)
+ quot = baud_base / baud;
+ }
+ }
+ /* As a last resort, if the quotient is zero, default to 9600 bps */
if (!quot)
quot = baud_base / 9600;
info->quot = quot;
@@ -1675,8 +1694,8 @@ static int set_serial_info(struct async_struct * info,
return -EPERM;
state->flags = ((state->flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK));
- info->flags = ((state->flags & ~ASYNC_USR_MASK) |
- (info->flags & ASYNC_USR_MASK));
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
state->custom_divisor = new_serial.custom_divisor;
goto check_and_exit;
}
@@ -1684,7 +1703,7 @@ static int set_serial_info(struct async_struct * info,
new_serial.irq = irq_cannonicalize(new_serial.irq);
if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
- (new_serial.baud_base == 0) || (new_serial.type < PORT_UNKNOWN) ||
+ (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
(new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
(new_serial.type == PORT_STARTECH)) {
return -EINVAL;
@@ -1755,7 +1774,7 @@ check_and_exit:
info->tty->alt_speed = 230400;
if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
- change_speed(info);
+ change_speed(info, 0);
}
} else
retval = startup(info);
@@ -2025,7 +2044,6 @@ static int set_multiport_struct(struct async_struct * info,
"driver!!\n");
}
}
-
return 0;
}
#endif
@@ -2172,7 +2190,7 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
- change_speed(info);
+ change_speed(info, old_termios);
/* Handle transition to B0 status */
if ((old_termios->c_cflag & CBAUD) &&
@@ -2360,6 +2378,17 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
char_time = 1;
if (timeout)
char_time = MIN(char_time, timeout);
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2*info->timeout)
+ timeout = 2*info->timeout;
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
printk("jiff=%lu...", jiffies);
@@ -2373,7 +2402,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
schedule_timeout(char_time);
if (signal_pending(current))
break;
- if (timeout && ((orig_jiffies + timeout) < jiffies))
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
current->state = TASK_RUNNING;
@@ -2667,13 +2696,13 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
*tty->termios = info->state->normal_termios;
else
*tty->termios = info->state->callout_termios;
- change_speed(info);
+ change_speed(info, 0);
}
#ifdef CONFIG_SERIAL_CONSOLE
if (sercons.cflag && sercons.index == line) {
tty->termios->c_cflag = sercons.cflag;
sercons.cflag = 0;
- change_speed(info);
+ change_speed(info, 0);
}
#endif
info->session = current->session;
@@ -2903,8 +2932,8 @@ static unsigned detect_uart_irq (struct serial_state * state)
* This routine is called by rs_init() to initialize a specific serial
* port. It determines what type of UART chip this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
- * whether or not this UART is a 16550A or not, since this will
- * determine whether or not we can use its FIFO features or not.
+ * whether or not this UART is a 16550A, since this will determine
+ * whether or not we can use its FIFO features.
*/
static void autoconfig(struct serial_state * state)
{
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 72d1f6276..57bae3ebf 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -353,7 +353,7 @@ extern inline void sx_long_delay(unsigned long delay)
{
unsigned long i;
- for (i = jiffies + delay; i > jiffies; ) ;
+ for (i = jiffies + delay; time_after(i, jiffies); ) ;
}
@@ -1073,7 +1073,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
/* Set baud rate for port */
tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
CD186x_TPC/2) / CD186x_TPC);
- if ((tmp < 0x10) && (again < jiffies)) {
+ if ((tmp < 0x10) && time_before(again, jiffies)) {
again = jiffies + HZ * 60;
/* Page 48 of version 2.0 of the CL-CD1865 databook */
if (tmp >= 12) {
@@ -1551,8 +1551,8 @@ static void sx_close(struct tty_struct * tty, struct file * filp)
timeout = jiffies+HZ;
while(port->IER & IER_TXEMPTY) {
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(port->timeout);
- if (jiffies > timeout) {
+ schedule_timeout(port->timeout);
+ if (time_after(jiffies, timeout)) {
printk (KERN_INFO "Timeout waiting for close\n");
break;
}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 0b2f495b1..dd27a4e26 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -1697,7 +1697,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout)
if (signal_pending(current))
break;
stl_delay(2);
- if (jiffies >= tend)
+ if (time_after_eq(jiffies, tend))
break;
}
}
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 4878d877e..30e0260b7 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -571,7 +571,7 @@ static int wait_for_ready(time_t timeout)
timeout -= spin_t;
spin_t += jiffies;
- while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffies<spin_t))
+ while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t))
schedule(); /* don't waste all the CPU time */
if ((stat & QIC02_STAT_READY) == 0)
return TE_OK;
@@ -586,7 +586,7 @@ static int wait_for_ready(time_t timeout)
TPQDEB({printk("wait_for_ready: additional timeout: %d\n", spin_t);})
/* not ready and no exception && timeout not expired yet */
- while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffies<spin_t)) {
+ while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t)) {
/* be `nice` to other processes on long operations... */
current->state = TASK_INTERRUPTIBLE;
/* nap 0.30 sec between checks, */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 192e5350c..05a4f246e 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -77,9 +77,7 @@
#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/poll.h>
-#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
-#endif
#include <linux/init.h>
#include <linux/smp_lock.h>
@@ -91,9 +89,7 @@
#include <linux/vt_kern.h>
#include <linux/selection.h>
-#ifdef CONFIG_KMOD
#include <linux/kmod.h>
-#endif
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
@@ -221,7 +217,6 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
return -EINVAL;
-#ifdef CONFIG_KMOD
/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
/* Cyrus Durgin <cider@speakeasy.org> */
if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
@@ -229,7 +224,6 @@ static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
sprintf(modname, "tty-ldisc-%d", ldisc);
request_module (modname);
}
-#endif
if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
return -EINVAL;
@@ -868,12 +862,7 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
* Failures after this point use release_mem to clean up, so
* there's no need to null out the local pointers.
*/
- driver->table[idx] = tty; /* FIXME: this is broken and
- probably causes ^D bug. tty->private_date does not (yet) point
- to a console, if keypress comes now, await armagedon.
-
- also, driver->table is accessed from interrupt for vt case,
- and this does not look like atomic access at all. */
+ driver->table[idx] = tty;
if (!*tp_loc)
*tp_loc = tp;
@@ -1848,6 +1837,10 @@ static void flush_to_ldisc(void *private_)
int count;
unsigned long flags;
+ if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ return;
+ }
if (tty->flip.buf_num) {
cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
@@ -1874,14 +1867,22 @@ static void flush_to_ldisc(void *private_)
/*
* Routine which returns the baud rate of the tty
- */
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
*/
static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+ 76800, 153600, 307200, 614400, 921600
+#else
+ 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+ 2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+static int n_baud_table = sizeof(baud_table)/sizeof(int);
int tty_get_baud_rate(struct tty_struct *tty)
{
@@ -1892,7 +1893,7 @@ int tty_get_baud_rate(struct tty_struct *tty)
i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
- if (i < 1 || i > 4)
+ if (i < 1 || i+15 >= n_baud_table)
tty->termios->c_cflag &= ~CBAUDEX;
else
i += 15;
@@ -1932,6 +1933,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty->flip.pty_sem = MUTEX;
tty->tq_hangup.routine = do_tty_hangup;
tty->tq_hangup.data = tty;
+ sema_init(&tty->atomic_read, 1);
}
/*
@@ -1966,9 +1968,7 @@ int tty_register_driver(struct tty_driver *driver)
if (tty_drivers) tty_drivers->prev = driver;
tty_drivers = driver;
-#ifdef CONFIG_PROC_FS
proc_tty_register_driver(driver);
-#endif
return error;
}
@@ -2010,9 +2010,7 @@ int tty_unregister_driver(struct tty_driver *driver)
if (driver->next)
driver->next->prev = driver->prev;
-#ifdef CONFIG_PROC_FS
proc_tty_unregister_driver(driver);
-#endif
return 0;
}
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 6a1d1c649..2cad9dba6 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -52,7 +52,6 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout)
if (!tty->driver.chars_in_buffer)
return;
add_wait_queue(&tty->write_wait, &wait);
- current->counter = 0; /* make us low-priority */
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
do {
@@ -210,11 +209,12 @@ static int get_sgflags(struct tty_struct * tty)
{
int flags = 0;
- if (!(tty->termios->c_lflag & ICANON))
+ if (!(tty->termios->c_lflag & ICANON)) {
if (tty->termios->c_lflag & ISIG)
flags |= 0x02; /* cbreak */
else
flags |= 0x20; /* raw */
+ }
if (tty->termios->c_lflag & ECHO)
flags |= 0x08; /* echo */
if (tty->termios->c_oflag & OPOST)
diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c
index 7f7471e19..1a96bec11 100644
--- a/drivers/char/tuner.c
+++ b/drivers/char/tuner.c
@@ -6,19 +6,31 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/malloc.h>
+#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/videodev.h>
#include "tuner.h"
-static int debug = 0; /* insmod parameter */
-static int type = 0; /* tuner type */
+static int debug = 0; /* insmod parameter */
+static int type = -1; /* tuner type */
#define dprintk if (debug) printk
+#if LINUX_VERSION_CODE > 0x020100
MODULE_PARM(debug,"i");
MODULE_PARM(type,"i");
+#endif
+
+#if LINUX_VERSION_CODE < 0x02017f
+void schedule_timeout(int j)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + j;
+ schedule();
+}
+#endif
struct tuner
{
@@ -69,9 +81,10 @@ static struct tunertype tuners[] = {
{"Temic NTSC", TEMIC, NTSC,
16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732},
{"TEMIC PAL_I", TEMIC, PAL_I,
- 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
+ // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
+ 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623},
{"Temic 4036 FY5 NTSC", TEMIC, NTSC,
- 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+ 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
};
/* ---------------------------------------------------------------------- */
@@ -98,11 +111,17 @@ static int tuner_afcstatus (struct tuner *t)
static void set_tv_freq(struct tuner *t, int freq)
{
- unsigned long flags;
u8 config;
u16 div;
- struct tunertype *tun=&tuners[t->type];
+ struct tunertype *tun;
+ LOCK_FLAGS;
+ if (t->type == -1) {
+ printk("tuner: tuner type not set\n");
+ return;
+ }
+
+ tun=&tuners[t->type];
if (freq < tun->thresh1)
config = tun->VHF_L;
else if (freq < tun->thresh2)
@@ -125,11 +144,17 @@ static void set_tv_freq(struct tuner *t, int freq)
static void set_radio_freq(struct tuner *t, int freq)
{
- unsigned long flags;
u8 config;
u16 div;
- struct tunertype *tun=&tuners[type];
+ struct tunertype *tun;
+ LOCK_FLAGS;
+
+ if (t->type == -1) {
+ printk("tuner: tuner type not set\n");
+ return;
+ }
+ tun=&tuners[t->type];
config = 0xa5;
div=freq + (int)(16*10.7);
div&=0x7fff;
@@ -143,7 +168,7 @@ static void set_radio_freq(struct tuner *t, int freq)
}
if (debug) {
UNLOCK_I2C_BUS(t->bus);
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_INTERRUPTIBLE;
schedule_timeout(HZ/10);
LOCK_I2C_BUS(t->bus);
@@ -181,7 +206,8 @@ static int tuner_attach(struct i2c_device *device)
t->bus = device->bus;
t->addr = device->addr;
t->type = type;
- dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
+ dprintk("tuner: type is %d (%s)\n",t->type,
+ (t->type == -1 ) ? "autodetect" : tuners[t->type].name);
MOD_INC_USE_COUNT;
return 0;
@@ -204,6 +230,8 @@ static int tuner_command(struct i2c_device *device,
switch (cmd)
{
case TUNER_SET_TYPE:
+ if (t->type != -1)
+ return 0;
t->type = *iarg;
dprintk("tuner: type set to %d (%s)\n",
t->type,tuners[t->type].name);
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index def6e7039..dd9364ecf 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -15,6 +15,7 @@
*/
#include <linux/config.h>
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -24,12 +25,12 @@
#include <linux/errno.h>
#include <linux/videodev.h>
+#if LINUX_VERSION_CODE >= 0x020100
#include <asm/uaccess.h>
+#endif
#include <asm/system.h>
-#ifdef CONFIG_KMOD
#include <linux/kmod.h>
-#endif
#define VIDEO_NUM_DEVICES 256
@@ -68,6 +69,9 @@ extern int fmi_init(struct video_init *);
#ifdef CONFIG_RADIO_MIROPCM20
extern int pcm20_init(struct video_init *);
#endif
+#ifdef CONFIG_RADIO_GEMTEK
+extern int gemtek_init(struct video_init *);
+#endif
#ifdef CONFIG_VIDEO_PMS
extern int init_pms_cards(struct video_init *);
#endif
@@ -100,14 +104,17 @@ static struct video_init video_init_list[]={
#endif
#ifdef CONFIG_RADIO_SF16FMI
{"SF16FMI", fmi_init},
-#endif
+#endif
#ifdef CONFIG_RADIO_MIROPCM20
{"PCM20", pcm20_init},
-#endif
+#endif
+#ifdef CONFIG_RADIO_GEMTEK
+ {"GemTek", gemtek_init},
+#endif
{"end", NULL}
};
-
+#if LINUX_VERSION_CODE >= 0x020100
/*
* Read will do some smarts later on. Buffer pin etc.
*/
@@ -123,6 +130,7 @@ static ssize_t video_read(struct file *file,
}
+
/*
* Write for now does nothing. No reason it shouldnt do overlay setting
* for some boards I guess..
@@ -138,7 +146,6 @@ static ssize_t video_write(struct file *file, const char *buf,
return 0;
}
-
/*
* Poll to see if we're readable, can probably be used for timing on incoming
* frames, etc..
@@ -153,6 +160,32 @@ static unsigned int video_poll(struct file *file, poll_table * wait)
return 0;
}
+
+#else
+static int video_read(struct inode *ino,struct file *file,
+ char *buf, int count)
+{
+ int err;
+ struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
+ if (vfl->read)
+ return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return -EINVAL;
+}
+
+static int video_write(struct inode *ino,struct file *file, const char *buf,
+ int count)
+{
+ int err;
+ struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
+ if (vfl->write)
+ return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return 0;
+}
+
+#endif
+
/*
* Open a video device.
*/
@@ -168,14 +201,12 @@ static int video_open(struct inode *inode, struct file *file)
vfl=video_device[minor];
if(vfl==NULL) {
-#ifdef CONFIG_KMOD
char modname[20];
sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor);
request_module(modname);
vfl=video_device[minor];
if (vfl==NULL)
-#endif
return -ENODEV;
}
if(vfl->busy)
@@ -212,11 +243,19 @@ static int video_release(struct inode *inode, struct file *file)
* image ?
*/
+#if LINUX_VERSION_CODE >= 0x020100
static long long video_lseek(struct file * file,
long long offset, int origin)
{
return -ESPIPE;
}
+#else
+static long long video_lseek(struct inode *inode, struct file * file,
+ long long offset, int origin)
+{
+ return -ESPIPE;
+}
+#endif
static int video_ioctl(struct inode *inode, struct file *file,
@@ -240,9 +279,16 @@ static int video_ioctl(struct inode *inode, struct file *file,
*/
+#if LINUX_VERSION_CODE >= 0x020100
int video_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+#else
+static int video_mmap(struct inode * ino, struct file * file,
+ struct vm_area_struct * vma)
+{
+ struct video_device *vfl=video_device[MINOR(ino->i_rdev)];
+#endif
if(vfl->mmap)
return vfl->mmap(vfl, (char *)vma->vm_start,
(unsigned long)(vma->vm_end-vma->vm_start));
@@ -326,11 +372,17 @@ static struct file_operations video_fops=
video_read,
video_write,
NULL, /* readdir */
+#if LINUX_VERSION_CODE >= 0x020100
video_poll, /* poll */
+#else
+ NULL,
+#endif
video_ioctl,
video_mmap,
video_open,
+#if LINUX_VERSION_CODE >= 0x020100
NULL, /* flush */
+#endif
video_release
};
@@ -374,5 +426,7 @@ void cleanup_module(void)
#endif
+#if LINUX_VERSION_CODE >= 0x020100
EXPORT_SYMBOL(video_register_device);
EXPORT_SYMBOL(video_unregister_device);
+#endif
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index d365e30a2..d227ba9e0 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -22,7 +22,6 @@
#include <linux/malloc.h>
#include <linux/major.h>
#include <linux/fs.h>
-#include <linux/config.h>
#include <asm/io.h>
#include <asm/uaccess.h>