summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Config.in8
-rw-r--r--drivers/char/Makefile25
-rw-r--r--drivers/char/apm_bios.c14
-rw-r--r--drivers/char/bt848.h10
-rw-r--r--drivers/char/bttv.c1556
-rw-r--r--drivers/char/bttv.h212
-rw-r--r--drivers/char/bw-qcam.c2
-rw-r--r--drivers/char/c-qcam.c2
-rw-r--r--drivers/char/console.c153
-rw-r--r--drivers/char/cyclades.c536
-rw-r--r--drivers/char/epca.c38
-rw-r--r--drivers/char/hfmodem/gentbl.c2
-rw-r--r--drivers/char/i2c.c430
-rw-r--r--drivers/char/i2c.h166
-rw-r--r--drivers/char/lp.c180
-rw-r--r--drivers/char/mem.c5
-rw-r--r--drivers/char/msp3400.c923
-rw-r--r--drivers/char/msp3400.h18
-rw-r--r--drivers/char/pc_keyb.c106
-rw-r--r--drivers/char/pc_keyb.h2
-rw-r--r--drivers/char/pms.c14
-rw-r--r--drivers/char/pty.c7
-rw-r--r--drivers/char/rocket.c32
-rw-r--r--drivers/char/serial.c662
-rw-r--r--drivers/char/stallion.c57
-rw-r--r--drivers/char/tga.c23
-rw-r--r--drivers/char/tty_io.c26
-rw-r--r--drivers/char/tuner.c269
-rw-r--r--drivers/char/tuner.h19
-rw-r--r--drivers/char/videodev.c51
-rw-r--r--drivers/char/vt.c14
31 files changed, 4166 insertions, 1396 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index e17a220e6..fad48a260 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -16,6 +16,7 @@ bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
+ bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ
bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT
bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6
fi
@@ -121,6 +122,13 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV
fi
dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+ #dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_VIDEO_SAA5249" != "n" ]; then
+ define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_SAA5249
+ fi
+ if [ "$CONFIG_VIDEO_BT848" != "n" ]; then
+ define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_BT848
+ fi
fi
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'PC joystick support' CONFIG_JOYSTICK
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 0ef46c200..b598d7769 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -20,7 +20,8 @@ FONTMAPFILE = cp437.uni
L_TARGET := char.a
M_OBJS :=
-L_OBJS := tty_io.o n_tty.o tty_ioctl.o pty.o mem.o random.o
+L_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o
+LX_OBJS := pty.o
ifdef CONFIG_VT
L_OBJS += console.o vt.o vc_screen.o consolemap.o consolemap_deftbl.o
@@ -307,11 +308,27 @@ else
endif
endif
+ifeq ($(CONFIG_BUS_I2C),y)
+ LX_OBJS += i2c.o
+else
+ ifeq ($(CONFIG_BUS_I2C),m)
+ MX_OBJS += i2c.o
+ endif
+endif
+
ifeq ($(CONFIG_VIDEO_BT848),y)
-L_OBJS += bttv.o
+L_OBJS += bttv.o msp3400.o tuner.o
else
ifeq ($(CONFIG_VIDEO_BT848),m)
- M_OBJS += bttv.o
+ M_OBJS += bttv.o msp3400.o tuner.o
+ endif
+endif
+
+ifeq ($(CONFIG_VIDEO_SAA5249),y)
+L_OBJS += saa5249.o
+else
+ ifeq ($(CONFIG_VIDEO_SAA5249),m)
+ M_OBJS += saa5249.o
endif
endif
@@ -335,7 +352,7 @@ ifeq ($(CONFIG_VIDEO_PMS),y)
L_OBJS += pms.o
else
ifeq ($(CONFIG_VIDEO_PMS),m)
- M_OBJS += pms.o
+ M_OBJS += pms.o
endif
endif
diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c
index 94f13f8fd..f4fcf4f7b 100644
--- a/drivers/char/apm_bios.c
+++ b/drivers/char/apm_bios.c
@@ -231,10 +231,10 @@ extern unsigned long get_cmos_time(void);
"pushl %%fs\n\t" \
"pushl %%gs\n\t" \
"xorl %%edx, %%edx\n\t" \
- "mov %%dx, %%ds\n\t" \
- "mov %%dx, %%es\n\t" \
- "mov %%dx, %%fs\n\t" \
- "mov %%dx, %%gs\n\t"
+ "movl %%dx, %%ds\n\t" \
+ "movl %%dx, %%es\n\t" \
+ "movl %%dx, %%fs\n\t" \
+ "movl %%dx, %%gs\n\t"
# define APM_DO_RESTORE_SEGS \
"popl %%gs\n\t" \
"popl %%fs\n\t" \
@@ -1159,8 +1159,10 @@ __initfunc(void apm_bios_init(void))
static struct proc_dir_entry *ent;
#ifdef __SMP__
- printk(KERN_NOTICE "APM disabled: APM is not SMP safe.\n");
- return;
+ if (smp_num_cpus > 1) {
+ printk(KERN_NOTICE "APM disabled: APM is not SMP safe.\n");
+ return;
+ }
#endif
if (apm_bios_info.version == 0) {
printk(KERN_INFO "APM BIOS not found.\n");
diff --git a/drivers/char/bt848.h b/drivers/char/bt848.h
index 2171a1574..5a76ea02a 100644
--- a/drivers/char/bt848.h
+++ b/drivers/char/bt848.h
@@ -1,7 +1,7 @@
/*
bt848.h - Bt848 register offsets
- Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
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
@@ -22,13 +22,15 @@
#define _BT848_H_
#ifndef PCI_VENDOR_ID_BROOKTREE
-#define PCI_VENDOR_ID_BROOKTREE 0x109e
+#define PCI_VENDOR_ID_BROOKTREE 0x109e
#endif
#ifndef PCI_DEVICE_ID_BT848
-#define PCI_DEVICE_ID_BT848 0x350
+#define PCI_DEVICE_ID_BT848 0x350
+#endif
+#ifndef PCI_DEVICE_ID_BT849
+#define PCI_DEVICE_ID_BT849 0x351
#endif
-#define RISCMEM_LEN 131040
/* Brooktree 848 registers */
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index db2a49b17..ec66585cf 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -1,7 +1,8 @@
/*
bttv - Bt848 frame grabber driver
- Copyright (C) 1996,97 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de)
+ & Marcus Metzler (mocm@thp.uni-koeln.de)
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
@@ -20,6 +21,15 @@
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:
+
+ * think of some good ioctls for Video4Linux to handle
+ YUV, planar YUV, ... grabs and sell them to AC :-)
+ * move norm from tuner to channel struct!?
+ composite source from a satellite tuner can deliver different norms
+ depending on tuned channel
+ * mmap VBI data?
*/
#include <linux/module.h>
@@ -39,21 +49,31 @@
#include <linux/sched.h>
#include <asm/segment.h>
#include <linux/types.h>
-#include <linux/videodev.h>
+#include <linux/wrapper.h>
+#include <linux/videodev.h>
#include <linux/version.h>
#include <asm/uaccess.h>
+#include "i2c.h"
#include "bttv.h"
#include "tuner.h"
#define DEBUG(x) /* Debug driver */
-#define IDEBUG(x) /* Debug interrupt handler */
+#define IDEBUG(x) /* Debug interrupt handler */
+
+static unsigned int remap=0; /* remap Bt848 */
+static unsigned int vidmem=0; /* manually set video mem address */
+static int triton1=0;
+static int radio=0;
-static unsigned int remap=0;
-static unsigned int vidmem=0;
-static unsigned int tuner=0; /* Default tuner */
-MODULE_PARM(tuner,"i");
+static unsigned int card=0;
+
+MODULE_PARM(remap,"i");
+MODULE_PARM(vidmem,"i");
+MODULE_PARM(triton1,"i");
+MODULE_PARM(radio,"i");
+MODULE_PARM(card,"i");
static int find_vga(void);
static void bt848_set_risc_jmps(struct bttv *btv);
@@ -61,17 +81,21 @@ static void bt848_set_risc_jmps(struct bttv *btv);
/* Anybody who uses more than four? */
#define BTTV_MAX 4
-static int bttv_num;
+static int bttv_num; /* number of Bt848s in use */
static struct bttv bttvs[BTTV_MAX];
#define I2C_TIMING (0x7<<4)
#define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA)
+#define I2C_DELAY 10
+#define I2C_SET(CTRL,DATA) \
+ { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }
+#define I2C_GET() (btread(BT848_I2C)&1)
+
#define AUDIO_MUTE_DELAY 10000
#define FREQ_CHANGE_DELAY 20000
#define EEPROM_WRITE_DELAY 20000
-
/*******************************/
/* Memory management functions */
/*******************************/
@@ -79,56 +103,137 @@ static struct bttv bttvs[BTTV_MAX];
/* convert virtual user memory address to physical address */
/* (virt_to_phys only works for kmalloced kernel memory) */
-static inline ulong uvirt_to_phys(ulong adr)
+static inline unsigned long uvirt_to_phys(unsigned long adr)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t *ptep, pte;
-/* printk("adr: 0x%08x\n",adr);*/
pgd = pgd_offset(current->mm, adr);
-/* printk("pgd: 0x%08x\n",pgd);*/
if (pgd_none(*pgd))
return 0;
pmd = pmd_offset(pgd, adr);
-/* printk("pmd: 0x%08x\n",pmd); */
if (pmd_none(*pmd))
return 0;
- ptep = pte_offset(pmd, adr&(~PGDIR_MASK));
+ ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);
pte = *ptep;
if(pte_present(pte))
- return (pte_page(pte)|(adr&(PAGE_SIZE-1)));
+ return
+ virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));
return 0;
}
+static inline unsigned long uvirt_to_bus(unsigned long adr)
+{
+ /* printk("adr: 0x%8x, ",adr);
+ printk("phys: 0x%8x, ",(uvirt_to_phys(adr)));
+ printk("bus: 0x%8x\n",virt_to_bus(phys_to_virt(uvirt_to_phys(adr))));
+ */
+ return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));
+}
+
/* convert virtual kernel memory address to physical address */
/* (virt_to_phys only works for kmalloced kernel memory) */
-static inline ulong kvirt_to_phys(ulong adr)
+static inline unsigned long kvirt_to_phys(unsigned long adr)
{
return uvirt_to_phys(VMALLOC_VMADDR(adr));
}
-static inline ulong kvirt_to_bus(ulong adr)
+static inline unsigned long kvirt_to_bus(unsigned long adr)
{
- return virt_to_bus(phys_to_virt(kvirt_to_phys(adr)));
+ return uvirt_to_bus(VMALLOC_VMADDR(adr));
}
+static void * rvmalloc(unsigned long size)
+{
+ void * mem;
+ unsigned long adr, page;
+
+ mem=vmalloc(size);
+ if (mem)
+ {
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_phys(adr);
+ mem_map_reserve(MAP_NR(phys_to_virt(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ }
+ return mem;
+}
-/*****************/
-/* I2C functions */
-/*****************/
+static void rvfree(void * mem, unsigned long size)
+{
+ unsigned long adr, page;
+
+ if (mem)
+ {
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ page = kvirt_to_phys(adr);
+ mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+ adr+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ vfree(mem);
+ }
+}
-static int I2CRead(struct bttv *btv, int addr)
+/*
+ * Create the giant waste of buffer space we need for now
+ * until we get DMA to user space sorted out (probably 2.3.x)
+ *
+ * We only create this as and when someone uses mmap
+ */
+
+static int fbuffer_alloc(struct bttv *btv)
+{
+ if(!btv->fbuffer)
+ btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000);
+ else
+ printk(KERN_ERR "bttv: Double alloc of fbuffer!\n");
+ if(!btv->fbuffer)
+ return -ENOBUFS;
+ return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* I2C functions */
+
+/* software I2C functions */
+
+static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data)
+{
+ struct bttv *btv = (struct bttv*)bus->data;
+ btwrite((ctrl<<1)|data, BT848_I2C);
+ udelay(I2C_DELAY);
+}
+
+static int i2c_getdataline(struct i2c_bus *bus)
+{
+ struct bttv *btv = (struct bttv*)bus->data;
+ return btread(BT848_I2C)&1;
+}
+
+/* hardware I2C functions */
+
+/* read I2C */
+static int I2CRead(struct i2c_bus *bus, unsigned char addr)
{
u32 i;
u32 stat;
+ struct bttv *btv = (struct bttv*)bus->data;
/* clear status bit ; BT848_INT_RACK is ro */
btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C);
-
+
/*
* Timeout for I2CRead is 1 second (this should be enough, really!)
*/
@@ -136,11 +241,12 @@ static int I2CRead(struct bttv *btv, int addr)
{
stat=btread(BT848_INT_STAT);
if (stat & BT848_INT_I2CDONE)
- break;
- udelay(1000); /* 1ms, as I2C is 1kHz (?) */
+ break;
+ udelay(1000);
}
- if (!i) {
+ if (!i)
+ {
printk(KERN_DEBUG "bttv: I2CRead timeout\n");
return -1;
}
@@ -153,12 +259,13 @@ static int I2CRead(struct bttv *btv, int addr)
/* set both to write both bytes, reset it to write only b1 */
-static int I2CWrite(struct bttv *btv, unchar addr, unchar b1,
- unchar b2, int both)
+static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
+ unsigned char b2, int both)
{
u32 i;
u32 data;
u32 stat;
+ struct bttv *btv = (struct bttv*)bus->data;
/* clear status bit; BT848_INT_RACK is ro */
btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);
@@ -172,15 +279,16 @@ static int I2CWrite(struct bttv *btv, unchar addr, unchar b1,
btwrite(data, BT848_I2C);
- for (i=1000; i; i--)
+ for (i=0x1000; i; i--)
{
stat=btread(BT848_INT_STAT);
if (stat & BT848_INT_I2CDONE)
break;
- udelay(1000);
+ udelay(1000);
}
- if (!i) {
+ if (!i)
+ {
printk(KERN_DEBUG "bttv: I2CWrite timeout\n");
return -1;
}
@@ -190,19 +298,20 @@ static int I2CWrite(struct bttv *btv, unchar addr, unchar b1,
return 0;
}
-static void readee(struct bttv *btv, unchar *eedata)
+/* read EEPROM */
+static void readee(struct i2c_bus *bus, unsigned char *eedata)
{
int i, k;
-
- if (I2CWrite(btv, 0xa0, 0, -1, 0)<0)
+
+ if (I2CWrite(bus, 0xa0, 0, -1, 0)<0)
{
printk(KERN_WARNING "bttv: readee error\n");
return;
}
-
+
for (i=0; i<256; i++)
{
- k=I2CRead(btv, 0xa1);
+ k=I2CRead(bus, 0xa1);
if (k<0)
{
printk(KERN_WARNING "bttv: readee error\n");
@@ -212,13 +321,14 @@ static void readee(struct bttv *btv, unchar *eedata)
}
}
-static void writeee(struct bttv *btv, unchar *eedata)
+/* write EEPROM */
+static void writeee(struct i2c_bus *bus, unsigned char *eedata)
{
int i;
for (i=0; i<256; i++)
{
- if (I2CWrite(btv, 0xa0, i, eedata[i], 1)<0)
+ if (I2CWrite(bus, 0xa0, i, eedata[i], 1)<0)
{
printk(KERN_WARNING "bttv: writeee error (%d)\n", i);
break;
@@ -227,28 +337,91 @@ static void writeee(struct bttv *btv, unchar *eedata)
}
}
+void attach_inform(struct i2c_bus *bus, int id)
+{
+ struct bttv *btv = (struct bttv*)bus->data;
+ int tunertype;
+
+ switch (id)
+ {
+ case I2C_DRIVERID_MSP3400:
+ btv->have_msp3400 = 1;
+ break;
+ case I2C_DRIVERID_TUNER:
+ btv->have_tuner = 1;
+ if (btv->type == BTTV_MIRO)
+ {
+ tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+ i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
+ TUNER_SET_TYPE,&tunertype);
+ }
+ break;
+ }
+}
+
+void detach_inform(struct i2c_bus *bus, int id)
+{
+ struct bttv *btv = (struct bttv*)bus->data;
+
+ switch (id)
+ {
+ case I2C_DRIVERID_MSP3400:
+ btv->have_msp3400 = 0;
+ break;
+ case I2C_DRIVERID_TUNER:
+ btv->have_tuner = 0;
+ break;
+ }
+}
+
+static struct i2c_bus bttv_i2c_bus_template =
+{
+ "bt848",
+ I2C_BUSID_BT848,
+ NULL,
+
+ SPIN_LOCK_UNLOCKED,
+
+ attach_inform,
+ detach_inform,
+
+ i2c_setlines,
+ i2c_getdataline,
+ I2CRead,
+ I2CWrite,
+};
+
+/* ----------------------------------------------------------------------- */
+
/*
- * Tuner, internal, external and mute
+ * Tuner, Radio, internal, external and mute
*/
-static unchar audiomuxs[][4] =
-{
- { 0x00, 0x00, 0x00, 0x00}, /* unknown */
- { 0x02, 0x00, 0x00, 0x0a}, /* MIRO */
- { 0x00, 0x02, 0x03, 0x04}, /* Hauppauge */
- { 0x04, 0x02, 0x03, 0x01}, /* STB */
- { 0x01, 0x02, 0x03, 0x04}, /* Intel??? */
- { 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000??? */
+static unsigned char audiomuxs[][5] =
+{
+ { 0x00, 0x00, 0x00, 0x00, 0x00}, /* unknown */
+ { 0x02, 0x00, 0x00, 0x00, 0x0a}, /* MIRO */
+ { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Hauppauge */
+ { 0x04, 0x00, 0x02, 0x03, 0x01}, /* STB */
+ { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Intel??? */
+ { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000 */
+ { 0x0c, 0x00, 0x0b, 0x0b, 0x00}, /* AVerMedia TVPhone */
};
static void audio(struct bttv *btv, int mode)
{
+ /* enable least significant GPIO output nibble */
btwrite(0x0f, BT848_GPIO_OUT_EN);
+
+ /* select direct input */
btwrite(0x00, BT848_GPIO_REG_INP);
switch (mode)
{
- case AUDIO_UNMUTE:
+ case AUDIO_MUTE:
+ btv->audio|=AUDIO_MUTE;
+ break;
+ case AUDIO_UNMUTE:
btv->audio&=~AUDIO_MUTE;
mode=btv->audio;
break;
@@ -263,8 +436,12 @@ static void audio(struct bttv *btv, int mode)
btv->audio|=mode;
break;
}
- if ((btv->audio&AUDIO_MUTE) || !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
- mode=AUDIO_OFF;
+ /* if audio mute or not in H-lock, turn audio off */
+ if ((btv->audio&AUDIO_MUTE) ||
+ (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)))
+ mode=AUDIO_OFF;
+ if ((mode == 0) && (btv->radio))
+ mode = 1;
btaor(audiomuxs[btv->type][mode] , ~0x0f, BT848_GPIO_DATA);
}
@@ -319,11 +496,19 @@ static void bt848_muxsel(struct bttv *btv, uint input)
#define VBIBUF_SIZE 65536
+/* Maximum sample number per VBI line is 2044, can NTSC deliver this?
+ Note that we write 2048-aligned to keep alignment to memory pages
+*/
+#define VBI_SPL 2044
+
+/* RISC command to write one VBI data line */
+#define VBI_RISC BT848_RISC_WRITE|VBI_SPL|BT848_RISC_EOL|BT848_RISC_SOL
+
static void make_vbitab(struct bttv *btv)
{
int i;
- dword *po=(dword *) btv->vbi_odd;
- dword *pe=(dword *) btv->vbi_even;
+ unsigned int *po=(unsigned int *) btv->vbi_odd;
+ unsigned int *pe=(unsigned int *) btv->vbi_even;
DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd));
DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even));
@@ -333,8 +518,8 @@ static void make_vbitab(struct bttv *btv)
*(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0;
for (i=0; i<16; i++)
{
- *(po++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL|(13<<20);
- *(po++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048);
+ *(po++)=VBI_RISC;
+ *(po++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
}
*(po++)=BT848_RISC_JUMP;
*(po++)=virt_to_bus(btv->risc_jmp+4);
@@ -342,11 +527,129 @@ static void make_vbitab(struct bttv *btv)
*(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0;
for (i=16; i<32; i++)
{
- *(pe++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL;
- *(pe++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048);
+ *(pe++)=VBI_RISC;
+ *(pe++)=kvirt_to_bus((unsigned long)btv->vbibuf+i*2048);
}
*(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16);
*(pe++)=virt_to_bus(btv->risc_jmp+10);
+ DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po));
+ DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe));
+}
+
+int fmtbppx2[16] = {
+ 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 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 fmt)
+{
+ unsigned long line;
+ unsigned long bpl; /* bytes per line */
+ unsigned long bl;
+ unsigned long todo;
+ unsigned int **rp;
+ int inter;
+ unsigned long vadr=(unsigned long) vbuf;
+
+ inter = (height>btv->win.cropheight/2) ? 1 : 0;
+ bpl=width*fmtbppx2[fmt&0xf]/2;
+
+ *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
+ *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+
+ for (line=0; line < (height<<(1^inter)); line++)
+ {
+ if (inter)
+ rp= (line&1) ? &re : &ro;
+ else
+ rp= (line>height) ? &re : &ro;
+
+ bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr);
+ if (bpl<=bl)
+ {
+ *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|
+ BT848_RISC_EOL|bpl;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=bpl;
+ }
+ else
+ {
+ todo=bpl;
+ *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_SOL|bl;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=bl;
+ todo-=bl;
+ while (todo>PAGE_SIZE)
+ {
+ *((*rp)++)=BT848_RISC_WRITE|PAGE_SIZE;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=PAGE_SIZE;
+ todo-=PAGE_SIZE;
+ }
+ *((*rp)++)=BT848_RISC_WRITE|BT848_RISC_EOL|todo;
+ *((*rp)++)=kvirt_to_bus(vadr);
+ vadr+=todo;
+ }
+ }
+
+ *(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;
+}
+
+/* does this really make a difference ???? */
+#define BURST_MAX 4096
+
+static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr, unsigned int command,
+ int *x, uint dx, uint bpp, uint width)
+{
+ unsigned int flags, len;
+
+ if (!dx)
+ return;
+ len=dx*bpp;
+
+#ifdef LIMIT_DMA
+ if (command==BT848_RISC_WRITEC)
+ {
+ unsigned int dx2=BURST_MAX/bpp;
+ while (len>BURST_MAX)
+ {
+ write_risc_segment(rp, line_adr, command,
+ &x,dx2, bpp, width);
+ dx-=dx2;
+ len=dx*bpp;
+ }
+ }
+#endif
+
+ /* mask upper 8 bits for 24+8 bit overlay modes */
+ flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0);
+
+ if (*x==0)
+ {
+ if (command==BT848_RISC_SKIP)
+ {
+ if (dx<width)
+ {
+ flags|=BT848_RISC_BYTE_ALL;
+ command=BT848_RISC_WRITE;
+ }
+ }
+ else
+ if (command==BT848_RISC_WRITEC)
+ command=BT848_RISC_WRITE;
+ flags|=BT848_RISC_SOL;
+ }
+ if (*x+dx==width)
+ flags|=BT848_RISC_EOL;
+ *((*rp)++)=command|flags|len;
+ if (command==BT848_RISC_WRITE)
+ *((*rp)++)=line_adr+*x*bpp;
+ *x+=dx;
}
/*
@@ -358,237 +661,264 @@ static void make_vbitab(struct bttv *btv)
* www.brooktree.com - nicely done those folks.
*/
-static void bt848_set_size(struct bttv *btv)
+struct tvnorm
+{
+ u16 cropwidth, cropheight;
+ u16 totalwidth;
+ u8 adelay, bdelay, iform;
+ u32 scaledtwidth;
+ u16 hdelayx1, hactivex1;
+ u16 vdelay;
+};
+
+static struct tvnorm tvnorms[] = {
+ /* PAL-BDGHI */
+ { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+ /* NTSC */
+ { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
+ /* SECAM */
+ { 768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+ /* PAL-M */
+ { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
+ 780, 186, 922, 0x16},
+ /* PAL-N */
+ { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
+ 944, 186, 922, 0x20},
+};
+#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
+ the even ones as RGB into videomem and the others as YUV in main memory for
+ compressing and sending to the video conferencing partner.
+
+*/
+static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
+ u16 hscale, u16 vscale,
+ u16 hactive, u16 vactive,
+ u16 hdelay, u16 vdelay,
+ u8 crop)
+{
+ int off = odd ? 0x80 : 0x00;
+
+ btwrite(vtc, BT848_E_VTC+off);
+ btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
+ btwrite(hscale&0xff, BT848_E_HSCALE_LO+off);
+ btaor((vscale>>8), 0xc0, BT848_E_VSCALE_HI+off);
+ btwrite(vscale&0xff, BT848_E_VSCALE_LO+off);
+ btwrite(hactive&0xff, BT848_E_HACTIVE_LO+off);
+ btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off);
+ btwrite(vactive&0xff, BT848_E_VACTIVE_LO+off);
+ btwrite(vdelay&0xff, BT848_E_VDELAY_LO+off);
+ btwrite(crop, BT848_E_CROP+off);
+}
+
+
+static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt)
{
- u16 vscale, hscale;
+ u16 vscale, hscale;
u32 xsf, sr;
u16 hdelay, vdelay;
u16 hactive, vactive;
u16 inter;
- u8 crop;
+ u8 crop, vtc;
+ struct tvnorm *tvn;
+
+ if (!width || !height)
+ return;
- /*
- * No window , no try...
- */
-
- if (!btv->win.width)
- return;
- if (!btv->win.height)
- return;
-
+ tvn=&tvnorms[btv->win.norm];
+
+ if (btv->win.cropwidth>tvn->cropwidth)
+ btv->win.cropwidth=tvn->cropwidth;
+ if (btv->win.cropheight>tvn->cropheight)
+ btv->win.cropheight=tvn->cropheight;
+
+ if (width>btv->win.cropwidth)
+ width=btv->win.cropwidth;
+ if (height>btv->win.cropheight)
+ height=btv->win.cropheight;
+
+ btwrite(tvn->adelay, BT848_ADELAY);
+ btwrite(tvn->bdelay, BT848_BDELAY);
+ btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM);
+
+ btwrite(fmt, BT848_COLOR_FMT);
+ hactive=width;
+
+ vtc=0;
+ /* Some people say interpolation looks bad ... */
+ /* vtc = (hactive < 193) ? 2 : ((hactive < 385) ? 1 : 0); */
+
+ btv->win.interlace = (height>btv->win.cropheight/2) ? 1 : 0;
inter=(btv->win.interlace&1)^1;
+ xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth;
+ hscale = ((tvn->totalwidth*4096UL)/xsf-4096);
+ vdelay=btv->win.cropy+tvn->vdelay;
- switch (btv->win.bpp)
- {
- /*
- * RGB8 seems to be a 9x5x5 GRB color cube starting at color 16
- * Why the h... can't they even mention this in the datasheet???
- */
- case 1:
- btwrite(BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT);
- btand(~0x10, BT848_CAP_CTL); /* Dithering looks much better in this mode */
- break;
- case 2:
- btwrite(BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT);
- btor(0x10, BT848_CAP_CTL);
- break;
- case 3:
- btwrite(BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT);
- btor(0x10, BT848_CAP_CTL);
- break;
- case 4:
- btwrite(BT848_COLOR_FMT_RGB32, BT848_COLOR_FMT);
- btor(0x10, BT848_CAP_CTL);
- break;
- }
-
- /*
- * Set things up according to the final picture width.
- */
-
- hactive=btv->win.width;
- if (hactive < 193)
- {
- btwrite (2, BT848_E_VTC);
- btwrite (2, BT848_O_VTC);
- }
- else if (hactive < 385)
- {
- btwrite (1, BT848_E_VTC);
- btwrite (1, BT848_O_VTC);
- }
- else
- {
- btwrite (0, BT848_E_VTC);
- btwrite (0, BT848_O_VTC);
- }
+ hdelay=(tvn->hdelayx1*tvn->scaledtwidth)/tvn->totalwidth;
+ hdelay=((hdelay+btv->win.cropx)*hactive)/btv->win.cropwidth;
+ hdelay&=0x3fe;
- /*
- * Ok are we doing Never The Same Color or PAL ?
- */
-
- if (btv->win.norm==1)
- {
- btv->win.cropwidth=640;
- btv->win.cropheight=480;
- btwrite(0x68, BT848_ADELAY);
- btwrite(0x5d, BT848_BDELAY);
- btaor(BT848_IFORM_NTSC, ~7, BT848_IFORM);
- btaor(BT848_IFORM_XT0, ~0x18, BT848_IFORM);
- xsf = (btv->win.width*365625UL)/300000UL;
- hscale = ((910UL*4096UL)/xsf-4096);
- vdelay=btv->win.cropy+0x16;
- hdelay=((hactive*135)/754+btv->win.cropx)&0x3fe;
- }
- else
- {
- btv->win.cropwidth=768;
- btv->win.cropheight=576;
- if (btv->win.norm==0)
- {
- btwrite(0x7f, BT848_ADELAY);
- btwrite(0x72, BT848_BDELAY);
- btaor(BT848_IFORM_PAL_BDGHI, ~BT848_IFORM_NORM, BT848_IFORM);
- }
- else
- {
- btwrite(0x7f, BT848_ADELAY);
- btwrite(0x00, BT848_BDELAY);
- btaor(BT848_IFORM_SECAM, ~BT848_IFORM_NORM, BT848_IFORM);
- }
- btaor(BT848_IFORM_XT1, ~0x18, BT848_IFORM);
- xsf = (btv->win.width*36875UL)/30000UL;
- hscale = ((1135UL*4096UL)/xsf-4096);
- vdelay=btv->win.cropy+0x20;
- hdelay=((hactive*186)/922+btv->win.cropx)&0x3fe;
- }
- sr=((btv->win.cropheight>>inter)*512)/btv->win.height-512;
+ sr=((btv->win.cropheight>>inter)*512)/height-512;
vscale=(0x10000UL-sr)&0x1fff;
vactive=btv->win.cropheight;
+ crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
+ ((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
+ vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0;
+
+ bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive,
+ hdelay, vdelay, crop);
+ bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive,
+ hdelay, vdelay, crop);
+
+}
-#if 0
- printk("bttv: hscale=0x%04x, ",hscale);
- printk("bttv: vscale=0x%04x\n",vscale);
- printk("bttv: hdelay =0x%04x\n",hdelay);
- printk("bttv: hactive=0x%04x\n",hactive);
- printk("bttv: vdelay =0x%04x\n",vdelay);
- printk("bttv: vactive=0x%04x\n",vactive);
-#endif
+int bpp2fmt[4] = {
+ BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16,
+ BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32
+};
- /*
- * Interlace is set elsewhere according to the final image
- * size we desire
- */
-
- if (btv->win.interlace)
- {
- btor(BT848_VSCALE_INT, BT848_E_VSCALE_HI);
- btor(BT848_VSCALE_INT, BT848_O_VSCALE_HI);
- }
- else
+static void bt848_set_winsize(struct bttv *btv)
+{
+ unsigned short format;
+ int bpp;
+
+ bpp=fmtbppx2[btv->win.color_fmt&0x0f]/2;
+ if (btv->win.bpp == 0)
{
- btand(~BT848_VSCALE_INT, BT848_E_VSCALE_HI);
- btand(~BT848_VSCALE_INT, BT848_O_VSCALE_HI);
+ btv->win.bpp=bpp;
+ format=btv->win.color_fmt;
}
-
- /*
- * Load her up
+ else if (btv->win.bpp!=bpp)
+ btv->win.color_fmt=format=bpp2fmt[(btv->win.bpp-1)&3];
+ else
+ format=btv->win.color_fmt;
+
+ /* RGB8 seems to be a 9x5x5 GRB color cube starting at
+ * color 16. Why the h... can't they even mention this in the
+ * datasheet??? [AC - because its a standard format so I guess
+ * it never occured them]
+ * Enable dithering in this mode
*/
-
- btwrite(hscale>>8, BT848_E_HSCALE_HI);
- btwrite(hscale>>8, BT848_O_HSCALE_HI);
- btwrite(hscale&0xff, BT848_E_HSCALE_LO);
- btwrite(hscale&0xff, BT848_O_HSCALE_LO);
-
- btwrite((vscale>>8)|(btread(BT848_E_VSCALE_HI)&0xe0), BT848_E_VSCALE_HI);
- btwrite((vscale>>8)|(btread(BT848_O_VSCALE_HI)&0xe0), BT848_O_VSCALE_HI);
- btwrite(vscale&0xff, BT848_E_VSCALE_LO);
- btwrite(vscale&0xff, BT848_O_VSCALE_LO);
-
- btwrite(hactive&0xff, BT848_E_HACTIVE_LO);
- btwrite(hactive&0xff, BT848_O_HACTIVE_LO);
- btwrite(hdelay&0xff, BT848_E_HDELAY_LO);
- btwrite(hdelay&0xff, BT848_O_HDELAY_LO);
-
- btwrite(vactive&0xff, BT848_E_VACTIVE_LO);
- btwrite(vactive&0xff, BT848_O_VACTIVE_LO);
- btwrite(vdelay&0xff, BT848_E_VDELAY_LO);
- btwrite(vdelay&0xff, BT848_O_VDELAY_LO);
+ if (format==BT848_COLOR_FMT_RGB8)
+ btand(~0x10, BT848_CAP_CTL);
+ else
+ btor(0x10, BT848_CAP_CTL);
- crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)|
- ((vactive>>4)&0x30)|((vdelay>>2)&0xc0);
- btwrite(crop, BT848_E_CROP);
- btwrite(crop, BT848_O_CROP);
+ bt848_set_geo(btv,btv->win.width, btv->win.height, format);
}
-
-/*
- * The floats in the tuner struct are computed at compile time
- * by gcc and cast back to integers. Thus we don't violate the
- * "no float in kernel" rule.
- */
-
-static struct tunertype tuners[] = {
- {"Temic PAL", TEMIC, PAL,
- 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 623},
- {"Philips PAL_I", Philips, PAL_I,
- 16*140.25,16*463.25,0x00,0x00,0x00,0x00,0x00, 623},
- {"Philips NTSC", Philips, NTSC,
- 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0, 732},
- {"Philips SECAM", Philips, SECAM,
- 16*168.25,16*447.25,0xA3,0x93,0x33,0x8e,0xc0, 623},
- {"NoTuner", NoTuner, NOTUNER,
- 0 ,0 ,0x00,0x00,0x00,0x00,0x00, 0},
- {"Philips PAL", Philips, PAL,
- 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0, 623},
- {"Temic NTSC", TEMIC, NTSC,
- 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2, 732},
- {"TEMIC PAL_I", TEMIC, PAL_I,
- 0 ,0 ,0x00,0x00,0x00,0x00,0xc2, 623},
-};
-
/*
* Set TSA5522 synthesizer frequency in 1/16 Mhz steps
*/
-static void set_freq(struct bttv *btv, ushort freq)
+static void set_freq(struct bttv *btv, unsigned short freq)
{
- u8 config;
- u16 div;
- struct tunertype *tun=&tuners[btv->tuner];
+ int fixme = freq; /* XXX */
int oldAudio = btv->audio;
-
+
audio(btv, AUDIO_MUTE);
udelay(AUDIO_MUTE_DELAY);
-
- if (freq < tun->thresh1)
- config = tun->VHF_L;
- else if (freq < tun->thresh2)
- config = tun->VHF_H;
- else
- config = tun->UHF;
- if(freq < tun->thresh1)
- config = tun->VHF_L;
- else if(freq < tun->thresh2)
- config = tun->VHF_H;
- else
- config=tun->UHF;
-
- div=freq+tun->IFPCoff;
-
- div&=0x7fff;
+ if (btv->radio)
+ {
+ if (btv->have_tuner)
+ i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
+ TUNER_SET_RADIOFREQ,&fixme);
- if (I2CWrite(btv, btv->tuneradr, (div>>8)&0x7f, div&0xff, 1)<0)
- return;
- I2CWrite(btv, btv->tuneradr, tun->config, config, 1);
- if (!(oldAudio & AUDIO_MUTE))
+ 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)
+ i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
+ TUNER_SET_TVFREQ,&fixme);
+
+ if (btv->have_msp3400) {
+ 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);
+ }
+ }
+
+ if (!(oldAudio & AUDIO_MUTE)) {
udelay(FREQ_CHANGE_DELAY);
audio(btv, AUDIO_UNMUTE);
}
}
+
+
+/*
+ * Grab into virtual memory.
+ * Currently only does double buffering. Do we need more?
+ */
+
+static int vgrab(struct bttv *btv, struct video_mmap *mp)
+{
+ unsigned int *ro, *re;
+ unsigned int *vbuf;
+
+ if(btv->fbuffer==NULL)
+ {
+ if(fbuffer_alloc(btv))
+ return -ENOBUFS;
+ }
+
+ /*
+ * No grabbing past the end of the buffer!
+ */
+
+ if(mp->frame>1 || mp->frame <0)
+ return -EINVAL;
+
+ if(mp->height <0 || mp->width <0)
+ return -EINVAL;
+
+ if(mp->height>480 || mp->width>640)
+ return -EINVAL;
+
+ /*
+ * FIXME: Check the format of the grab here. This is probably
+ * also less restrictive than the normal overlay grabs. Stuff
+ * like QCIF has meaning as a capture.
+ */
+
+ /*
+ * Ok load up the BT848
+ */
+
+ vbuf=(unsigned int *)(btv->fbuffer+0x144000*mp->frame);
+ if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
+ return -EAGAIN;
+ ro=btv->grisc+(((btv->grabcount++)&1) ? 2048 :0);
+ re=ro+1024;
+ btv->gwidth=mp->width;
+ btv->gheight=mp->height;
+ btv->gfmt=mp->format;
+ make_vrisctab(btv, ro, re, vbuf, btv->gwidth, btv->gheight, btv->gfmt);
+ /* bt848_set_risc_jmps(btv); */
+ btor(3, BT848_CAP_CTL);
+ btor(3, BT848_GPIO_DMA_CTL);
+ btv->gro=virt_to_bus(ro);
+ btv->gre=virt_to_bus(re);
+ if (!(btv->grabbing++))
+ btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
+ /* interruptible_sleep_on(&btv->capq); */
+ return 0;
+}
static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock)
{
@@ -608,7 +938,6 @@ static long bttv_read(struct video_device *v, char *buf, unsigned long count, in
todo-=q;
buf+=q;
-/* btv->vbip=0; */
cli();
if (todo && q==VBIBUF_SIZE-btv->vbip)
{
@@ -659,14 +988,17 @@ static int bttv_open(struct video_device *dev, int flags)
users+=bttvs[i].user;
if (users==1)
find_vga();
+ btv->fbuffer=NULL;
+ if (!btv->fbuffer)
+ btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000);
+ if (!btv->fbuffer)
+ {
+ btv->user--;
+ return -EINVAL;
+ }
break;
case 1:
break;
- case 2:
- btv->vbip=VBIBUF_SIZE;
- btv->cap|=0x0c;
- bt848_set_risc_jmps(btv);
- break;
}
MOD_INC_USE_COUNT;
return 0;
@@ -679,17 +1011,15 @@ static void bttv_close(struct video_device *dev)
btv->user--;
audio(btv, AUDIO_MUTE);
btv->cap&=~3;
-#if 0 /* FIXME */
- if(minor&0x20)
- {
- btv->cap&=~0x0c;
- }
-#endif
bt848_set_risc_jmps(btv);
+ if(btv->fbuffer)
+ rvfree((void *) btv->fbuffer, 2*0x144000);
+ btv->fbuffer=0;
MOD_DEC_USE_COUNT;
}
+
/***********************************/
/* ioctls and supporting functions */
/***********************************/
@@ -714,7 +1044,7 @@ extern inline void bt848_contrast(struct bttv *btv, uint cont)
btaor(conthi, ~4, BT848_O_CONTROL);
}
-extern inline void bt848_sat_u(struct bttv *btv, ulong data)
+extern inline void bt848_sat_u(struct bttv *btv, unsigned long data)
{
u32 datahi;
@@ -724,7 +1054,7 @@ extern inline void bt848_sat_u(struct bttv *btv, ulong data)
btaor(datahi, ~2, BT848_O_CONTROL);
}
-static inline void bt848_sat_v(struct bttv *btv, ulong data)
+static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
{
u32 datahi;
@@ -734,6 +1064,7 @@ static inline void bt848_sat_v(struct bttv *btv, ulong data)
btaor(datahi, ~1, BT848_O_CONTROL);
}
+
/*
* Cliprect -> risc table.
*
@@ -772,15 +1103,17 @@ static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
}
first2.next=NULL;
- rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem[rpo++]=0;
+ rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1|(0xf<<20);
+ rmem[rpo++]=0;
- rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem2[rpe++]=0;
+ rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1;
+ rmem2[rpe++]=0;
/*
* 32bit depth frame buffers need extra flags setting
*/
-
+
if (depth==4)
mask=BT848_RISC_BYTE3;
else
@@ -842,7 +1175,7 @@ static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
* here, but the overlap might be partial
*/
- /* add rect to second (x-sorted) list if rect.y == y */
+ /* add rect to second (x-sorted) list if rect.y == y */
if ((cur=first.next))
{
while ((cur) && (cur->y == y))
@@ -953,8 +1286,9 @@ static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count)
{
/* Skip the line : write a SKIP + start/end of line marks */
(*rp)--;
- rpp[(*rp)-1]=BT848_RISC_SKIP|(btv->win.width*depth)|
- BT848_RISC_EOL|BT848_RISC_SOL;
+ rpp[(*rp)-1]=BT848_RISC_SKIP|
+ (btv->win.width*depth)|
+ BT848_RISC_EOL|BT848_RISC_SOL;
}
}
/*
@@ -988,15 +1322,15 @@ static void new_risc_clip(struct video_window *vw, struct video_clip *vcp, int x
vw->clipcount++;
}
+
/*
* ioctl routine
*/
+
static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
unsigned char eedata[256];
-/* unsigned long data;*/
-/* static ushort creg;*/
struct bttv *btv=(struct bttv *)dev;
static int lastchan=0;
@@ -1092,10 +1426,14 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
/* Only channel 0 has a tuner */
if(v.tuner!=0 || lastchan)
return -EINVAL;
- if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC)
+ if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC
+ &&v.mode!=VIDEO_MODE_SECAM)
return -EOPNOTSUPP;
+ /* FIXME: norm should be in video_channel struct
+ composite source can have different norms too
+ */
btv->win.norm = v.mode;
- bt848_set_size(btv);
+ bt848_set_winsize(btv);
return 0;
}
case VIDIOCGPICT:
@@ -1109,6 +1447,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
p.palette=VIDEO_PALETTE_RGB24;
if(btv->win.bpp==4)
p.palette=VIDEO_PALETTE_RGB32;
+
if(copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
return 0;
@@ -1155,7 +1494,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
on=(btv->cap&3)?1:0;
bt848_cap(btv,0);
- bt848_set_size(btv);
+ bt848_set_winsize(btv);
if(vw.clipcount>256)
return -EDOM; /* Too many! */
@@ -1188,7 +1527,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
*/
write_risc_data(btv,vcp, vw.clipcount);
vfree(vcp);
- if(on)
+ if(on && btv->win.vidadr!=0)
bt848_cap(btv,1);
return 0;
}
@@ -1213,14 +1552,15 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
int v;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- if(btv->win.vidadr==0 || btv->win.width==0 || btv->win.height==0)
- return -EINVAL;
if(v==0)
{
bt848_cap(btv,0);
}
else
{
+ if(btv->win.vidadr==0 || btv->win.width==0
+ || btv->win.height==0)
+ return -EINVAL;
bt848_cap(btv,1);
}
return 0;
@@ -1247,7 +1587,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
if(v.depth!=8 && v.depth!=16 && v.depth!=24 && v.depth!=32)
return -EINVAL;
- btv->win.vidadr=(int)v.base;
+ if (v.base)
+ /* also handle virtual base addresses */
+ if ((unsigned int)v.base>=0xe0000000UL)
+ btv->win.vidadr=(uint)v.base;
+ else
+ btv->win.vidadr=PAGE_OFFSET|
+ uvirt_to_bus((uint)v.base);
btv->win.sheight=v.height;
btv->win.swidth=v.width;
btv->win.bpp=v.depth/8;
@@ -1255,7 +1601,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
v.base, v.width,v.height, btv->win.bpp, btv->win.bpl));
- bt848_set_size(btv);
+ bt848_set_winsize(btv);
return 0;
}
case VIDIOCKEY:
@@ -1287,6 +1633,17 @@ 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->have_msp3400)
+ {
+ v.flags|=VIDEO_AUDIO_VOLUME;
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_VOLUME,&(v.volume));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_STEREO,&(v.mode));
+ }
+ else v.mode = VIDEO_SOUND_MONO;
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -1296,28 +1653,55 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
struct video_audio v;
if(copy_from_user(&v,arg, sizeof(v)))
return -EFAULT;
- if(v.audio!=0)
- return -EINVAL;
if(v.flags&VIDEO_AUDIO_MUTE)
audio(btv, AUDIO_MUTE);
+ if(v.audio<0||v.audio>2)
+ return -EINVAL;
+ bt848_muxsel(btv,v.audio);
if(!(v.flags&VIDEO_AUDIO_MUTE))
audio(btv, AUDIO_UNMUTE);
+ if (btv->have_msp3400)
+ {
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_VOLUME,&(v.volume));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_STEREO,&(v.mode));
+ }
btv->audio_dev=v;
return 0;
}
- case BTTV_WRITEEE:
+ case VIDIOCSYNC:
+ if (btv->grabbing && btv->grab==btv->lastgrab)
+ interruptible_sleep_on(&btv->capq);
+ btv->lastgrab=btv->grab;
+ return 0;
+
+ case BTTV_WRITEE:
+ if(!suser())
+ return -EPERM;
if(copy_from_user((void *) eedata, (void *) arg, 256))
return -EFAULT;
- writeee(btv, eedata);
- break;
+ writeee(&(btv->i2c), eedata);
+ return 0;
case BTTV_READEE:
- readee(btv, eedata);
+ if(!suser())
+ return -EPERM;
+ readee(&(btv->i2c), eedata);
if(copy_to_user((void *) arg, (void *) eedata, 256))
return -EFAULT;
break;
+ case VIDIOCMCAPTURE:
+ {
+ struct video_mmap vm;
+ if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm)))
+ return -EFAULT;
+ return vgrab(btv, &vm);
+ }
default:
return -ENOIOCTLCMD;
}
@@ -1329,6 +1713,41 @@ static int bttv_init_done(struct video_device *dev)
return 0;
}
+/*
+ * This maps the vmalloced and reserved fbuffer to user space.
+ *
+ * FIXME:
+ * - PAGE_READONLY should suffice!?
+ * - remap_page_range is kind of inefficient for page by page remapping.
+ * But e.g. pte_alloc() does not work in modules ... :-(
+ */
+
+static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+ struct bttv *btv=(struct bttv *)dev;
+ unsigned long start=(unsigned long) adr;
+ unsigned long page,pos;
+
+ if (size>2*0x144000)
+ return -EINVAL;
+ if (!btv->fbuffer)
+ {
+ if(fbuffer_alloc(btv))
+ return -EINVAL;
+ }
+ pos=(unsigned long) btv->fbuffer;
+ while (size > 0)
+ {
+ page = kvirt_to_phys(pos);
+ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
+ start+=PAGE_SIZE;
+ pos+=PAGE_SIZE;
+ size-=PAGE_SIZE;
+ }
+ return 0;
+}
+
static struct video_device bttv_template=
{
"UNSET",
@@ -1339,6 +1758,96 @@ static struct video_device bttv_template=
bttv_read,
bttv_write,
bttv_ioctl,
+ bttv_mmap,
+ bttv_init_done,
+ NULL,
+ 0,
+ 0
+};
+
+
+static long vbi_read(struct video_device *v, char *buf, unsigned long count,
+ int nonblock)
+{
+ struct bttv *btv=(struct bttv *)(v-2);
+ int q,todo;
+
+ todo=count;
+ while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
+ {
+ if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
+ return -EFAULT;
+ todo-=q;
+ buf+=q;
+
+ cli();
+ if (todo && q==VBIBUF_SIZE-btv->vbip)
+ {
+ if(nonblock)
+ {
+ sti();
+ if(count==todo)
+ return -EWOULDBLOCK;
+ return count-todo;
+ }
+ interruptible_sleep_on(&btv->vbiq);
+ sti();
+ if(signal_pending(current))
+ {
+ if(todo==count)
+ return -EINTR;
+ else
+ return count-todo;
+ }
+ }
+ }
+ if (todo)
+ {
+ if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo))
+ return -EFAULT;
+ btv->vbip+=todo;
+ }
+ return count;
+}
+
+static int vbi_open(struct video_device *dev, int flags)
+{
+ struct bttv *btv=(struct bttv *)(dev-2);
+
+ btv->vbip=VBIBUF_SIZE;
+ btv->cap|=0x0c;
+ bt848_set_risc_jmps(btv);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void vbi_close(struct video_device *dev)
+{
+ struct bttv *btv=(struct bttv *)(dev-2);
+
+ btv->cap&=~0x0c;
+ bt848_set_risc_jmps(btv);
+
+ MOD_DEC_USE_COUNT;
+}
+
+
+static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ return -EINVAL;
+}
+
+static struct video_device vbi_template=
+{
+ "bttv vbi",
+ VID_TYPE_CAPTURE|VID_TYPE_TELETEXT,
+ VID_HARDWARE_BT848,
+ vbi_open,
+ vbi_close,
+ vbi_read,
+ bttv_write,
+ vbi_ioctl,
NULL, /* no mmap yet */
bttv_init_done,
NULL,
@@ -1346,9 +1855,106 @@ static struct video_device bttv_template=
0
};
+
+static int radio_open(struct video_device *dev, int flags)
+{
+ struct bttv *btv = (struct bttv *)(dev-1);
+
+ if (btv->user)
+ return -EBUSY;
+ btv->user++;
+ set_freq(btv,400*16);
+ btv->radio = 1;
+ bt848_muxsel(btv,0);
+ audio(btv, AUDIO_UNMUTE);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void radio_close(struct video_device *dev)
+{
+ struct bttv *btv=(struct bttv *)(dev-1);
+
+ btv->user--;
+ btv->radio = 0;
+ audio(btv, AUDIO_MUTE);
+ MOD_DEC_USE_COUNT;
+}
+
+static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock)
+{
+ return -EINVAL;
+}
+
+static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct bttv *btv=(struct bttv *)(dev-1);
+ static int lastchan=0;
+ switch (cmd) {
+ case VIDIOCGCAP:
+ /* XXX */
+ break;
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner v;
+ if(copy_from_user(&v,arg,sizeof(v))!=0)
+ return -EFAULT;
+ if(v.tuner||lastchan) /* Only tuner 0 */
+ return -EINVAL;
+ strcpy(v.name, "Radio");
+ v.rangelow=(int)(87.5*16);
+ v.rangehigh=(int)(108.0*16);
+ v.flags= 0; /* XXX */
+ v.mode = 0; /* XXX */
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSTUNER:
+ {
+ struct video_tuner v;
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ /* Only channel 0 has a tuner */
+ if(v.tuner!=0 || lastchan)
+ return -EINVAL;
+ /* XXX anything to do ??? */
+ return 0;
+ }
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
+ bttv_ioctl((struct video_device *)btv,cmd,arg);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static struct video_device radio_template=
+{
+ "bttv radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_BT848,
+ radio_open,
+ radio_close,
+ radio_read, /* just returns -EINVAL */
+ bttv_write, /* just returns -EINVAL */
+ radio_ioctl,
+ NULL, /* no mmap */
+ bttv_init_done, /* just returns 0 */
+ NULL,
+ 0,
+ 0
+};
+
+
struct vidbases
{
- ushort vendor, device;
+ unsigned short vendor, device;
char *name;
uint badr;
};
@@ -1386,7 +1992,7 @@ static uint dec_offsets[4] = {
static int find_vga(void)
{
unsigned int devfn, class, vendev;
- ushort vendor, device, badr;
+ unsigned short vendor, device, badr;
int found=0, bus=0, i, tga_type;
unsigned int vidadr=0;
@@ -1470,6 +2076,8 @@ static int find_vga(void)
return found;
}
+
+
#define TRITON_PCON 0x50
#define TRITON_BUS_CONCURRENCY (1<<0)
#define TRITON_STREAMING (1<<1)
@@ -1480,28 +2088,27 @@ static void handle_chipset(void)
{
int index;
+ /* Just in case some nut set this to something dangerous */
+ if (triton1)
+ triton1=BT848_INT_ETBF;
+
for (index = 0; index < 8; index++)
{
unsigned char bus, devfn;
- unsigned char b, bo;
+ 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))
+ 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_82441,
- index, &bus, &devfn))
+ 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, "));
@@ -1512,139 +2119,176 @@ static void handle_chipset(void)
index, &bus, &devfn))
{
printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n");
- pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
- bo=b;
- DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
-
+ 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 */
- if(!(b & TRITON_BUS_CONCURRENCY))
- {
- printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n");
- b |= TRITON_BUS_CONCURRENCY;
- }
+ {
+ unsigned char bo;
- /* still freezes on other boards -> switch off even more */
- 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;
- }
+ pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
+ bo=b;
+ DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
- if (b!=bo)
- {
- pcibios_write_config_byte(bus, devfn, TRITON_PCON, b);
- printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 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
}
}
}
-static void init_tda9850(struct bttv *btv)
+
+static void init_tda9850(struct i2c_bus *bus)
{
- I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0, 1);
+ I2CWrite(bus, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */
+ I2CWrite(bus, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */
+ I2CWrite(bus, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */
+ I2CWrite(bus, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/
+ I2CWrite(bus, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */
+ I2CWrite(bus, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */
+ I2CWrite(bus, I2C_TDA9850, TDA9850_ALI3, 0x03, 1);
}
+
+
/* Figure out card and tuner type */
static void idcard(struct bttv *btv)
{
- int i;
-
+ int tunertype;
btwrite(0, BT848_GPIO_OUT_EN);
DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA)));
- btv->type=BTTV_MIRO;
- btv->tuner=tuner;
-
- if (I2CRead(btv, I2C_HAUPEE)>=0)
- btv->type=BTTV_HAUPPAUGE;
- else if (I2CRead(btv, I2C_STBEE)>=0)
- btv->type=BTTV_STB;
-
- for (i=0xc0; i<0xd0; i+=2)
+ /* Default the card to the user-selected one. */
+ btv->type=card;
+
+ /* If we were asked to auto-detect, then do so!
+ Right now this will only recognize Miro, Hauppauge or STB
+ */
+ if (btv->type == BTTV_UNKNOWN)
{
- if (I2CRead(btv, i)>=0)
- {
- btv->tuneradr=i;
- break;
- }
+ btv->type=BTTV_MIRO;
+
+ if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0)
+ btv->type=BTTV_HAUPPAUGE;
+ else
+ if (I2CRead(&(btv->i2c), I2C_STBEE)>=0)
+ btv->type=BTTV_STB;
}
- btv->dbx = I2CRead(btv, I2C_TDA9850) ? 0 : 1;
+ btv->dbx = I2CRead(&(btv->i2c), I2C_TDA9850) ? 0 : 1;
if (btv->dbx)
- init_tda9850(btv);
+ init_tda9850(&(btv->i2c));
/* How do I detect the tuner type for other cards but Miro ??? */
printk(KERN_INFO "bttv: model: ");
switch (btv->type)
{
case BTTV_MIRO:
- btv->tuner=((btread(BT848_GPIO_DATA)>>10)-1)&7;
- printk("MIRO");
+ 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);
+ }
strcpy(btv->video_dev.name,"BT848(Miro)");
break;
case BTTV_HAUPPAUGE:
- printk("HAUPPAUGE");
+ printk("HAUPPAUGE\n");
strcpy(btv->video_dev.name,"BT848(Hauppauge)");
break;
case BTTV_STB:
- printk("STB");
+ printk("STB\n");
strcpy(btv->video_dev.name,"BT848(STB)");
break;
case BTTV_INTEL:
- printk("Intel");
+ printk("Intel\n");
strcpy(btv->video_dev.name,"BT848(Intel)");
break;
case BTTV_DIAMOND:
- printk("Diamond");
+ printk("Diamond\n");
strcpy(btv->video_dev.name,"BT848(Diamond)");
break;
+ case BTTV_AVERMEDIA:
+ printk("AVerMedia\n");
+ strcpy(btv->video_dev.name,"BT848(AVerMedia)");
+ break;
}
- printk(" (%s @ 0x%02x)\n", tuners[btv->tuner].name, btv->tuneradr);
audio(btv, AUDIO_MUTE);
}
+
static void bt848_set_risc_jmps(struct bttv *btv)
{
int flags=btv->cap;
-
+
+ /* Sync to start of odd field */
btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE;
btv->risc_jmp[1]=0;
- btv->risc_jmp[2]=BT848_RISC_JUMP;
+ /* Jump to odd vbi sub */
+ btv->risc_jmp[2]=BT848_RISC_JUMP|(0x5<<20);
if (flags&8)
btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd);
else
btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4);
- btv->risc_jmp[4]=BT848_RISC_JUMP;
+ /* Jump to odd sub */
+ btv->risc_jmp[4]=BT848_RISC_JUMP|(0x6<<20);
if (flags&2)
btv->risc_jmp[5]=virt_to_bus(btv->risc_odd);
else
btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6);
+
+ /* Sync to start of even field */
btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO;
btv->risc_jmp[7]=0;
+ /* Jump to even vbi sub */
btv->risc_jmp[8]=BT848_RISC_JUMP;
if (flags&4)
btv->risc_jmp[9]=virt_to_bus(btv->vbi_even);
else
btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10);
- btv->risc_jmp[10]=BT848_RISC_JUMP;
+ /* Jump to even sub */
+ btv->risc_jmp[10]=BT848_RISC_JUMP|(8<<20);
if (flags&1)
btv->risc_jmp[11]=virt_to_bus(btv->risc_even);
else
- btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp);
+ btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp+12);
+
+ btv->risc_jmp[12]=BT848_RISC_JUMP;
+ btv->risc_jmp[13]=virt_to_bus(btv->risc_jmp);
+ /* enable cpaturing and DMA */
btaor(flags, ~0x0f, BT848_CAP_CTL);
if (flags&0x0f)
bt848_dma(btv, 3);
@@ -1653,12 +2297,15 @@ static void bt848_set_risc_jmps(struct bttv *btv)
}
-static int init_bt848(struct bttv *btv)
+static int init_bt848(int i)
{
- /* reset the bt848 */
- btwrite(0,BT848_SRESET);
+ struct bttv *btv = &bttvs[i];
+
btv->user=0;
+ /* reset the bt848 */
+ btwrite(0, BT848_SRESET);
+
DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem));
/* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */
@@ -1674,43 +2321,66 @@ static int init_bt848(struct bttv *btv)
btv->win.cropx=0;
btv->win.cropy=0;
btv->win.bpp=2;
+ btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
btv->win.bpl=1024*btv->win.bpp;
btv->win.swidth=1024;
btv->win.sheight=768;
btv->cap=0;
- if (!(btv->risc_odd=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+ btv->gmode=0;
+ btv->risc_odd=0;
+ btv->risc_even=0;
+ btv->risc_jmp=0;
+ btv->vbibuf=0;
+ btv->grisc=0;
+ btv->grabbing=0;
+ btv->grabcount=0;
+ btv->grab=0;
+ btv->lastgrab=0;
+
+ /* i2c */
+ memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus));
+ sprintf(btv->i2c.name,"bt848-%d",i);
+ btv->i2c.data = btv;
+
+ if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
return -1;
- if (!(btv->risc_even=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
+ if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL)))
return -1;
- if (!(btv->risc_jmp =(dword *) kmalloc(2048, GFP_KERNEL)))
+ if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL)))
return -1;
- btv->vbi_odd=btv->risc_jmp+12;
+ DEBUG(printk(KERN_DEBUG "risc_jmp: %p\n",btv->risc_jmp));
+ btv->vbi_odd=btv->risc_jmp+16;
btv->vbi_even=btv->vbi_odd+256;
- btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp);
+ btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12);
btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6);
btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD);
- btv->vbibuf=(unchar *) vmalloc(VBIBUF_SIZE);
+ btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE);
if (!btv->vbibuf)
return -1;
+ if (!(btv->grisc=(unsigned int *) kmalloc(16384, GFP_KERNEL)))
+ return -1;
+
+ btv->fbuffer=NULL;
bt848_muxsel(btv, 1);
- bt848_set_size(btv);
+ bt848_set_winsize(btv);
/* btwrite(0, BT848_TDEC); */
btwrite(0x10, BT848_COLOR_CTL);
btwrite(0x00, BT848_CAP_CTL);
+ btwrite(0xfc, BT848_GPIO_DMA_CTL);
btwrite(0x0ff, BT848_VBI_PACK_SIZE);
btwrite(1, BT848_VBI_PACK_DEL);
- btwrite(0xfc, BT848_GPIO_DMA_CTL);
+
btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI,
BT848_IFORM);
- bt848_bright(btv, 0x10);
btwrite(0xd8, BT848_CONTRAST_LO);
+ bt848_bright(btv, 0x10);
btwrite(0x60, BT848_E_VSCALE_HI);
btwrite(0x60, BT848_O_VSCALE_HI);
@@ -1719,19 +2389,27 @@ static int init_bt848(struct bttv *btv)
btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+
+ btv->picture.colour=254<<7;
+ btv->picture.brightness=128<<8;
+ btv->picture.hue=128<<8;
+ btv->picture.contrast=0xd8<<7;
+
btwrite(0x00, BT848_E_SCLOOP);
btwrite(0x00, BT848_O_SCLOOP);
- btwrite(0xffffffUL,BT848_INT_STAT);
-/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|BT848_INT_FDSR|
- BT848_INT_FTRGT|BT848_INT_FBUS|*/
- btwrite(BT848_INT_ETBF|
+ /* clear interrupt status */
+ btwrite(0xfffffUL, BT848_INT_STAT);
+
+ /* set interrupt mask */
+ btwrite(triton1|
+/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|
+ BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/
BT848_INT_SCERR|
BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES|
BT848_INT_FMTCHG|BT848_INT_HLOCK,
BT848_INT_MASK);
-/* make_risctab(btv); */
make_vbitab(btv);
bt848_set_risc_jmps(btv);
@@ -1739,20 +2417,32 @@ static int init_bt848(struct bttv *btv)
* Now add the template and register the device unit.
*/
- memcpy(&btv->video_dev,&bttv_template,sizeof(bttv_template));
+ memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template));
+ memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
+ memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template));
idcard(btv);
-
- btv->picture.brightness=0x90<<8;
- btv->picture.contrast = 0x70 << 8;
- btv->picture.colour = 0x70<<8;
- btv->picture.hue = 0x8000;
-
- if(video_register_device(&btv->video_dev)<0)
+
+ if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0)
return -1;
+ if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0)
+ {
+ video_unregister_device(&btv->video_dev);
+ return -1;
+ }
+ if (radio)
+ {
+ if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0)
+ {
+ video_unregister_device(&btv->vbi_dev);
+ video_unregister_device(&btv->video_dev);
+ return -1;
+ }
+ }
+ i2c_register_bus(&btv->i2c);
+
return 0;
}
-
static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
{
u32 stat,astat;
@@ -1779,7 +2469,8 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (astat&BT848_INT_FMTCHG)
{
IDEBUG(printk ("bttv: IRQ_FMTCHG\n"));
-/* btv->win.norm&=(dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
+ /*btv->win.norm&=
+ (dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */
}
if (astat&BT848_INT_VPRES)
{
@@ -1795,22 +2486,47 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
bt848_dma(btv, 1);
wake_up_interruptible(&btv->vbiq);
wake_up_interruptible(&btv->capq);
+
}
if (astat&BT848_INT_RISCI)
{
IDEBUG(printk ("bttv: IRQ_RISCI\n"));
- /* printk ("bttv: IRQ_RISCI%d\n",stat>>28); */
+
+ /* captured VBI frame */
if (stat&(1<<28))
{
btv->vbip=0;
wake_up_interruptible(&btv->vbiq);
}
+
+ /* captured full frame */
if (stat&(2<<28))
{
- bt848_set_risc_jmps(btv);
+ btv->grab++;
wake_up_interruptible(&btv->capq);
+ if ((--btv->grabbing))
+ {
+ btv->risc_jmp[5]=btv->gro;
+ btv->risc_jmp[11]=btv->gre;
+ bt848_set_geo(btv, btv->gwidth,
+ btv->gheight,
+ btv->gfmt);
+ } else {
+ bt848_set_risc_jmps(btv);
+ bt848_set_geo(btv, btv->win.width,
+ btv->win.height,
+ btv->win.color_fmt);
+ }
break;
}
+ if (stat&(8<<28))
+ {
+ btv->risc_jmp[5]=btv->gro;
+ btv->risc_jmp[11]=btv->gre;
+ btv->risc_jmp[12]=BT848_RISC_JUMP;
+ bt848_set_geo(btv, btv->gwidth, btv->gheight,
+ btv->gfmt);
+ }
}
if (astat&BT848_INT_OCERR)
{
@@ -1842,7 +2558,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
}
if (astat&BT848_INT_HLOCK)
{
- if (dstat&BT848_DSTATUS_HLOC)
+ if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio))
audio(btv, AUDIO_ON);
else
audio(btv, AUDIO_OFF);
@@ -1858,12 +2574,14 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (count > 20)
{
btwrite(0, BT848_INT_MASK);
- printk(KERN_ERR "bttv: IRQ lockup, cleared int mask\n");
+ printk(KERN_ERR
+ "bttv: IRQ lockup, cleared int mask\n");
}
}
}
+
/*
* Scan for a Bt848 card, request the irq and map the io memory
*/
@@ -1885,8 +2603,10 @@ static int find_bt848(void)
}
for (pci_index = 0;
- !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_BT849,
+ pci_index, &bus, &devfn)
+ ||!pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
+ pci_index, &bus, &devfn);
++pci_index)
{
btv=&bttvs[bttv_num];
@@ -1899,8 +2619,13 @@ static int find_bt848(void)
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,
@@ -1921,7 +2646,8 @@ static int find_bt848(void)
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: Brooktree Bt848 (rev %d) ",btv->revision);
+ printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
+ btv->id, btv->revision);
printk("bus: %d, devfn: %d, ",
btv->bus, btv->devfn);
printk("irq: %d, ",btv->irq);
@@ -1959,8 +2685,8 @@ static int find_bt848(void)
if (!latency)
{
latency=32;
- pcibios_write_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER,
- latency);
+ pcibios_write_config_byte(btv->bus, btv->devfn,
+ PCI_LATENCY_TIMER, latency);
}
DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
bttv_num++;
@@ -1970,6 +2696,7 @@ static int find_bt848(void)
return bttv_num;
}
+
static void release_bttv(void)
{
u8 command;
@@ -1979,21 +2706,28 @@ static void release_bttv(void)
for (i=0;i<bttv_num; i++)
{
btv=&bttvs[i];
+
/* turn off all capturing, DMA and IRQs */
+ btand(~15, BT848_GPIO_DMA_CTL);
+
/* first disable interrupts before unmapping the memory! */
btwrite(0, BT848_INT_MASK);
btwrite(0xffffffffUL,BT848_INT_STAT);
btwrite(0x0, BT848_GPIO_OUT_EN);
- bt848_cap(btv, 0);
-
+ /* unregister i2c_bus */
+ i2c_unregister_bus((&btv->i2c));
+
/* disable PCI 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);
/* unmap and free memory */
+ if (btv->grisc)
+ kfree((void *) btv->grisc);
+
if (btv->risc_odd)
kfree((void *) btv->risc_odd);
@@ -2007,15 +2741,20 @@ static void release_bttv(void)
DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf));
if (btv->vbibuf)
vfree((void *) btv->vbibuf);
+
+
free_irq(btv->irq,btv);
DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
if (btv->bt848_mem)
iounmap(btv->bt848_mem);
+
video_unregister_device(&btv->video_dev);
+ video_unregister_device(&btv->vbi_dev);
+ if (radio)
+ video_unregister_device(&btv->radio_dev);
}
}
-
#ifdef MODULE
int init_module(void)
@@ -2030,22 +2769,39 @@ int init_bttv_cards(struct video_init *unused)
if (find_bt848()<0)
return -EIO;
+ /* initialize Bt848s */
for (i=0; i<bttv_num; i++)
{
- if (init_bt848(&bttvs[i])<0)
+ if (init_bt848(i)<0)
{
release_bttv();
return -EIO;
}
- }
+ }
return 0;
}
+
+
#ifdef MODULE
void cleanup_module(void)
{
- release_bttv();
+ release_bttv();
}
#endif
+
+/*
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index e1c54e94c..ca0fb057c 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -26,72 +26,138 @@
#include <linux/types.h>
#include <linux/wait.h>
+#include "i2c.h"
+#include "msp3400.h"
#include "bt848.h"
+#include <linux/videodev.h>
-typedef unsigned int dword;
+#define MAX_CLIPRECS 100
+#define RISCMEM_LEN (32744*2)
+#define MAX_FBUF 0x144000
-struct riscprog {
- uint length;
- dword *busadr;
- dword *prog;
+struct riscprog
+{
+ unsigned int length;
+ u32 *busadr;
+ u32 *prog;
};
-/* values that can be set by user programs */
-
-struct bttv_window {
- int x, y;
- ushort width, height;
- ushort bpp, bpl;
- ushort swidth, sheight;
- short cropx, cropy;
- ushort cropwidth, cropheight;
- int vidadr;
- ushort freq;
- int norm;
- int interlace;
- int color_fmt;
+
+/* clipping rectangle */
+struct cliprec
+{
+ int x, y, x2, y2;
+ struct cliprec *next;
+};
+
+
+/* grab buffer */
+struct gbuffer
+{
+ struct gbuffer *next;
+ struct gbuffer *next_active;
+ void *adr;
+ int x, y;
+ int width, height;
+ unsigned int bpl;
+ unsigned int fmt;
+ int flags;
+#define GBUF_ODD 1
+#define GBUF_EVEN 2
+#define GBUF_LFB 4
+#define GBUF_INT 8
+ unsigned int length;
+ void *ro;
+ void *re;
+ u32 bro;
+ u32 bre;
+};
+
+
+#ifdef __KERNEL__
+
+struct bttv_window
+{
+ int x, y;
+ ushort width, height;
+ ushort bpp, bpl;
+ ushort swidth, sheight;
+ short cropx, cropy;
+ ushort cropwidth, cropheight;
+ unsigned int vidadr;
+ ushort freq;
+ int norm;
+ int interlace;
+ int color_fmt;
};
-/* private data that can only be read (or set indirectly) by user program */
-
-struct bttv {
- struct video_device video_dev;
- struct video_picture picture; /* Current picture params */
- struct video_audio audio_dev; /* Current audio params */
- u_char bus; /* PCI bus the Bt848 is on */
- u_char devfn;
- u_char revision;
- u_char irq; /* IRQ used by Bt848 card */
- uint bt848_adr; /* bus address of IO mem returned by PCI BIOS */
- u_char *bt848_mem; /* pointer to mapped IO memory */
- ulong busriscmem;
- dword *riscmem;
+
+struct bttv
+{
+ struct video_device video_dev;
+ struct video_device radio_dev;
+ struct video_device vbi_dev;
+ struct video_picture picture; /* Current picture params */
+ struct video_audio audio_dev; /* Current audio params */
+
+ struct i2c_bus i2c;
+ int have_msp3400;
+ int have_tuner;
+
+ unsigned short id;
+ unsigned char bus; /* PCI bus the Bt848 is on */
+ unsigned char devfn;
+ unsigned char revision;
+ unsigned char irq; /* IRQ used by Bt848 card */
+ unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */
+ unsigned char *bt848_mem; /* pointer to mapped IO memory */
+ unsigned long busriscmem;
+ u32 *riscmem;
- u_char *vbibuf;
- struct bttv_window win;
- int type; /* card type */
- int audio; /* audio mode */
- int user;
- int tuner;
- int tuneradr;
- int dbx;
-
- dword *risc_jmp;
- dword *vbi_odd;
- dword *vbi_even;
- dword bus_vbi_even;
- dword bus_vbi_odd;
- struct wait_queue *vbiq;
- struct wait_queue *capq;
- int vbip;
-
- dword *risc_odd;
- dword *risc_even;
- int cap;
+ unsigned char *vbibuf;
+ struct bttv_window win;
+ int type; /* card type */
+ int audio; /* audio mode */
+ int user;
+ int dbx;
+ int radio;
+
+ u32 *risc_jmp;
+ u32 *vbi_odd;
+ u32 *vbi_even;
+ u32 bus_vbi_even;
+ u32 bus_vbi_odd;
+ struct wait_queue *vbiq;
+ struct wait_queue *capq;
+ struct wait_queue *capqo;
+ struct wait_queue *capqe;
+ int vbip;
+
+ u32 *risc_odd;
+ u32 *risc_even;
+ int cap;
+ struct cliprec *cliprecs;
+ int ncr; /* number of clipping rectangles */
+
+ struct gbuffer *ogbuffers;
+ struct gbuffer *egbuffers;
+ u16 gwidth, gheight, gfmt;
+ u32 *grisc;
+ unsigned long gro;
+ unsigned long gre;
+ char *fbuffer;
+ int gmode;
+ int grabbing;
+ int lastgrab;
+ int grab;
+ int grabcount;
};
+#endif
+
/*The following should be done in more portable way. It depends on define
of _ALPHA_BTTV in the Makefile.*/
+
#ifdef _ALPHA_BTTV
#define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr)))
#define btread(adr) readl(btv->bt848_adr+(adr))
@@ -105,30 +171,10 @@ struct bttv {
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
/* bttv ioctls */
-#define BTTV_WRITE_BTREG 0x00
-#define BTTV_READ_BTREG 0x01
-#define BTTV_SET_BTREG 0x02
-#define BTTV_SETRISC 0x03
-#define BTTV_SETWTW 0x04
-#define BTTV_GETWTW 0x05
-#define BTTV_DMA 0x06
-#define BTTV_CAP_OFF 0x07
-#define BTTV_CAP_ON 0x08
-#define BTTV_GETBTTV 0x09
-#define BTTV_SETFREQ 0x0a
-#define BTTV_SETCHAN 0x0b
-#define BTTV_INPUT 0x0c
-#define BTTV_READEE 0x0d
-#define BTTV_WRITEEE 0x0e
-#define BTTV_BRIGHT 0x0f
-#define BTTV_HUE 0x10
-#define BTTV_COLOR 0x11
-#define BTTV_CONTRAST 0x12
-#define BTTV_SET_FFREQ 0x13
-#define BTTV_MUTE 0x14
-
-#define BTTV_GRAB 0x20
-#define BTTV_TESTM 0x20
+
+#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_UNKNOWN 0x00
@@ -137,12 +183,14 @@ struct bttv {
#define BTTV_STB 0x03
#define BTTV_INTEL 0x04
#define BTTV_DIAMOND 0x05
+#define BTTV_AVERMEDIA 0x06
#define AUDIO_TUNER 0x00
-#define AUDIO_EXTERN 0x01
-#define AUDIO_INTERN 0x02
-#define AUDIO_OFF 0x03
-#define AUDIO_ON 0x04
+#define AUDIO_RADIO 0x01
+#define AUDIO_EXTERN 0x02
+#define AUDIO_INTERN 0x03
+#define AUDIO_OFF 0x04
+#define AUDIO_ON 0x05
#define AUDIO_MUTE 0x80
#define AUDIO_UNMUTE 0x81
diff --git a/drivers/char/bw-qcam.c b/drivers/char/bw-qcam.c
index 48951cdb8..2142cf6a1 100644
--- a/drivers/char/bw-qcam.c
+++ b/drivers/char/bw-qcam.c
@@ -885,7 +885,7 @@ int init_bwqcam(struct parport *port)
printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
- if(video_register_device(&qcam->vdev)==-1)
+ if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1)
{
parport_unregister_device(qcam->pdev);
kfree(qcam);
diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c
index a69684110..e424266c8 100644
--- a/drivers/char/c-qcam.c
+++ b/drivers/char/c-qcam.c
@@ -727,7 +727,7 @@ int init_cqcam(struct parport *port)
printk(KERN_INFO "Connectix Colour Quickcam on %s\n",
qcam->pport->name);
- if (video_register_device(&qcam->vdev)==-1)
+ if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER)==-1)
{
parport_unregister_device(qcam->pdev);
kfree(qcam);
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 26c1ceda8..bff096479 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -220,6 +220,120 @@ int last_console = 0;
int want_console = -1;
int kmsg_redirect = 0;
+#ifdef CONFIG_SERIAL_ECHO
+
+#include <linux/serial_reg.h>
+
+extern int serial_echo_init (int base);
+extern int serial_echo_print (const char *s);
+
+/*
+ * this defines the address for the port to which printk echoing is done
+ * when CONFIG_SERIAL_ECHO is defined
+ */
+#define SERIAL_ECHO_PORT 0x3f8 /* COM1 */
+
+static int serial_echo_port = 0;
+
+#define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port)
+#define serial_echo_inb(a) inb((a)+serial_echo_port)
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/* Wait for transmitter & holding register to empty */
+#define WAIT_FOR_XMITR \
+ do { \
+ lsr = serial_echo_inb(UART_LSR); \
+ } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+
+/* These two functions abstract the actual communications with the
+ * debug port. This is so we can change the underlying communications
+ * mechanism without modifying the rest of the code.
+ */
+int
+serial_echo_print(const char *s)
+{
+ int lsr, ier;
+ int i;
+
+ if (!serial_echo_port) return (0);
+
+ /*
+ * First save the IER then disable the interrupts
+ */
+ ier = serial_echo_inb(UART_IER);
+ serial_echo_outb(0x00, UART_IER);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; *s; i++, s++) {
+ WAIT_FOR_XMITR;
+
+ /* Send the character out. */
+ serial_echo_outb(*s, UART_TX);
+
+ /* if a LF, also do CR... */
+ if (*s == 10) {
+ WAIT_FOR_XMITR;
+ serial_echo_outb(13, UART_TX);
+ }
+ }
+
+ /*
+ * Finally, Wait for transmitter & holding register to empty
+ * and restore the IER
+ */
+ do {
+ lsr = serial_echo_inb(UART_LSR);
+ } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+ serial_echo_outb(ier, UART_IER);
+
+ return (0);
+}
+
+
+int
+serial_echo_init(int base)
+{
+ int comstat, hi, lo;
+
+ if (base != 0x2f8 && base != 0x3f8) {
+ serial_echo_port = 0;
+ return (0);
+ } else
+ serial_echo_port = base;
+
+ /*
+ * read the Divisor Latch
+ */
+ comstat = serial_echo_inb(UART_LCR);
+ serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR);
+ hi = serial_echo_inb(UART_DLM);
+ lo = serial_echo_inb(UART_DLL);
+ serial_echo_outb(comstat, UART_LCR);
+
+ /*
+ * now do hardwired init
+ */
+ serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */
+ serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */
+ serial_echo_outb(0x00, UART_DLM); /* 9600 baud */
+ serial_echo_outb(0x0c, UART_DLL);
+ serial_echo_outb(0x03, UART_LCR); /* Done with divisor */
+
+ /* Prior to disabling interrupts, read the LSR and RBR
+ * registers
+ */
+ comstat = serial_echo_inb(UART_LSR); /* COM? LSR */
+ comstat = serial_echo_inb(UART_RX); /* COM? RBR */
+ serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */
+
+ return(0);
+}
+
+#endif /* CONFIG_SERIAL_ECHO */
+
int vc_cons_allocated(unsigned int i)
{
return (i < MAX_NR_CONSOLES && vc_cons[i].d);
@@ -610,6 +724,37 @@ scrdown(int currcons, unsigned int t, unsigned int b, unsigned int nr)
has_scrolled = 1;
}
+/*
+ * Routine to reset the visible "screen" to the top of video memory.
+ * This is necessary when exiting from the kernel back to a console
+ * which expects only the top of video memory to be used for the visible
+ * screen (with scrolling down by moving the memory contents).
+ * The normal action of the LINUX console is to scroll using all of the
+ * video memory and diddling the hardware top-of-video register as needed.
+ */
+void
+scrreset(void)
+{
+ int currcons = fg_console;
+ unsigned short * d = (unsigned short *) video_mem_start;
+ unsigned short * s = (unsigned short *) origin;
+ unsigned int count;
+
+ count = (video_num_lines-1)*video_num_columns;
+ memcpyw(d, s, 2*count);
+ memsetw(d + count, video_erase_char,
+ 2*video_num_columns);
+ scr_end -= origin-video_mem_start;
+ pos -= origin-video_mem_start;
+ origin = video_mem_start;
+
+ has_scrolled = 1;
+ has_wrapped = 1;
+
+ set_origin(currcons);
+ set_cursor(currcons);
+}
+
static void lf(int currcons)
{
/* don't scroll if above bottom of scrolling region, or
@@ -1897,6 +2042,10 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
return;
}
+#ifdef CONFIG_SERIAL_ECHO
+ serial_echo_print(b);
+#endif /* CONFIG_SERIAL_ECHO */
+
while (count-- > 0) {
c = *(b++);
if (c == 10 || c == 13 || need_wrap) {
@@ -2161,6 +2310,10 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
/* This may be suboptimal but is a safe bet - go with it */
video_scan_lines = video_font_height * video_num_lines;
+#ifdef CONFIG_SERIAL_ECHO
+ serial_echo_init(SERIAL_ECHO_PORT);
+#endif /* CONFIG_SERIAL_ECHO */
+
printk("Console: %ld point font, %ld scans\n",
video_font_height, video_scan_lines);
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 4535230ac..9f51607fe 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,6 +1,9 @@
#define BLOCKMOVE
+#define NEW_INTR_FLOW
+#define Z_WAKE
+#define NEW_PCI
static char rcsid[] =
-"$Revision: 2.1.1.1 $$Date: 1997/12/03 17:31:19 $";
+"$Revision: 2.2.1.1 $$Date: 1998/03/19 16:43:12 $";
/*
* linux/drivers/char/cyclades.c
@@ -30,11 +33,28 @@ static char rcsid[] =
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
+ * Revision 2.2.1.1 1998/03/19 16:43:12 ivan
+ * added conditional compilation for new/old PCI structure support;
+ * removed kernel series (2.0.x / 2.1.x) conditional compilation.
+ *
+ * Revision 2.1.1.3 1998/03/16 18:01:12 ivan
+ * cleaned up the data loss fix;
+ * fixed XON/XOFF handling once more (Cyclades-Z);
+ * general revision in the driver routines;
+ * introduction of a mechanism to prevent data loss with slow
+ * printers, by forcing a delay before closing the port.
+ *
+ * Revision 2.1.1.2 1998/02/17 16:50:00 ivan
+ * fixed detection/handling of new CD1400 in Ye boards;
+ * fixed XON/XOFF handling (Cyclades-Z);
+ * fixed data loss caused by a premature port close;
+ * introduction of a flag that holds the CD1400 version ID per port
+ * (used by the CYGETCD1400VER new ioctl).
+ *
* Revision 2.1.1.1 1997/12/03 17:31:19 ivan
- * Code review for the module cleanup routine (fixed memory leak);
+ * Code review for the module cleanup routine;
* fixed RTS and DTR status report for new CD1400's in get_modem_info;
- * purged conditional code for older kernels;
- * includes anonymous changes regarding signal_pending
+ * includes anonymous changes regarding signal_pending.
*
* Revision 2.1 1997/11/01 17:42:41 ivan
* Changes in the driver to support Alpha systems (except 8Zo V_1);
@@ -461,17 +481,16 @@ static char rcsid[] =
#define ZO_V2 1
#define ZE_V1 2
-#define SERIAL_PARANOIA_CHECK
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_OTHER
-#undef SERIAL_DEBUG_IO
-#undef SERIAL_DEBUG_COUNT
-#undef SERIAL_DEBUG_DTR
-#undef CYCLOM_16Y_HACK
-#undef CYCLOM_ENABLE_MONITORING
-#undef CY_PCI_DEBUG
-
+#define SERIAL_PARANOIA_CHECK
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_THROTTLE
+#undef SERIAL_DEBUG_OTHER
+#undef SERIAL_DEBUG_IO
+#undef SERIAL_DEBUG_COUNT
+#undef SERIAL_DEBUG_DTR
+#undef CYCLOM_16Y_HACK
+#undef CYCLOM_ENABLE_MONITORING
+#undef CY_PCI_DEBUG
#if 0
#define PAUSE __asm__("nop");
@@ -525,7 +544,9 @@ static char rcsid[] =
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
+#ifndef NEW_PCI
#include <linux/bios32.h>
+#endif
#include <linux/pci.h>
#include <linux/version.h>
@@ -567,10 +588,9 @@ static unsigned long cy_get_user(unsigned long *addr)
#define SERIAL_TYPE_NORMAL 1
#define SERIAL_TYPE_CALLOUT 2
+static DECLARE_TASK_QUEUE(tq_cyclades);
-DECLARE_TASK_QUEUE(tq_cyclades);
-
-struct tty_driver cy_serial_driver, cy_callout_driver;
+static struct tty_driver cy_serial_driver, cy_callout_driver;
static volatile int cy_irq_triggered;
static volatile int cy_triggered;
@@ -857,7 +877,6 @@ do_cyclades_bh(void)
run_task_queue(&tq_cyclades);
} /* do_cyclades_bh */
-
static void
do_softint(void *private_)
{
@@ -884,6 +903,11 @@ do_softint(void *private_)
}
wake_up_interruptible(&tty->write_wait);
}
+#ifdef Z_WAKE
+ if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) {
+ wake_up_interruptible(&info->shutdown_wait);
+ }
+#endif
} /* do_softint */
@@ -1015,6 +1039,7 @@ get_auto_irq(volatile ucchar *address)
unsigned long timeout;
volatile ucchar *base_addr;
int index;
+ unsigned long flags;
index = 0; /* IRQ probing is only for ISA */
base_addr = address;
@@ -1024,13 +1049,13 @@ get_auto_irq(volatile ucchar *address)
* Enable interrupts and see who answers
*/
cy_irq_triggered = 0;
- cli();
+ save_flags(flags); cli();
cy_writeb((u_long)base_addr+(CyCAR<<index), 0);
cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
probe_ready = 1;
- sti();
+ restore_flags(flags);
timeout = jiffies+(HZ/50);
while (timeout >= jiffies) {
@@ -1051,7 +1076,7 @@ do_auto_irq(volatile ucchar *address)
int irq_lines = 0;
int irq_try_1 = 0, irq_try_2 = 0;
int retries;
- unsigned long flags;
+ unsigned long flags;
/* Turn on interrupts (they may be off) */
save_flags(flags); sti();
@@ -1347,7 +1372,7 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
/* delay a bit */
cy_writeb((u_long)base_addr + (CyTDR<<index), 0);
cy_writeb((u_long)base_addr + (CyTDR<<index), 0x82);
- if (cy_readb(base_addr + (CyGFRCR<<index)) >= 0x48 ) {
+ if (info->chip_rev >= CD1400_REV_J ) {
/* It is a CD1400 rev. J or later */
cy_writeb((u_long)base_addr + (CyTDR<<index),
info->x_break*500/HZ);
@@ -1362,7 +1387,30 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
info->x_break = 0;
}
+#ifdef NEW_INTR_FLOW
+ if (!info->xmit_cnt){
+ cy_writeb((u_long)base_addr+(CySRER<<index),
+ cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+ cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+ goto txdone;
+ }
+ if (info->xmit_buf == 0){
+ cy_writeb((u_long)base_addr+(CySRER<<index),
+ cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+ goto txdone;
+ }
+ if (info->tty->stopped || info->tty->hw_stopped){
+ cy_writeb((u_long)base_addr+(CySRER<<index),
+ cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+ goto txdone;
+ }
+#endif
while (char_count-- > 0){
+#ifdef NEW_INTR_FLOW
+ if (!info->xmit_cnt){
+ goto txdone;
+ }
+#else
if (!info->xmit_cnt){
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
@@ -1376,8 +1424,8 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
if (info->tty->stopped || info->tty->hw_stopped){
cy_writeb((u_long)base_addr+(CySRER<<index),
cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- goto txdone;
- }
+ }
+#endif
/* Because the Embedded Transmit Commands have
been enabled, we must check to see if the
escape character, NULL, is being sent. If it
@@ -1413,7 +1461,6 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
if (info->xmit_cnt < WAKEUP_CHARS) {
cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
}
-
txend:
/* end of service */
cy_writeb((u_long)base_addr+(CyTIR<<index),
@@ -1492,7 +1539,6 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
/* clear interrupts */
cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<<index), 0);
/* Cy_ClrIntr is 0x1800 */
-
} /* cyy_interrupt */
/***********************************************************/
@@ -1715,6 +1761,11 @@ cyz_poll(unsigned long arg)
break;
case C_CM_MDSR:
break;
+#ifdef Z_WAKE
+ case C_CM_IOCTLW:
+ cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+ break;
+#endif
case C_CM_FATAL:
/* should do something with this !!! */
break;
@@ -1995,7 +2046,13 @@ startup(struct cyclades_port * info)
#endif
cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
- cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD|C_IN_MCTS);
+#ifdef Z_WAKE
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_MDCD|C_IN_MCTS|C_IN_IOCTLW);
+#else
+ cy_writel(&ch_ctrl[channel].intr_enable,
+ C_IN_MDCD|C_IN_MCTS);
+#endif
retval = cyz_issue_cmd( &cy_card[card],
channel, C_CM_IOCTL, 0L); /* was C_CM_RESET */
if (retval != 0){
@@ -2090,20 +2147,14 @@ shutdown(struct cyclades_port * info)
card, chip, channel, (long)base_addr);
#endif
- /* REALLY SHOULD WAIT FOR LAST CHARACTER TO BE
- SENT BEFORE DROPPING THE LINE !!! (Perhaps
- set some flag that is read when XMTY happens.)
- Other choices are to delay some fixed interval
- or schedule some later processing.
- */
save_flags(flags); cli();
+
if (info->xmit_buf){
unsigned char * temp;
temp = info->xmit_buf;
info->xmit_buf = 0;
free_page((unsigned long) temp);
}
-
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
@@ -2148,14 +2199,15 @@ shutdown(struct cyclades_port * info)
board_ctrl = &(zfw_ctrl->board_ctrl);
ch_ctrl = zfw_ctrl->ch_ctrl;
-
save_flags(flags); cli();
+
if (info->xmit_buf){
unsigned char * temp;
temp = info->xmit_buf;
info->xmit_buf = 0;
free_page((unsigned long) temp);
}
+
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
cy_writel((u_long)&ch_ctrl[channel].rs_control,
(uclong)(cy_readl(&ch_ctrl[channel].rs_control) &
@@ -2163,14 +2215,13 @@ shutdown(struct cyclades_port * info)
retval = cyz_issue_cmd(&cy_card[info->card],
channel, C_CM_IOCTLM, 0L);
if (retval != 0){
- printk("cyc:shutdown retval was %x\n",
- retval);
+ printk("cyc:shutdown retval (2) was %x\n", retval);
}
#ifdef SERIAL_DEBUG_DTR
printk("cyc:shutdown dropping Z DTR\n");
#endif
}
-
+
if (info->tty){
set_bit(TTY_IO_ERROR, &info->tty->flags);
}
@@ -2207,8 +2258,10 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
*/
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING) {
+ interruptible_sleep_on(&info->close_wait);
+ }
if (info->flags & ASYNC_HUP_NOTIFY){
return -EAGAIN;
}else{
@@ -2242,7 +2295,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
* If non-blocking mode is set, then make the check up front
* and then exit.
*/
- if (filp->f_flags & O_NONBLOCK) {
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
if (info->flags & ASYNC_CALLOUT_ACTIVE){
return -EBUSY;
}
@@ -2263,7 +2317,10 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
- info->count--;
+ save_flags(flags); cli();
+ if (!tty_hung_up_p(filp))
+ info->count--;
+ restore_flags(flags);
#ifdef SERIAL_DEBUG_COUNT
printk("cyc block_til_ready: (%d): decrementing count to %d\n",
current->pid, info->count);
@@ -2569,8 +2626,54 @@ cy_close(struct tty_struct * tty, struct file * filp)
info->normal_termios = *tty->termios;
if (info->flags & ASYNC_CALLOUT_ACTIVE)
info->callout_termios = *tty->termios;
- if (info->flags & ASYNC_INITIALIZED)
- tty_wait_until_sent(tty, 5*HZ); /* 5 seconds timeout */
+
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait2 != 0) { /* The port's being forced to wait,
+ independent on the port settings */
+ tty_wait_until_sent(tty, info->closing_wait2*HZ);
+ } else {
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait*HZ);
+ }
+
+ /* Waiting for on-board buffers to be empty before closing the port */
+ if (!IS_CYC_Z(cy_card[info->card])) {
+#ifdef NEW_INTR_FLOW
+ unsigned char *base_addr = (unsigned char *)
+ cy_card[info->card].base_addr;
+ int index = cy_card[info->card].bus_index;
+
+ if (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
+ /* Interrupts are enabled, so go to sleep */
+ interruptible_sleep_on(&info->shutdown_wait);
+ }
+#endif
+ } else {
+#ifdef Z_WAKE
+ unsigned char *base_addr = (unsigned char *)
+ cy_card[info->card].base_addr;
+ struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
+ struct ZFW_CTRL *zfw_ctrl =
+ (struct ZFW_CTRL *) (base_addr + cy_readl(&firm_id->zfwctrl_addr));
+ struct CH_CTRL *ch_ctrl = zfw_ctrl->ch_ctrl;
+ int channel = info->line - cy_card[info->card].first_line;
+ int retval;
+
+ if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+ retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ C_CM_IOCTLW, 0L);
+ if (retval != 0){
+ printk("cyc:shutdown retval (1) was %x\n", retval);
+ }
+ interruptible_sleep_on(&info->shutdown_wait);
+ }
+#endif
+ }
+
shutdown(info);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
@@ -2635,14 +2738,13 @@ cy_write(struct tty_struct * tty, int from_user,
if (from_user)
down(&tmp_buf_sem);
+ save_flags(flags);
while (1) {
- save_flags(flags); cli();
+ cli();
c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0){
- restore_flags(flags);
+ if (c <= 0)
break;
- }
if (from_user) {
copy_from_user(tmp_buf, buf, c);
@@ -2665,13 +2767,10 @@ cy_write(struct tty_struct * tty, int from_user,
}
if (from_user)
up(&tmp_buf_sem);
-
-
- if (info->xmit_cnt
- && !tty->stopped
- && !tty->hw_stopped ) {
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
start_xmit(info);
}
+ restore_flags(flags);
return total;
} /* cy_write */
@@ -2789,16 +2888,47 @@ static int
cy_chars_in_buffer(struct tty_struct *tty)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, channel;
-#ifdef SERIAL_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
- info->line, info->xmit_cnt); /* */
-#endif
-
if (serial_paranoia_check(info, tty->device, "cy_chars_in_buffer"))
return 0;
- return info->xmit_cnt;
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+
+ if (!IS_CYC_Z(cy_card[card])) {
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt); /* */
+#endif
+ return info->xmit_cnt;
+ } else {
+ static volatile struct FIRM_ID *firm_id;
+ static volatile struct ZFW_CTRL *zfw_ctrl;
+ static volatile struct CH_CTRL *ch_ctrl;
+ static volatile struct BUF_CTRL *buf_ctrl;
+ int char_count;
+ volatile uclong tx_put, tx_get, tx_bufsize;
+
+ firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+ zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+ cy_readl(&firm_id->zfwctrl_addr));
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+ tx_get = cy_readl(&buf_ctrl->tx_get);
+ tx_put = cy_readl(&buf_ctrl->tx_put);
+ tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ if (tx_put >= tx_get)
+ char_count = tx_put - tx_get;
+ else
+ char_count = tx_put - tx_get + tx_bufsize;
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt + char_count); /* */
+#endif
+ return (info->xmit_cnt + char_count);
+ }
} /* cy_chars_in_buffer */
@@ -2819,7 +2949,8 @@ set_line_char(struct cyclades_port * info)
unsigned long flags;
unsigned char *base_addr;
int card,chip,channel,index;
- unsigned cflag;
+ unsigned cflag, iflag;
+ unsigned short chip_number;
int i;
@@ -2830,9 +2961,11 @@ set_line_char(struct cyclades_port * info)
return;
}
cflag = info->tty->termios->c_cflag;
+ iflag = info->tty->termios->c_iflag;
card = info->card;
channel = (info->line) - (cy_card[card].first_line);
+ chip_number = channel / 4;
if (!IS_CYC_Z(cy_card[card])) {
@@ -2844,17 +2977,16 @@ set_line_char(struct cyclades_port * info)
if (i & CBAUDEX) {
if (i == B57600)
i = 16;
+#ifdef B76800
+ else if(i == B76800)
+ i = 17;
+#endif
else if(i == B115200)
i = 18;
- else if(i == B230400 &&
- cy_readb(cy_card[card].base_addr+(CyGFRCR<<index)) >= 0x48) {
+ else if(i == B230400 && (info->chip_rev >= CD1400_REV_J)) {
/* It is a CD1400 rev. J or later */
i = 20;
}
-#ifdef B76800
- else if(i == B76800)
- i = 17;
-#endif
else
info->tty->termios->c_cflag &= ~CBAUDEX;
}
@@ -2868,6 +3000,10 @@ set_line_char(struct cyclades_port * info)
switch(info->baud) {
case 57600:
i += 1; break;
+#ifdef B76800
+ case 76800:
+ i += 2; break;
+#endif
case 115200:
i += 3; break;
case 230400:
@@ -2877,7 +3013,7 @@ set_line_char(struct cyclades_port * info)
}
}
}
- if(cy_readb(cy_card[card].base_addr+(CyGFRCR<<index)) >= 0x48) {
+ if(info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[i]; /* Tx BPR */
info->tco = baud_co_60[i]; /* Tx CO */
@@ -3116,6 +3252,16 @@ set_line_char(struct cyclades_port * info)
case B460800: cy_writel(&ch_ctrl->comm_baud , 460800); break;
}
+ if ((i = cy_readl(&ch_ctrl->comm_baud)) == 134) {
+ info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+ /* get it right for 134.5 baud */
+ } else if (i) {
+ info->timeout = (info->xmit_fifo_size*HZ*15/i) + 2;
+ /* this needs to be propagated into the card info */
+ } else {
+ info->timeout = 0;
+ }
+
/* byte size and parity */
switch(cflag & CSIZE){
case CS5: cy_writel(&ch_ctrl->comm_data_l , C_DL_CS5); break;
@@ -3151,7 +3297,7 @@ set_line_char(struct cyclades_port * info)
cy_readl(&ch_ctrl->hw_flow) & ~(C_RS_CTS | C_RS_RTS));
}
- retval = cyz_issue_cmd( &cy_card[card], channel, C_CM_IOCTL, 0L);
+ retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
if (retval != 0){
printk("cyc:set_line_char retval at %d was %x\n",
__LINE__, retval);
@@ -3164,6 +3310,14 @@ set_line_char(struct cyclades_port * info)
info->flags |= ASYNC_CHECK_CD;
}
+ if (iflag & IXON){
+ cy_writel(&ch_ctrl->sw_flow,
+ cy_readl(&ch_ctrl->sw_flow) | C_FL_OXX);
+ } else {
+ cy_writel(&ch_ctrl->sw_flow,
+ cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX);
+ }
+
if(i == 0){ /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
@@ -3183,7 +3337,6 @@ set_line_char(struct cyclades_port * info)
printk("cyc:set_line_char retval at %d was %x\n",
__LINE__, retval);
}
- cy_readl(&ch_ctrl->comm_baud);
if (info->tty){
clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -3231,8 +3384,9 @@ set_serial_info(struct cyclades_port * info,
if (!suser()) {
if ((new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
- (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
+ (new_serial.baud_base != info->baud) ||
+ ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
+ (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)))
return -EPERM;
info->flags = ((info->flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK));
@@ -3246,11 +3400,12 @@ set_serial_info(struct cyclades_port * info,
* At this point, we start making changes.....
*/
+ info->baud = new_serial.baud_base;
info->flags = ((info->flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS));
- info->baud = new_serial.baud_base;
- info->close_delay = new_serial.close_delay;
-
+ info->close_delay = new_serial.close_delay * HZ/100;
+ info->closing_wait = new_serial.closing_wait * HZ/100;
+
check_and_exit:
if (info->flags & ASYNC_INITIALIZED){
@@ -3807,25 +3962,44 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = set_default_timeout(info, (unsigned long)arg);
break;
case CYSETRFLOW:
- info->rflow = 1;
+ info->rflow = (int)arg;
ret_val = 0;
break;
- case CYRESETRFLOW:
- info->rflow = 0;
- ret_val = 0;
+ case CYGETRFLOW:
+ ret_val = info->rflow;
break;
case CYSETRTSDTR_INV:
- info->rtsdtr_inv = 1;
+ info->rtsdtr_inv = (int)arg;
ret_val = 0;
break;
- case CYRESETRTSDTR_INV:
- info->rtsdtr_inv = 0;
+ case CYGETRTSDTR_INV:
+ ret_val = info->rtsdtr_inv;
+ break;
+ case CYGETCARDINFO:
+ error = verify_area(VERIFY_WRITE, (void *) arg
+ ,sizeof(struct cyclades_card));
+ if (error){
+ ret_val = error;
+ break;
+ }
+ copy_to_user((void *)arg, (void *)&cy_card[info->card],
+ sizeof (struct cyclades_card));
ret_val = 0;
+ break;
+ case CYGETCD1400VER:
+ ret_val = info->chip_rev;
break;
case CYZPOLLCYCLE:
cyz_polling_cycle = (HZ * arg) / 1000;
ret_val = 0;
break;
+ case CYSETWAIT:
+ info->closing_wait2 = (unsigned short)arg;
+ ret_val = 0;
+ break;
+ case CYGETWAIT:
+ ret_val = info->closing_wait2;
+ break;
case TCSBRK: /* SVID version: non-zero arg --> no break */
ret_val = tty_check_change(tty);
if (ret_val)
@@ -3969,12 +4143,13 @@ cy_throttle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
- printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+
+ printk("cyc:throttle %s: %d....ttyC%d\n",
+ tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ if (serial_paranoia_check(info, tty->device, "cy_throttle")){
return;
}
@@ -4025,17 +4200,21 @@ cy_unthrottle(struct tty_struct * tty)
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
- printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+ printk("cyc:unthrottle %s: %d....ttyC%d\n",
+ tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->device, "cy_nthrottle")){
+ if (serial_paranoia_check(info, tty->device, "cy_unthrottle")){
return;
}
if (I_IXOFF(tty)) {
- info->x_char = START_CHAR(tty);
- /* Should use the "Send Special Character" feature!!! */
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ info->x_char = START_CHAR(tty);
+ /* Should use the "Send Special Character" feature!!! */
}
card = info->card;
@@ -4147,6 +4326,49 @@ cy_start(struct tty_struct *tty)
} /* cy_start */
+static void
+cy_flush_buffer(struct tty_struct *tty)
+{
+ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ int card, channel;
+ unsigned long flags;
+
+#ifdef SERIAL_DEBUG_IO
+ printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
+#endif
+
+ if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
+ return;
+ save_flags(flags); cli();
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ restore_flags(flags);
+
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+
+ if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
+ buffers as well */
+ static volatile struct FIRM_ID *firm_id;
+ static volatile struct ZFW_CTRL *zfw_ctrl;
+ static volatile struct CH_CTRL *ch_ctrl;
+ static volatile struct BUF_CTRL *buf_ctrl;
+
+ firm_id = (struct FIRM_ID *)(cy_card[card].base_addr + ID_ADDRESS);
+ zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr +
+ cy_readl(&firm_id->zfwctrl_addr));
+ ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
+ buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
+
+ while (cy_readl(&buf_ctrl->tx_get) != cy_readl(&buf_ctrl->tx_put))
+ cy_writel(&buf_ctrl->tx_put, cy_readl(&buf_ctrl->tx_get));
+ }
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+} /* cy_flush_buffer */
+
+
/*
* cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
@@ -4161,7 +4383,8 @@ cy_hangup(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "cy_hangup"))
return;
-
+
+ cy_flush_buffer(tty);
shutdown(info);
info->event = 0;
info->count = 0;
@@ -4174,28 +4397,6 @@ cy_hangup(struct tty_struct *tty)
} /* cy_hangup */
-static void
-cy_flush_buffer(struct tty_struct *tty)
-{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_IO
- printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
-#endif
-
- if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
- return;
- save_flags(flags); cli();
- info->xmit_cnt = info->xmit_head = info->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);
-} /* cy_flush_buffer */
-
-
/*
* ---------------------------------------------------------------------
* cy_init() and friends
@@ -4266,7 +4467,7 @@ cyy_init_card(volatile ucchar *true_base_addr,int index))
return chip_number;
}
cy_writeb((u_long)base_addr+(CyGCR<<index), CyCH0_SERIAL);
- if (cy_readb(base_addr+(CyGFRCR<<index)) >= 0x48){
+ if (cy_readb(base_addr+(CyGFRCR<<index)) >= CD1400_REV_J){
/* It is a CD1400 rev. J or later */
/* Impossible to reach 5ms with this chip.
Changed to 2ms instead (f = 500 Hz). */
@@ -4276,11 +4477,11 @@ cyy_init_card(volatile ucchar *true_base_addr,int index))
cy_writeb((u_long)base_addr+(CyPPR<<index), CyCLOCK_25_5MS);
}
- /*
+ /*
printk(" chip #%d at %#6lx is rev 0x%2x\n",
chip_number, (unsigned long)base_addr,
- base_addr[CyGFRCR<<index]);
- */
+ cy_readb(base_addr+(CyGFRCR<<index)));
+ */
}
return chip_number;
} /* cyy_init_card */
@@ -4309,7 +4510,7 @@ cy_detect_isa(void))
/* probe for CD1400... */
-#if !defined(__alpha__)
+#if !defined(__alpha__)
cy_isa_address = ioremap((unsigned int)cy_isa_address,
CyISA_Ywin);
#endif
@@ -4391,37 +4592,65 @@ __initfunc(static int
cy_detect_pci(void))
{
#ifdef CONFIG_PCI
+
+#ifdef NEW_PCI
+ struct pci_dev *pdev = NULL;
+ unsigned char cyy_rev_id;
+#else
unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
+#endif
unsigned long pci_intr_ctrl;
unsigned char cy_pci_irq;
uclong cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
unsigned short i,j,cy_pci_nchan;
- unsigned short device_id,dev_index = 0,board_index = 0;
+ unsigned short device_id,dev_index = 0;
+#ifndef NEW_PCI
+ unsigned short board_index = 0;
+#endif
uclong mailbox;
uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
+#ifdef NEW_PCI
+ if(pci_present() == 0) { /* PCI bus not present */
+#else
if(pcibios_present() == 0) { /* PCI bus not present */
+#endif
return(0);
}
for (i = 0; i < NR_CARDS; i++) {
/* look for a Cyclades card by vendor and device id */
while((device_id = cy_pci_dev_id[dev_index]) != 0) {
+#ifdef NEW_PCI
+ if((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES,
+ device_id, pdev)) == NULL) {
+ dev_index++; /* try next device id */
+ } else {
+ break; /* found a board */
+ }
+#else
if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
device_id,board_index,
- &cyy_bus, &cyy_dev_fn) != 0)
- {
+ &cyy_bus, &cyy_dev_fn) != 0) {
dev_index++; /* try next device id */
board_index = 0;
} else {
board_index++;
break; /* found a board */
}
+#endif
}
if (device_id == 0)
break;
/* read PCI configuration area */
+#ifdef NEW_PCI
+ cy_pci_irq = pdev->irq;
+ cy_pci_addr0 = pdev->base_address[0];
+ cy_pci_addr1 = pdev->base_address[1];
+ cy_pci_addr2 = pdev->base_address[2];
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+#else
pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
PCI_INTERRUPT_LINE, &cy_pci_irq);
pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
@@ -4435,24 +4664,33 @@ cy_detect_pci(void))
(unsigned int *) &cy_pci_addr2);
pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
PCI_REVISION_ID, &cyy_rev_id);
+#endif
if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
|| (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
#ifdef CY_PCI_DEBUG
printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
+#ifdef NEW_PCI
+ pdev->bus->number, pdev->devfn);
+#else
cyy_bus, cyy_dev_fn);
+#endif
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);
#endif
- cy_pci_addr1 &= 0xfffffffc;
- cy_pci_addr2 &= 0xfffffff0;
+ cy_pci_addr1 &= PCI_BASE_ADDRESS_IO_MASK;
+ cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
#if defined(__alpha__)
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- cyy_bus, cyy_dev_fn);
+#ifdef NEW_PCI
+ pdev->bus->number, pdev->devfn);
+#else
+ cyy_bus, cyy_dev_fn);
+#endif
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",
@@ -4537,7 +4775,11 @@ cy_detect_pci(void))
}else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
/* print message */
printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
+#ifdef NEW_PCI
+ pdev->bus->number, pdev->devfn);
+#else
cyy_bus, cyy_dev_fn);
+#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
@@ -4547,13 +4789,17 @@ cy_detect_pci(void))
}else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
#ifdef CY_PCI_DEBUG
printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- cyy_bus, cyy_dev_fn);
+#ifdef NEW_PCI
+ pdev->bus->number, pdev->devfn);
+#else
+ cyy_bus, cyy_dev_fn);
+#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
(ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
#endif
- cy_pci_addr0 &= 0xfffffff0;
+ cy_pci_addr0 &= PCI_BASE_ADDRESS_MEM_MASK;
#if !defined(__alpha__)
cy_pci_addr0 = (unsigned int) ioremap(
cy_pci_addr0 & PAGE_MASK,
@@ -4562,7 +4808,7 @@ cy_detect_pci(void))
#endif
mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *)
cy_pci_addr0)->mail_box_0);
- cy_pci_addr2 &= 0xfffffff0;
+ cy_pci_addr2 &= PCI_BASE_ADDRESS_MEM_MASK;
if (mailbox == ZE_V1) {
#if !defined(__alpha__)
cy_pci_addr2 = (unsigned int) ioremap(
@@ -4789,7 +5035,7 @@ show_version(void)
tmp = strchr(rcsvers, ' '); *tmp++ = '\0';
rcsdate = strchr(tmp, ' '); rcsdate++;
tmp = strrchr(rcsdate, ' '); *tmp = '\0';
- printk("Cyclom driver %s %s\n",
+ printk("Cyclades driver %s %s\n",
rcsvers, rcsdate);
printk(" built %s %s\n",
__DATE__, __TIME__);
@@ -4822,6 +5068,7 @@ cy_init(void))
int number_z_boards = 0;
int board,port,i,index;
unsigned long mailbox;
+ unsigned short chip_number;
int nports;
show_version();
@@ -4870,9 +5117,9 @@ cy_init(void))
cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
if (tty_register_driver(&cy_serial_driver))
- panic("Couldn't register Cyclom serial driver\n");
+ panic("Couldn't register Cyclades serial driver\n");
if (tty_register_driver(&cy_callout_driver))
- panic("Couldn't register Cyclom callout driver\n");
+ panic("Couldn't register Cyclades callout driver\n");
init_bh(CYCLADES_BH, do_cyclades_bh);
@@ -4934,9 +5181,13 @@ cy_init(void))
info->type = PORT_STARTECH;
info->card = board;
info->line = port;
+ info->chip_rev = 0;
info->flags = STD_COM_FLAGS;
info->tty = 0;
- info->xmit_fifo_size = 0;
+ if (mailbox == ZO_V1)
+ info->xmit_fifo_size = CYZ_FIFO_SIZE;
+ else
+ info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
info->cor1 = 0;
info->cor2 = 0;
info->cor3 = 0;
@@ -4946,7 +5197,9 @@ cy_init(void))
info->tco = 0;
info->rbpr = 0;
info->rco = 0;
- info->close_delay = 0;
+ info->close_delay = 5*HZ/10;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->closing_wait2 = 0;
info->x_char = 0;
info->event = 0;
info->count = 0;
@@ -4964,6 +5217,7 @@ cy_init(void))
cy_serial_driver.init_termios;
info->open_wait = 0;
info->close_wait = 0;
+ info->shutdown_wait = 0;
/* info->session */
/* info->pgrp */
info->read_status_mask = 0;
@@ -4988,14 +5242,19 @@ cy_init(void))
info->line = port;
info->flags = STD_COM_FLAGS;
info->tty = 0;
- info->xmit_fifo_size = 12;
+ info->xmit_fifo_size = CyMAX_CHAR_FIFO;
info->cor1 = CyPARITY_NONE|Cy_1_STOP|Cy_8_BITS;
info->cor2 = CyETC;
info->cor3 = 0x08; /* _very_ small rcv threshold */
info->cor4 = 0;
info->cor5 = 0;
- info->close_delay = 0;
- if (cy_readb(cinfo->base_addr+(CyGFRCR<<index)) >= 0x48) {
+ info->close_delay = 5*HZ/10;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->closing_wait2 = 0;
+ chip_number = (port - cinfo->first_line) / 4;
+ if ((info->chip_rev = cy_readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number]<<index) +
+ (CyGFRCR<<index))) >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[13]; /* Tx BPR */
info->tco = baud_co_60[13]; /* Tx CO */
@@ -5028,6 +5287,7 @@ cy_init(void))
cy_serial_driver.init_termios;
info->open_wait = 0;
info->close_wait = 0;
+ info->shutdown_wait = 0;
/* info->session */
/* info->pgrp */
info->read_status_mask =
@@ -5066,21 +5326,19 @@ cleanup_module(void)
int i;
unsigned long flags;
-
if (cyz_timeron){
cyz_timeron = 0;
del_timer(&cyz_timerlist);
}
- save_flags(flags);
- cli();
+ save_flags(flags); cli();
remove_bh(CYCLADES_BH);
free_page((unsigned long)tmp_buf);
if (tty_unregister_driver(&cy_callout_driver))
- printk("Couldn't unregister Cyclom callout driver\n");
+ printk("Couldn't unregister Cyclades callout driver\n");
if (tty_unregister_driver(&cy_serial_driver))
- printk("Couldn't unregister Cyclom serial driver\n");
+ printk("Couldn't unregister Cyclades serial driver\n");
restore_flags(flags);
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 0a6f0dd82..6fee9da6d 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -106,7 +106,6 @@ char kernel_version[]=UTS_RELEASE;
#ifdef ENABLE_PCI
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/digiPCI.h>
#endif /* ENABLE_PCI */
@@ -1747,7 +1746,7 @@ int pc_init(void)
--------------------------------------------------------------------- */
pci_boards_found = 0;
- if (pcibios_present())
+ if (pci_present())
{
if(num_cards < MAXBOARDS)
pci_boards_found += init_PCI(num_cards);
@@ -4039,31 +4038,23 @@ 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(char bus, 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)
{ /* Begin get_PCI_configuration */
- int error;
+ struct pci_dev *dev = pci_find_slot(bus, device_fn);
- error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
- base_addr0);
-
- error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1,
- base_addr1);
-
- error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2,
- base_addr2);
-
- error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_3,
- base_addr3);
-
- error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_4,
- base_addr4);
+ if (!dev)
+ return(0);
- error |= pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_5,
- base_addr5);
+ *base_addr0 = dev->base_address[0];
+ *base_addr1 = dev->base_address[1];
+ *base_addr2 = dev->base_address[2];
+ *base_addr3 = dev->base_address[3];
+ *base_addr4 = dev->base_address[4];
+ *base_addr5 = dev->base_address[5];
/* ------------------------------------------------------------------------
NOTE - The code below mask out either the 2 or 4 bits dependent on the
@@ -4103,11 +4094,6 @@ int get_PCI_configuration(char bus, char device_fn,
else
(*base_addr5) &= PCI_BASE_ADDRESS_MEM_MASK;
- if (error)
- {
- printk(KERN_ERR "<Error> - DIGI PCI error: board not initializing due to error\n");
- return(0);
- }
return(1);
} /* End get_PCI_configuration */
@@ -4311,5 +4297,3 @@ int init_PCI(int boards_found)
} /* End init_PCI */
#endif /* ENABLE_PCI */
-
-
diff --git a/drivers/char/hfmodem/gentbl.c b/drivers/char/hfmodem/gentbl.c
index c99b963d8..d60651b1b 100644
--- a/drivers/char/hfmodem/gentbl.c
+++ b/drivers/char/hfmodem/gentbl.c
@@ -62,7 +62,7 @@ int main(int argc, char *argv[])
printf("/*\n * This file is automatically generated by %s, DO NOT EDIT!\n*/\n\n",
argv[0]);
gensintbl();
- return(0);
+ exit(0);
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/char/i2c.c b/drivers/char/i2c.c
new file mode 100644
index 000000000..5507d94ba
--- /dev/null
+++ b/drivers/char/i2c.c
@@ -0,0 +1,430 @@
+/*
+ * Generic i2c interface for linux
+ *
+ * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/locks.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+
+#define REGPRINT(x) if (verbose) (x)
+#define I2C_DEBUG(x) if (i2c_debug) (x)
+
+static int scan = 0;
+static int verbose = 1;
+static int i2c_debug = 0;
+
+MODULE_PARM(scan,"i");
+MODULE_PARM(verbose,"i");
+MODULE_PARM(i2c_debug,"i");
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_bus *busses[I2C_BUS_MAX];
+static struct i2c_driver *drivers[I2C_DRIVER_MAX];
+static int bus_count = 0, driver_count = 0;
+
+int i2c_init(void)
+{
+ printk(KERN_INFO "i2c: initialized%s\n",
+ scan ? " (i2c bus scan enabled)" : "");
+ /* anything to do here ? */
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+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;
+
+ /* probe for device */
+ LOCK_I2C_BUS(bus);
+ for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2)
+ {
+ i2c_start(bus);
+ ack = i2c_sendbyte(bus,addr,0);
+ i2c_stop(bus);
+ if (!ack)
+ break;
+ }
+ UNLOCK_I2C_BUS(bus);
+ if (ack)
+ return;
+
+ /* got answer */
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (NULL == driver->devices[i])
+ break;
+ if (I2C_DEVICE_MAX == i)
+ return;
+
+ for (j = 0; j < I2C_DEVICE_MAX; j++)
+ if (NULL == bus->devices[j])
+ break;
+ if (I2C_DEVICE_MAX == j)
+ return;
+
+ if (NULL == (device = kmalloc(sizeof(struct i2c_device),GFP_KERNEL)))
+ return;
+ device->bus = bus;
+ device->driver = driver;
+ device->addr = addr;
+
+ /* Attach */
+
+ if (driver->attach(device)!=0)
+ {
+ kfree(device);
+ return;
+ }
+ driver->devices[i] = device;
+ driver->devcount++;
+ bus->devices[j] = device;
+ bus->devcount++;
+
+ if (bus->attach_inform)
+ bus->attach_inform(bus,driver->id);
+ REGPRINT(printk("i2c: device attached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,addr,bus->name,driver->name));
+}
+
+static void i2c_detach_device(struct i2c_device *device)
+{
+ int i;
+
+ if (device->bus->detach_inform)
+ device->bus->detach_inform(device->bus,device->driver->id);
+ device->driver->detach(device);
+
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (device == device->driver->devices[i])
+ break;
+ if (I2C_DEVICE_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n",
+ device->name);
+ return;
+ }
+ device->driver->devices[i] = NULL;
+ device->driver->devcount--;
+
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (device == device->bus->devices[i])
+ break;
+ if (I2C_DEVICE_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n",
+ device->name);
+ return;
+ }
+ device->bus->devices[i] = NULL;
+ device->bus->devcount--;
+
+ REGPRINT(printk("i2c: device detached: %s (addr=0x%02x, bus=%s, driver=%s)\n",device->name,device->addr,device->bus->name,device->driver->name));
+ kfree(device);
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_register_bus(struct i2c_bus *bus)
+{
+ unsigned long flags;
+ int i,ack;
+
+ memset(bus->devices,0,sizeof(bus->devices));
+ bus->devcount = 0;
+
+ for (i = 0; i < I2C_BUS_MAX; i++)
+ if (NULL == busses[i])
+ break;
+ if (I2C_BUS_MAX == i)
+ return -ENOMEM;
+
+ busses[i] = bus;
+ bus_count++;
+ REGPRINT(printk("i2c: bus registered: %s\n",bus->name));
+
+ MOD_INC_USE_COUNT;
+
+ if (scan)
+ {
+ /* scan whole i2c bus */
+ LOCK_I2C_BUS(bus);
+ for (i = 0; i < 256; i+=2)
+ {
+ i2c_start(bus);
+ ack = i2c_sendbyte(bus,i,0);
+ i2c_stop(bus);
+ if (!ack)
+ {
+ printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n",
+ bus->name,i);
+ }
+ }
+ UNLOCK_I2C_BUS(bus);
+ }
+
+ /* probe available drivers */
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (drivers[i])
+ i2c_attach_device(bus,drivers[i]);
+ return 0;
+}
+
+int i2c_unregister_bus(struct i2c_bus *bus)
+{
+ int i;
+
+ /* detach devices */
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (bus->devices[i])
+ i2c_detach_device(bus->devices[i]);
+
+ for (i = 0; i < I2C_BUS_MAX; i++)
+ if (bus == busses[i])
+ break;
+ if (I2C_BUS_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n",
+ bus->name);
+ return -ENODEV;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ busses[i] = NULL;
+ bus_count--;
+ REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name));
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_register_driver(struct i2c_driver *driver)
+{
+ int i;
+
+ memset(driver->devices,0,sizeof(driver->devices));
+ driver->devcount = 0;
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (NULL == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i)
+ return -ENOMEM;
+
+ drivers[i] = driver;
+ driver_count++;
+
+ MOD_INC_USE_COUNT;
+
+ REGPRINT(printk("i2c: driver registered: %s\n",driver->name));
+
+ /* Probe available busses */
+ for (i = 0; i < I2C_BUS_MAX; i++)
+ if (busses[i])
+ i2c_attach_device(busses[i],driver);
+
+ return 0;
+}
+
+int i2c_unregister_driver(struct i2c_driver *driver)
+{
+ int i;
+
+ /* detach devices */
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (driver->devices[i])
+ i2c_detach_device(driver->devices[i]);
+
+ for (i = 0; i < I2C_DRIVER_MAX; i++)
+ if (driver == drivers[i])
+ break;
+ if (I2C_DRIVER_MAX == i)
+ {
+ printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n",
+ driver->name);
+ return -ENODEV;
+ }
+
+ MOD_DEC_USE_COUNT;
+
+ drivers[i] = NULL;
+ driver_count--;
+ REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name));
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_control_device(struct i2c_bus *bus, int id,
+ unsigned int cmd, void *arg)
+{
+ int i;
+
+ for (i = 0; i < I2C_DEVICE_MAX; i++)
+ if (bus->devices[i] && bus->devices[i]->driver->id == id)
+ break;
+ if (i == I2C_DEVICE_MAX)
+ return -ENODEV;
+ if (NULL == bus->devices[i]->driver->command)
+ return -ENODEV;
+ return bus->devices[i]->driver->command(bus->devices[i],cmd,arg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+#define I2C_SET(bus,ctrl,data) (bus->i2c_setlines(bus,ctrl,data))
+#define I2C_GET(bus) (bus->i2c_getdataline(bus))
+
+void i2c_start(struct i2c_bus *bus)
+{
+ I2C_SET(bus,0,1);
+ I2C_SET(bus,1,1);
+ I2C_SET(bus,1,0);
+ I2C_SET(bus,0,0);
+ I2C_DEBUG(printk("%s: < ",bus->name));
+}
+
+void i2c_stop(struct i2c_bus *bus)
+{
+ I2C_SET(bus,0,0);
+ I2C_SET(bus,1,0);
+ I2C_SET(bus,1,1);
+ I2C_DEBUG(printk(">\n"));
+}
+
+void i2c_one(struct i2c_bus *bus)
+{
+ I2C_SET(bus,0,1);
+ I2C_SET(bus,1,1);
+ I2C_SET(bus,0,1);
+}
+
+void i2c_zero(struct i2c_bus *bus)
+{
+ I2C_SET(bus,0,0);
+ I2C_SET(bus,1,0);
+ I2C_SET(bus,0,0);
+}
+
+int i2c_ack(struct i2c_bus *bus)
+{
+ int ack;
+
+ I2C_SET(bus,0,1);
+ I2C_SET(bus,1,1);
+ ack = I2C_GET(bus);
+ I2C_SET(bus,0,1);
+ return ack;
+}
+
+int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack)
+{
+ int i, ack;
+
+ I2C_SET(bus,0,0);
+ for (i=7; i>=0; i--)
+ (data&(1<<i)) ? i2c_one(bus) : i2c_zero(bus);
+ if (wait_for_ack)
+ udelay(wait_for_ack);
+ ack=i2c_ack(bus);
+ I2C_DEBUG(printk("%02x%c ",(int)data,ack?'-':'+'));
+ return ack;
+}
+
+unsigned char i2c_readbyte(struct i2c_bus *bus,int last)
+{
+ int i;
+ unsigned char data=0;
+
+ I2C_SET(bus,0,1);
+ for (i=7; i>=0; i--)
+ {
+ I2C_SET(bus,1,1);
+ if (I2C_GET(bus))
+ data |= (1<<i);
+ I2C_SET(bus,0,1);
+ }
+ last ? i2c_one(bus) : i2c_zero(bus);
+ I2C_DEBUG(printk("=%02x%c ",(int)data,last?'-':'+'));
+ return data;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int i2c_read(struct i2c_bus *bus, unsigned char addr)
+{
+ int ret;
+
+ if (bus->i2c_read)
+ return bus->i2c_read(bus, addr);
+
+ i2c_start(bus);
+ i2c_sendbyte(bus,addr,0);
+ ret = i2c_readbyte(bus,1);
+ i2c_stop(bus);
+ return ret;
+}
+
+int i2c_write(struct i2c_bus *bus, unsigned char addr,
+ unsigned char data1, unsigned char data2, int both)
+{
+ int ack;
+
+ if (bus->i2c_write)
+ return bus->i2c_write(bus, addr, data1, data2, both);
+
+ i2c_start(bus);
+ i2c_sendbyte(bus,addr,0);
+ ack = i2c_sendbyte(bus,data1,0);
+ if (both)
+ ack = i2c_sendbyte(bus,data2,0);
+ i2c_stop(bus);
+ return ack ? -1 : 0 ;
+}
+
+/* ----------------------------------------------------------------------- */
+
+#ifdef MODULE
+
+EXPORT_SYMBOL(i2c_register_bus);
+EXPORT_SYMBOL(i2c_unregister_bus);
+EXPORT_SYMBOL(i2c_register_driver);
+EXPORT_SYMBOL(i2c_unregister_driver);
+EXPORT_SYMBOL(i2c_control_device);
+EXPORT_SYMBOL(i2c_start);
+EXPORT_SYMBOL(i2c_stop);
+EXPORT_SYMBOL(i2c_one);
+EXPORT_SYMBOL(i2c_zero);
+EXPORT_SYMBOL(i2c_ack);
+EXPORT_SYMBOL(i2c_sendbyte);
+EXPORT_SYMBOL(i2c_readbyte);
+EXPORT_SYMBOL(i2c_read);
+EXPORT_SYMBOL(i2c_write);
+
+
+int init_module(void)
+{
+ return i2c_init();
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff --git a/drivers/char/i2c.h b/drivers/char/i2c.h
new file mode 100644
index 000000000..66aef224c
--- /dev/null
+++ b/drivers/char/i2c.h
@@ -0,0 +1,166 @@
+#ifndef I2C_H
+#define I2C_H
+
+/*
+ * linux i2c interface. Works a little bit like the scsi subsystem.
+ * There are:
+ *
+ * i2c the basic control module (like scsi_mod)
+ * bus driver a driver with a i2c bus (hostadapter driver)
+ * chip driver a driver for a chip connected
+ * to a i2c bus (cdrom/hd driver)
+ *
+ * A device will be attached to one bus and one chip driver. Every chip
+ * driver gets a unique ID.
+ *
+ * A chip driver can provide a ioctl-like callback for the
+ * communication with other parts of the kernel (not every i2c chip is
+ * useful without other devices, a TV card tuner for example).
+ *
+ * "i2c internal" parts of the structs: only the i2c module is allowed to
+ * write to them, for others they are read-only.
+ *
+ */
+
+#define I2C_BUS_MAX 4 /* max # of bus drivers */
+#define I2C_DRIVER_MAX 8 /* max # of chip drivers */
+#define I2C_DEVICE_MAX 8 /* max # if devices per bus/driver */
+
+struct i2c_bus;
+struct i2c_driver;
+struct i2c_device;
+
+#define I2C_DRIVERID_MSP3400 1
+#define I2C_DRIVERID_TUNER 2
+#define I2C_DRIVERID_VIDEOTEXT 3
+
+#define I2C_BUSID_BT848 1 /* I2C bus on a BT848 */
+
+/*
+ * struct for a driver for a i2c chip (tuner, soundprocessor,
+ * videotext, ... ).
+ *
+ * a driver will register within the i2c module. The i2c module will
+ * callback the driver (i2c_attach) for every device it finds on a i2c
+ * bus at the specified address. If the driver decides to "accept"
+ * the, device, it must return a struct i2c_device, and NULL
+ * otherwise.
+ *
+ * i2c_detach = i2c_attach ** -1
+ *
+ * i2c_command will be used to pass commands to the driver in a
+ * ioctl-line manner.
+ *
+ */
+
+struct i2c_driver
+{
+ char name[32]; /* some useful label */
+ int id; /* device type ID */
+ unsigned char addr_l, addr_h; /* address range of the chip */
+
+ int (*attach)(struct i2c_device *device);
+ int (*detach)(struct i2c_device *device);
+ int (*command)(struct i2c_device *device,unsigned int cmd, void *arg);
+
+ /* i2c internal */
+ struct i2c_device *devices[I2C_DEVICE_MAX];
+ int devcount;
+};
+
+
+/*
+ * this holds the informations about a i2c bus available in the system.
+ *
+ * a chip with a i2c bus interface (like bt848) registers the bus within
+ * the i2c module. This struct provides functions to access the i2c bus.
+ *
+ * One must hold the spinlock to access the i2c bus (XXX: is the irqsave
+ * required? Maybe better use a semaphore?).
+ * [-AC-] having a spinlock_irqsave is only needed if we have drivers wishing
+ * to bang their i2c bus from an interrupt.
+ *
+ * attach/detach_inform is a callback to inform the bus driver about
+ * attached chip drivers.
+ *
+ */
+
+/* needed: unsigned long flags */
+
+#define LOCK_I2C_BUS(bus) spin_lock_irqsave(&(bus->bus_lock),flags);
+#define UNLOCK_I2C_BUS(bus) spin_unlock_irqrestore(&(bus->bus_lock),flags);
+
+struct i2c_bus
+{
+ char name[32]; /* some useful label */
+ int id;
+ void *data; /* free for use by the bus driver */
+
+ spinlock_t bus_lock;
+
+ /* attach/detach inform callbacks */
+ void (*attach_inform)(struct i2c_bus *bus, int id);
+ void (*detach_inform)(struct i2c_bus *bus, int id);
+
+ /* Software I2C */
+ void (*i2c_setlines)(struct i2c_bus *bus, int ctrl, int data);
+ int (*i2c_getdataline)(struct i2c_bus *bus);
+
+ /* Hardware I2C */
+ int (*i2c_read)(struct i2c_bus *bus, unsigned char addr);
+ int (*i2c_write)(struct i2c_bus *bus, unsigned char addr,
+ unsigned char b1, unsigned char b2, int both);
+
+ /* internal data for i2c module */
+ struct i2c_device *devices[I2C_DEVICE_MAX];
+ int devcount;
+};
+
+
+/*
+ * This holds per-device data for a i2c device
+ */
+
+struct i2c_device
+{
+ char name[32]; /* some useful label */
+ void *data; /* free for use by the chip driver */
+ unsigned char addr; /* chip addr */
+
+ /* i2c internal */
+ struct i2c_bus *bus;
+ struct i2c_driver *driver;
+};
+
+
+/* ------------------------------------------------------------------- */
+/* i2c module functions */
+
+/* register/unregister a i2c bus */
+int i2c_register_bus(struct i2c_bus *bus);
+int i2c_unregister_bus(struct i2c_bus *bus);
+
+/* register/unregister a chip driver */
+int i2c_register_driver(struct i2c_driver *driver);
+int i2c_unregister_driver(struct i2c_driver *driver);
+
+/* send a command to a chip using the ioctl-like callback interface */
+int i2c_control_device(struct i2c_bus *bus, int id,
+ unsigned int cmd, void *arg);
+
+/* i2c bus access functions */
+void i2c_start(struct i2c_bus *bus);
+void i2c_stop(struct i2c_bus *bus);
+void i2c_one(struct i2c_bus *bus);
+void i2c_zero(struct i2c_bus *bus);
+int i2c_ack(struct i2c_bus *bus);
+
+int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack);
+unsigned char i2c_readbyte(struct i2c_bus *bus,int last);
+
+/* i2c (maybe) hardware functions */
+int i2c_read(struct i2c_bus *bus, unsigned char addr);
+int i2c_write(struct i2c_bus *bus, unsigned char addr,
+ unsigned char b1, unsigned char b2, int both);
+
+#endif /* I2C_H */
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 8c024bba5..2e2ffc341 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -14,24 +14,25 @@
* carsten@sol.wohnheim.uni-ulm.de
* Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
* parport_sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * Fixed kernel_(to/from)_user memory copy to check for errors
+ * by Riccardo Facchetti <fizban@tin.it>
*/
/* This driver should, in theory, work with any parallel port that has an
* appropriate low-level driver; all I/O is done through the parport
- * abstraction layer. There is a performance penalty for this, but parallel
- * ports are comparitively low-speed devices anyway.
+ * abstraction layer.
*
* If this driver is built into the kernel, you can configure it using the
* kernel command-line. For example:
*
- * lp=parport1,none,parport2 (bind lp0 to parport1, disable lp1 and
+ * lp=parport1,none,parport2 (bind lp0 to parport1, disable lp1 and
* bind lp2 to parport2)
*
* lp=auto (assign lp devices to all ports that
* have printers attached, as determined
* by the IEEE-1284 autoprobe)
*
- * lp=reset (reset the printer during
+ * lp=reset (reset the printer during
* initialisation)
*
* lp=off (disable the printer driver entirely)
@@ -39,13 +40,11 @@
* If the driver is loaded as a module, similar functionality is available
* using module parameters. The equivalent of the above commands would be:
*
- * # insmod lp.o parport=1,-1,2 (use -1 for disabled ports, since
- * module parameters do not allow you
- * to mix textual and numeric values)
+ * # insmod lp.o parport=1,none,2
*
- * # insmod lp.o autoprobe=1
+ * # insmod lp.o parport=auto
*
- * # insmod lp.0 reset=1
+ * # insmod lp.o reset=1
*/
/* COMPATIBILITY WITH OLD KERNELS
@@ -163,14 +162,22 @@ static inline int lp_char(char lpchar, int minor)
unsigned long count = 0;
struct lp_stats *stats;
- do {
- status = r_str (minor);
- count++;
+ for (;;) {
lp_yield(minor);
- } while (!LP_READY(minor, status) && count < LP_CHAR(minor));
-
- if (count == LP_CHAR(minor))
- return 0;
+ status = r_str (minor);
+ if (++count == LP_CHAR(minor))
+ return 0;
+ if (LP_POLLING(minor))
+ {
+ if (LP_READY(minor, status))
+ break;
+ } else {
+ if (!LP_READY(minor, status))
+ return 0;
+ else
+ break;
+ }
+ }
w_dtr(minor, lpchar);
stats = &LP_STAT(minor);
@@ -229,23 +236,32 @@ static void lp_error(int minor)
}
static int lp_check_status(int minor) {
+ static unsigned char last = 0;
unsigned char status = r_str(minor);
if ((status & LP_POUTPA)) {
- printk(KERN_INFO "lp%d out of paper\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return 1;
- lp_error(minor);
+ if (last != LP_POUTPA) {
+ last = LP_POUTPA;
+ printk(KERN_INFO "lp%d out of paper\n", minor);
+ }
} else if (!(status & LP_PSELECD)) {
- printk(KERN_INFO "lp%d off-line\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return 1;
- lp_error(minor);
+ if (last != LP_PSELECD) {
+ last = LP_PSELECD;
+ printk(KERN_INFO "lp%d off-line\n", minor);
+ }
} else if (!(status & LP_PERRORP)) {
- printk(KERN_ERR "lp%d printer error\n", minor);
+ if (last != LP_PERRORP) {
+ last = LP_PERRORP;
+ printk(KERN_ERR "lp%d on fire!\n", minor);
+ }
+ }
+ else last = 0;
+
+ if (last != 0) {
if (LP_F(minor) & LP_ABORT)
return 1;
lp_error(minor);
}
+
return 0;
}
@@ -265,7 +281,9 @@ static inline int lp_write_buf(unsigned int minor, const char *buf, int count)
do {
bytes_written = 0;
copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
- copy_from_user(lp->lp_buffer, buf, copy_size);
+
+ if (copy_from_user(lp->lp_buffer, buf, copy_size))
+ return -EFAULT;
while (copy_size) {
if (lp_char(lp->lp_buffer[bytes_written], minor)) {
@@ -451,15 +469,19 @@ static ssize_t lp_read(struct file * file, char * buf,
current->timeout=jiffies + LP_TIME(minor);
schedule ();
}
+
counter=0;
+
if (( i & 1) != 0) {
Byte= (Byte | z<<4);
- put_user(Byte, temp);
+ if (put_user(Byte, (char *)temp))
+ return -EFAULT;
temp++;
} else Byte=z;
}
+
lp_select_in_high(minor);
- parport_release(lp_table[minor].dev);
+ lp_parport_release(minor);
return temp-buf;
}
@@ -530,6 +552,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned int minor = MINOR(inode->i_rdev);
+ int status;
int retval = 0;
#ifdef LP_DEBUG
@@ -571,48 +594,33 @@ static int lp_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
break;
case LPGETIRQ:
- retval = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(int));
- if (retval)
- return retval;
- copy_to_user((int *) arg, &LP_IRQ(minor), sizeof(int));
+ if (copy_to_user((int *) arg, &LP_IRQ(minor),
+ sizeof(int)))
+ return -EFAULT;
break;
case LPGETSTATUS:
- retval = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(int));
- if (retval)
- return retval;
- else {
- int status;
- lp_parport_claim (minor);
- status = r_str(minor);
- lp_parport_release (minor);
- copy_to_user((int *) arg, &status, sizeof(int));
- }
+ lp_parport_claim(minor);
+ status = r_str(minor);
+ lp_parport_release(minor);
+
+ if (copy_to_user((int *) arg, &status, sizeof(int)))
+ return -EFAULT;
break;
case LPRESET:
lp_reset(minor);
break;
case LPGETSTATS:
- retval = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct lp_stats));
- if (retval)
- return retval;
- else {
- copy_to_user((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats));
- if (suser())
- memset(&LP_STAT(minor), 0, sizeof(struct lp_stats));
- }
+ if (copy_to_user((int *) arg, &LP_STAT(minor),
+ sizeof(struct lp_stats)))
+ return -EFAULT;
+ if (suser())
+ memset(&LP_STAT(minor), 0,
+ sizeof(struct lp_stats));
break;
case LPGETFLAGS:
- retval = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(int));
- if (retval)
- return retval;
- else {
- int status = LP_F(minor);
- copy_to_user((int *) arg, &status, sizeof(int));
- }
+ status = LP_F(minor);
+ if (copy_to_user((int *) arg, &status, sizeof(int)))
+ return -EFAULT;
break;
default:
retval = -EINVAL;
@@ -641,17 +649,16 @@ static struct file_operations lp_fops = {
#ifdef MODULE
-static int parport[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static char *parport[LP_NO] = { NULL, };
static int reset = 0;
-static int autoprobe = 0;
-MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "i");
+MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "s");
MODULE_PARM(reset, "i");
-MODULE_PARM(autoprobe, "i");
#else
-static int parport[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
+static int parport_nr[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
static int reset __initdata = 0;
static int parport_ptr = 0;
@@ -661,21 +668,21 @@ __initfunc(void lp_setup(char *str, int *ints))
if (!str) {
if (ints[0] == 0 || ints[1] == 0) {
/* disable driver on "lp=" or "lp=0" */
- parport[0] = LP_PARPORT_OFF;
+ parport_nr[0] = LP_PARPORT_OFF;
} else {
printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
}
} else if (!strncmp(str, "parport", 7)) {
int n = simple_strtoul(str+7, NULL, 10);
if (parport_ptr < LP_NO)
- parport[parport_ptr++] = n;
+ parport_nr[parport_ptr++] = n;
else
printk(KERN_INFO "lp: too many ports, %s ignored.\n",
str);
} else if (!strcmp(str, "auto")) {
- parport[0] = LP_PARPORT_AUTO;
+ parport_nr[0] = LP_PARPORT_AUTO;
} else if (!strcmp(str, "none")) {
- parport[parport_ptr++] = LP_PARPORT_NONE;
+ parport_nr[parport_ptr++] = LP_PARPORT_NONE;
} else if (!strcmp(str, "reset")) {
reset = 1;
}
@@ -709,7 +716,7 @@ int lp_init(void)
unsigned int i;
struct parport *port;
- switch (parport[0])
+ switch (parport_nr[0])
{
case LP_PARPORT_OFF:
return 0;
@@ -718,7 +725,7 @@ int lp_init(void)
case LP_PARPORT_AUTO:
for (port = parport_enumerate(); port; port = port->next) {
- if (parport[0] == LP_PARPORT_AUTO &&
+ if (parport_nr[0] == LP_PARPORT_AUTO &&
port->probe_info.class != PARPORT_CLASS_PRINTER)
continue;
@@ -728,12 +735,11 @@ int lp_init(void)
}
break;
- case LP_PARPORT_NONE:
default:
for (i = 0; i < LP_NO; i++) {
- if (parport[i] >= 0) {
+ if (parport_nr[i] >= 0) {
char buffer[16];
- sprintf(buffer, "parport%d", parport[i]);
+ sprintf(buffer, "parport%d", parport_nr[i]);
for (port = parport_enumerate(); port;
port = port->next) {
if (!strcmp(port->name, buffer)) {
@@ -762,8 +768,28 @@ int lp_init(void)
#ifdef MODULE
int init_module(void)
{
- if (autoprobe)
- parport[0] = LP_PARPORT_AUTO;
+ if (parport[0]) {
+ /* The user gave some parameters. Let's see what they were. */
+ if (!strncmp(parport[0], "auto", 4))
+ parport_nr[0] = LP_PARPORT_AUTO;
+ else {
+ int n;
+ for (n = 0; n < LP_NO && parport[n]; n++) {
+ if (!strncmp(parport[n], "none", 4))
+ parport_nr[n] = LP_PARPORT_NONE;
+ else {
+ char *ep;
+ unsigned long r = simple_strtoul(parport[n], &ep, 0);
+ if (ep != parport[n])
+ parport_nr[n] = r;
+ else {
+ printk(KERN_ERR "lp: bad port specifier `%s'\n", parport[n]);
+ return -ENODEV;
+ }
+ }
+ }
+ }
+ }
return lp_init();
}
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 1ca4412af..3ddffff0b 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -385,9 +385,6 @@ static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
default:
return -EINVAL;
}
- if (file->f_pos < 0)
- return 0;
- return file->f_pos;
}
#define mmap_kmem mmap_mem
@@ -547,7 +544,7 @@ __initfunc(int chr_dev_init(void))
#ifdef CONFIG_JOYSTICK
/*
* Some joysticks only appear when the soundcard they are
- * connected too is confgured. Keep the sound/joystick ordering.
+ * connected to is configured. Keep the sound/joystick ordering.
*/
js_init();
#endif
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
new file mode 100644
index 000000000..0d5f02638
--- /dev/null
+++ b/drivers/char/msp3400.c
@@ -0,0 +1,923 @@
+/*
+ * programming the msp34* sound processor family
+ *
+ * (c) 1997,1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ *
+ * what works and what doesn't:
+ *
+ * AM-Mono
+ * probably doesn't (untested)
+ *
+ * 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)
+ * should work, with autodetect
+ *
+ * FM-Stereo (satellite)
+ * should work, no autodetect (i.e. default is mono, but you can
+ * switch to stereo -- untested)
+ *
+ * NICAM (B/G, used in UK, Scandinavia and Spain)
+ * should work, with autodetect. Support for NICAM was added by
+ * Pekka Pietikainen <pp@netppl.fi>
+ *
+ *
+ * TODO:
+ * - better SAT support
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+/* #include <asm/smp_lock.h> */
+
+/* kernel_thread */
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+#include "i2c.h"
+#include <linux/videodev.h>
+
+#include "msp3400.h"
+
+int debug = 0; /* insmod parameter */
+
+struct msp3400c
+{
+ struct i2c_bus *bus;
+
+ int nicam;
+ int mode;
+ int norm;
+ int volume;
+ int stereo;
+
+ /* thread */
+ struct task_struct *thread;
+ struct semaphore *wait;
+ struct semaphore *notify;
+ int active,restart,rmmod;
+};
+
+#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */
+
+/* ---------------------------------------------------------------------- */
+
+#define dprintk if (debug) printk
+
+MODULE_PARM(debug,"i");
+
+/* ---------------------------------------------------------------------- */
+
+#define I2C_MSP3400C 0x80
+#define I2C_MSP3400C_DEM 0x10
+#define I2C_MSP3400C_DFP 0x12
+
+/* ----------------------------------------------------------------------- */
+/* functions for talking to the MSP3400C Sound processor */
+
+static int msp3400c_reset(struct i2c_bus *bus)
+{
+ int ret = 0;
+
+ udelay(2000);
+ i2c_start(bus);
+ i2c_sendbyte(bus, I2C_MSP3400C,2000);
+ i2c_sendbyte(bus, 0x00,0);
+ i2c_sendbyte(bus, 0x80,0);
+ i2c_sendbyte(bus, 0x00,0);
+ i2c_stop(bus);
+ udelay(2000);
+ i2c_start(bus);
+ if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
+ 0 != i2c_sendbyte(bus, 0x00,0) ||
+ 0 != i2c_sendbyte(bus, 0x00,0) ||
+ 0 != i2c_sendbyte(bus, 0x00,0))
+ {
+ ret = -1;
+ printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n");
+ }
+ i2c_stop(bus);
+ udelay(2000);
+ return ret;
+}
+
+static int msp3400c_read(struct i2c_bus *bus, int dev, int addr)
+{
+ int ret=0;
+ short val = 0;
+ i2c_start(bus);
+ if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
+ 0 != i2c_sendbyte(bus, dev+1, 0) ||
+ 0 != i2c_sendbyte(bus, addr >> 8, 0) ||
+ 0 != i2c_sendbyte(bus, addr & 0xff, 0))
+ {
+ ret = -1;
+ }
+ else
+ {
+ i2c_start(bus);
+ if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000))
+ {
+ ret = -1;
+ }
+ else
+ {
+ val |= (int)i2c_readbyte(bus,0) << 8;
+ val |= (int)i2c_readbyte(bus,1);
+ }
+ }
+ i2c_stop(bus);
+ if (-1 == ret)
+ {
+ printk(KERN_WARNING "msp3400: I/O error, trying reset (read %s 0x%x)\n",
+ (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
+ msp3400c_reset(bus);
+ }
+ return val;
+}
+
+static int msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val)
+{
+ int ret = 0;
+
+ i2c_start(bus);
+ if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
+ 0 != i2c_sendbyte(bus, dev, 0) ||
+ 0 != i2c_sendbyte(bus, addr >> 8, 0) ||
+ 0 != i2c_sendbyte(bus, addr & 0xff, 0) ||
+ 0 != i2c_sendbyte(bus, val >> 8, 0) ||
+ 0 != i2c_sendbyte(bus, val & 0xff, 0))
+ {
+ ret = -1;
+ }
+ i2c_stop(bus);
+ if (-1 == ret)
+ {
+ printk(KERN_ERR "msp3400: I/O error, trying reset (write %s 0x%x)\n",
+ (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
+ msp3400c_reset(bus);
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* This macro is allowed for *constants* only, gcc must calculate it
+ at compile time. Remember -- no floats in kernel mode */
+#define MSP_CARRIER(freq) ((int)((float)(freq/18.432)*(1<<24)))
+
+#define MSP_MODE_AM_DETECT 0
+#define MSP_MODE_FM_RADIO 2
+#define MSP_MODE_FM_TERRA 3
+#define MSP_MODE_FM_SAT 4
+#define MSP_MODE_FM_NICAM1 5
+#define MSP_MODE_FM_NICAM2 6
+
+static struct MSP_INIT_DATA_DEM
+{
+ int fir1[6];
+ int fir2[6];
+ int cdo1;
+ int cdo2;
+ int ad_cv;
+ int mode_reg;
+ int dfp_src;
+ int dfp_matrix;
+} msp_init_data[] = {
+ /* AM (for carrier detect / msp3400) */
+ { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0500, 0x0020, 0x3000},
+
+ /* AM (for carrier detect / msp3410) */
+ { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0100, 0x0020, 0x3000},
+
+ /* 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 },
+
+ /* Terrestial FM-mono */
+ { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0480, 0x0030, 0x3000},
+
+ /* Sat FM-mono */
+ { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000},
+
+ /* NICAM B/G, D/K */
+ { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000},
+
+ /* NICAM I */
+ { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000},
+};
+
+struct CARRIER_DETECT
+{
+ int cdo;
+ char *name;
+};
+
+static struct CARRIER_DETECT carrier_detect_main[] =
+{
+ /* main carrier */
+ { 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" }
+};
+
+static struct CARRIER_DETECT carrier_detect_55[] = {
+ /* PAL B/G */
+ { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" },
+ { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" }
+};
+
+static struct CARRIER_DETECT carrier_detect_65[] = {
+ /* PAL SAT / SECAM */
+ { 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" },
+};
+
+#define CARRIER_COUNT(x) (sizeof(x)/sizeof(struct CARRIER_DETECT))
+
+/* ------------------------------------------------------------------------ */
+
+static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2)
+{
+ msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff);
+ 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);
+}
+
+static void msp3400c_setvolume(struct i2c_bus *bus, int vol)
+{
+ int val = (vol * 0x73 / 65535) << 8;
+
+ dprintk("msp3400: setvolume: 0x%02x\n",val>>8);
+ msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
+ msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */
+ /* scart - on/off only */
+ msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0);
+}
+
+static void msp3400c_setmode(struct msp3400c *msp, int type)
+{
+ int i;
+
+ dprintk("msp3400: setmode: %d\n",type);
+ msp->mode = type;
+ msp->stereo = VIDEO_SOUND_MONO;
+
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */
+ msp_init_data[type].ad_cv);
+
+ for (i = 5; i >= 0; i--) /* fir 1 */
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0001,
+ msp_init_data[type].fir1[i]);
+
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0040);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0000);
+ for (i = 5; i >= 0; i--)
+ msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005,
+ msp_init_data[type].fir2[i]);
+
+ 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_DFP, 0x0008,
+ msp_init_data[type].dfp_src);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,
+ msp_init_data[type].dfp_src);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,
+ msp_init_data[type].dfp_src);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e,
+ msp_init_data[type].dfp_matrix);
+
+ if (msp->nicam)
+ {
+ /* msp3410 needs some more initialization */
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0010, 0x3000);
+ }
+}
+
+static void msp3400c_setstereo(struct msp3400c *msp, int mode)
+{
+ int nicam=0; /* channel source: FM/AM or nicam */
+
+ /* switch demodulator */
+ switch (msp->mode)
+ {
+ case MSP_MODE_FM_TERRA:
+ dprintk("msp3400: B/G setstereo: %d\n",mode);
+ msp->stereo = mode;
+ msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.7421875),MSP_CARRIER(5.5));
+ switch (mode)
+ {
+ case VIDEO_SOUND_STEREO:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001);
+ break;
+ case VIDEO_SOUND_MONO:
+ case VIDEO_SOUND_LANG1:
+ case VIDEO_SOUND_LANG2:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3000);
+ break;
+ }
+ break;
+ case MSP_MODE_FM_SAT:
+ dprintk("msp3400: sat setstereo: %d\n",mode);
+ msp->stereo = mode;
+ switch (mode)
+ {
+ case VIDEO_SOUND_MONO:
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
+ break;
+ case VIDEO_SOUND_STEREO:
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
+ break;
+ case VIDEO_SOUND_LANG1:
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+ break;
+ case VIDEO_SOUND_LANG2:
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
+ break;
+ }
+ break;
+ case MSP_MODE_FM_NICAM1:
+ dprintk("msp3400: NICAM1 setstereo: %d\n",mode);
+ msp->stereo = mode;
+ msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.85),MSP_CARRIER(5.5));
+ nicam=0x0100;
+ break;
+ default:
+ /* can't do stereo - abort here */
+ return;
+ }
+
+ /* switch audio */
+ switch (mode)
+ {
+ case VIDEO_SOUND_STEREO:
+ 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);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005, 0x4000);
+ break;
+ case VIDEO_SOUND_MONO:
+ case VIDEO_SOUND_LANG1:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0000|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0000|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0000|nicam);
+ break;
+ case VIDEO_SOUND_LANG2:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0010|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0010|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0010|nicam);
+ break;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct REGISTER_DUMP {
+ int addr;
+ char *name;
+};
+
+struct REGISTER_DUMP d1[] =
+{
+ { 0x007e, "autodetect" },
+ { 0x0023, "C_AD_BITS " },
+ { 0x0038, "ADD_BITS " },
+ { 0x003e, "CIB_BITS " },
+ { 0x0057, "ERROR_RATE" },
+};
+
+/*
+ * A kernel thread for msp3400 control -- we don't want to block the
+ * in the ioctl while doing the sound carrier & stereo detect
+ */
+
+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, check_stereo;
+ int i;
+
+ /* lock_kernel(); */
+
+ exit_mm(current);
+ current->session = 1;
+ current->pgrp = 1;
+ sigfillset(&current->blocked);
+ current->fs->umask = 0;
+ strcpy(current->comm,"msp3400");
+
+ msp->wait = &sem;
+ msp->thread = current;
+
+ /* unlock_kernel(); */
+
+ dprintk("msp3400: thread: start\n");
+ if(msp->notify != NULL)
+ up(msp->notify);
+
+ for (;;)
+ {
+ if (msp->rmmod)
+ goto done;
+ dprintk("msp3400: thread: sleep\n");
+ down_interruptible(&sem);
+ dprintk("msp3400: thread: wakeup\n");
+ if (msp->rmmod)
+ goto done;
+#if 0
+ if (VIDEO_MODE_RADIO == msp->norm)
+ {
+ msp->active = 1;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/10;
+ schedule();
+ if (signal_pending(current))
+ goto done;
+ LOCK_I2C_BUS(msp->bus);
+ val1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b);
+ val2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
+ UNLOCK_I2C_BUS(msp->bus);
+ printk("msp3400: DC %d/%d\n",val1,val2);
+ msp->active = 0;
+ continue;
+ }
+#endif
+
+ if (VIDEO_MODE_RADIO == msp->norm)
+ continue; /* nothing to do */
+
+ msp->active = 1;
+restart:
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setvolume(msp->bus, 0);
+ msp3400c_setmode(msp, MSP_MODE_AM_DETECT);
+ val1 = val2 = max1 = max2 = check_stereo = 0;
+
+ /* carrier detect pass #1 -- main carrier */
+ cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
+ for (this = 0; this < count; this++)
+ {
+ msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
+ UNLOCK_I2C_BUS(msp->bus);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/25;
+ schedule();
+ if (signal_pending(current))
+ goto done;
+ if (msp->restart)
+ {
+ msp->restart = 0;
+ goto restart;
+ }
+
+ LOCK_I2C_BUS(msp->bus);
+ val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b);
+ if (val1 < val)
+ val1 = val, max1 = this;
+ dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name);
+ }
+
+ /* carrier detect pass #2 -- second (stereo) carrier */
+ switch (max1)
+ {
+ case 1: /* 5.5 */
+ cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55);
+ break;
+ case 3: /* 6.5 */
+ cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65);
+ break;
+ case 0: /* 4.5 */
+ case 2: /* 6.0 */
+ default:
+ cd = NULL; count = 0;
+ break;
+ }
+ for (this = 0; this < count; this++)
+ {
+ msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
+ UNLOCK_I2C_BUS(msp->bus);
+
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/25;
+ schedule();
+ if (signal_pending(current))
+ goto done;
+ if (msp->restart)
+ {
+ msp->restart = 0;
+ goto restart;
+ }
+
+ LOCK_I2C_BUS(msp->bus);
+ val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b);
+ if (val2 < val)
+ val2 = val, max2 = this;
+ dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
+ }
+
+ /* programm the msp3400 according to the results */
+ 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 */
+ msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+ check_stereo = 1;
+ }
+ if (max2 == 1 && msp->nicam)
+ {
+ /* B/G NICAM */
+ 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));
+ check_stereo = 1;
+ }
+ break;
+ case 2: /* 6.0 */
+ case 3: /* 6.5 */
+ default:
+ 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);
+ break;
+ }
+
+ /* unmute */
+ msp3400c_setvolume(msp->bus, msp->volume);
+
+ if (check_stereo)
+ {
+ /* stereo available -- check current mode */
+ UNLOCK_I2C_BUS(msp->bus);
+
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ;
+ schedule();
+ if (signal_pending(current))
+ goto done;
+ if (msp->restart)
+ {
+ msp->restart = 0;
+ goto restart;
+ }
+
+ LOCK_I2C_BUS(msp->bus);
+ switch (msp->mode)
+ {
+ case MSP_MODE_FM_TERRA:
+ val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18);
+ dprintk("msp3400: stereo detect register: %d\n",val);
+
+ if (val > 4096)
+ {
+ msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
+ }
+ else if (val < -4096)
+ {
+ msp3400c_setstereo(msp, VIDEO_SOUND_LANG1);
+ }
+ else
+ {
+ msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+ }
+ break;
+ case MSP_MODE_FM_NICAM1:
+ val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23);
+ switch ((val & 0x1e) >> 1)
+ {
+ case 0:
+ case 8:
+ msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
+ break;
+ default:
+ msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+ break;
+ }
+
+ /* dump registers (for debugging) */
+ if (debug)
+ {
+ for (i=0; i<sizeof(d1)/sizeof(struct REGISTER_DUMP); i++)
+ {
+ val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM, d1[i].addr);
+ printk(KERN_DEBUG "msp3400: %s = 0x%x\n",
+ d1[i].name,val);
+ }
+ }
+ break;
+ }
+ }
+ UNLOCK_I2C_BUS(msp->bus);
+ msp->active = 0;
+ }
+
+done:
+ dprintk("msp3400: thread: exit\n");
+ msp->wait = NULL;
+ msp->active = 0;
+ msp->thread = NULL;
+
+ if(msp->notify != NULL)
+ up(msp->notify);
+ return 0;
+}
+
+int msp3410d_thread(void *data)
+{
+ unsigned long flags;
+ struct msp3400c *msp = data;
+ struct semaphore sem = MUTEX_LOCKED;
+ int i, val;
+
+ /* lock_kernel(); */
+
+ exit_mm(current);
+ current->session = 1;
+ current->pgrp = 1;
+ sigfillset(&current->blocked);
+ current->fs->umask = 0;
+ strcpy(current->comm,"msp3410 (nicam)");
+
+ msp->wait = &sem;
+ msp->thread = current;
+
+ /* unlock_kernel(); */
+
+ dprintk("msp3410: thread: start\n");
+ if(msp->notify != NULL)
+ up(msp->notify);
+
+ for (;;)
+ {
+ if (msp->rmmod)
+ goto done;
+ dprintk("msp3410: thread: sleep\n");
+ down_interruptible(&sem);
+ dprintk("msp3410: thread: wakeup\n");
+ if (msp->rmmod)
+ goto done;
+
+ if (VIDEO_MODE_RADIO == msp->norm)
+ continue; /* nothing to do */
+
+ msp->active = 1;
+
+restart:
+ LOCK_I2C_BUS(msp->bus);
+ /* mute */
+ msp3400c_setvolume(msp->bus, 0);
+ /* quick & dirty hack:
+ get the audio proccessor into some useful state */
+ msp3400c_setmode(msp, MSP_MODE_FM_NICAM1);
+ /* kick autodetect */
+ msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x20, 0x01);
+ msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01);
+ UNLOCK_I2C_BUS(msp->bus);
+
+ /* wait 1 sec */
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ;
+ schedule();
+ if (signal_pending(current))
+ goto done;
+ if (msp->restart)
+ {
+ msp->restart = 0;
+ goto restart;
+ }
+
+ LOCK_I2C_BUS(msp->bus);
+ /* debug register dump */
+ for (i = 0; i < sizeof(d1)/sizeof(struct REGISTER_DUMP); i++)
+ {
+ val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM,d1[i].addr);
+ printk(KERN_DEBUG "msp3400: %s = 0x%x\n",d1[i].name,val);
+ }
+ /* unmute */
+ msp3400c_setvolume(msp->bus, msp->volume);
+ UNLOCK_I2C_BUS(msp->bus);
+
+ msp->active = 0;
+ }
+
+done:
+ dprintk("msp3410: thread: exit\n");
+ msp->wait = NULL;
+ msp->active = 0;
+ msp->thread = NULL;
+
+ if(msp->notify != NULL)
+ up(msp->notify);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int msp3400c_attach(struct i2c_device *device)
+{
+ unsigned long flags;
+ struct semaphore sem = MUTEX_LOCKED;
+ struct msp3400c *msp;
+ int rev1,rev2;
+
+ /*
+ * MSP3400's are for now only assumed to live on busses
+ * connected to a BT848. Adjust as and when you get new
+ * funky cards using these components.
+ */
+
+ if(device->bus->id != I2C_BUSID_BT848)
+ return -EINVAL;
+
+ device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL);
+ if (NULL == msp)
+ return -ENOMEM;
+ memset(msp,0,sizeof(struct msp3400c));
+ msp->bus = device->bus;
+ msp->volume = 65535;
+
+ LOCK_I2C_BUS(msp->bus);
+ if (-1 == msp3400c_reset(msp->bus))
+ {
+ UNLOCK_I2C_BUS(msp->bus);
+ kfree(msp);
+ return -1;
+ }
+
+ msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
+ msp3400c_setvolume(msp->bus, msp->volume);
+
+ 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);
+#endif
+ UNLOCK_I2C_BUS(msp->bus);
+
+ 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;
+ printk(KERN_INFO "msp3400: init: chip=%s%s\n",
+ device->name, msp->nicam ? ", can decode nicam" : "");
+
+ MOD_INC_USE_COUNT;
+ /* startup control thread */
+ msp->notify = &sem;
+ kernel_thread(msp3400c_thread, (void *)msp, 0);
+ down(&sem);
+ msp->notify = NULL;
+ if (!msp->active)
+ up(msp->wait);
+ return 0;
+}
+
+static int msp3400c_detach(struct i2c_device *device)
+{
+ unsigned long flags;
+ struct semaphore sem = MUTEX_LOCKED;
+ struct msp3400c *msp = (struct msp3400c*)device->data;
+
+ /* shutdown control thread */
+ msp->notify = &sem;
+ msp->rmmod = 1;
+ if (!msp->active)
+ up(msp->wait);
+ down(&sem);
+ msp->notify = NULL;
+
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_reset(msp->bus);
+ UNLOCK_I2C_BUS(msp->bus);
+
+ kfree(msp);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+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;
+
+ switch (cmd)
+ {
+ case MSP_SET_RADIO:
+ msp->norm = VIDEO_MODE_RADIO;
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setmode(msp,MSP_MODE_FM_RADIO);
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
+ case MSP_SET_TVNORM:
+ msp->norm = *iarg;
+ break;
+ case MSP_NEWCHANNEL:
+ if (!msp->active)
+ up(msp->wait);
+ else
+ msp->restart = 1;
+ break;
+
+ case MSP_GET_VOLUME:
+ *iarg = msp->volume;
+ break;
+ case MSP_SET_VOLUME:
+ msp->volume = *iarg;
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setvolume(msp->bus,msp->volume);
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
+
+ case MSP_GET_STEREO:
+ *iarg = msp->stereo;
+ break;
+ case MSP_SET_STEREO:
+ if (*iarg)
+ {
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setstereo(msp,*iarg);
+ 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);
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_msp =
+{
+ "msp3400", /* name */
+ I2C_DRIVERID_MSP3400, /* ID */
+ I2C_MSP3400C, I2C_MSP3400C, /* addr range */
+
+ msp3400c_attach,
+ msp3400c_detach,
+ msp3400c_command
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int msp3400c_init(void)
+#endif
+{
+ i2c_register_driver(&i2c_driver_msp);
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ i2c_unregister_driver(&i2c_driver_msp);
+}
+#endif
+
diff --git a/drivers/char/msp3400.h b/drivers/char/msp3400.h
new file mode 100644
index 000000000..1b4eedab0
--- /dev/null
+++ b/drivers/char/msp3400.h
@@ -0,0 +1,18 @@
+#ifndef MSP3400_H
+#define MSP3400_H
+
+/* ---------------------------------------------------------------------- */
+
+#define MSP_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */
+#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_STEREO _IOR('m',6,int)
+#define MSP_SET_STEREO _IOW('m',7,int)
+
+#define MSP_GET_DC _IOW('m',8,int)
+
+#endif /* MSP3400_H */
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index 5f6ed4b01..e4718688a 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -22,7 +22,9 @@
#include <asm/keyboard.h>
#include <asm/bitops.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/system.h>
+#include <asm/irq.h>
/* Some configuration switches are present in the include file... */
@@ -34,39 +36,30 @@
* them.
*/
-#ifndef __i386__
-#define INIT_KBD
-#endif
-
-#ifdef INIT_KBD
-
-/* Simple translation table for the SysRq keys */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char pckbd_sysrq_xlate[128] =
- "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
- "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
- "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
- "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
- "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
- "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
- "\r\000/"; /* 0x60 - 0x6f */
+/*
+ * Some x86 BIOSes do not correctly initializes the keyboard, so the
+ * "kbd-reset" command line options can be given to force a reset.
+ * [Ranger]
+ */
+#ifdef __i386__
+int kbd_startup_reset __initdata = 0;
+#else
+int kbd_startup_reset __initdata = 1;
#endif
static int kbd_wait_for_input(void)
{
- int n;
int status, data;
unsigned long start = jiffies;
do {
status = kbd_read_status();
+
/*
* Wait for input data to become available. This bit will
* then be cleared by the following read of the DATA
* register.
*/
-
if (!(status & KBD_STAT_OBF))
continue;
@@ -86,28 +79,10 @@ static int kbd_wait_for_input(void)
return -1; /* timed-out if fell through to here... */
}
-static void init_write_command(int data)
-{
- int status;
-
- do {
- status = kbd_read_status();
- } while (status & KBD_STAT_IBF);
- kbd_write_command(data);
-}
-
-static void init_write_output(int data)
+static char *initialize_kbd2(void)
{
int status;
- do {
- status = kbd_read_status();
- } while (status & KBD_STAT_IBF);
- kbd_write_output(data);
-}
-
-static char *initialize_kbd2(void)
-{
/* Flush any pending input. */
while (kbd_wait_for_input() != -1)
@@ -119,7 +94,7 @@ static char *initialize_kbd2(void)
* If the test is successful a x55 is placed in the input buffer.
*/
- init_write_command(KBD_CCMD_SELF_TEST);
+ kbd_write_command(KBD_CCMD_SELF_TEST);
if (kbd_wait_for_input() != 0x55)
return "Keyboard failed self test";
@@ -129,43 +104,58 @@ static char *initialize_kbd2(void)
* test are placed in the input buffer.
*/
- init_write_command(KBD_CCMD_KBD_TEST);
+ kbd_write_command(KBD_CCMD_KBD_TEST);
if (kbd_wait_for_input() != 0x00)
return "Keyboard interface failed self test";
/* Enable the keyboard by allowing the keyboard clock to run. */
- init_write_command(KBD_CCMD_KBD_ENABLE);
+ kbd_write_command(KBD_CCMD_KBD_ENABLE);
/*
* Reset keyboard. If the read times out
* then the assumption is that no keyboard is
* plugged into the machine.
* This defaults the keyboard to scan-code set 2.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
*/
- init_write_output(KBD_CMD_RESET);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Keyboard reset failed, no ACK";
+ do {
+ kbd_write_output(KBD_CMD_RESET);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ else if (status != KBD_REPLY_RESEND)
+ return "Keyboard reset failed, no ACK";
+ } while (1);
+
if (kbd_wait_for_input() != KBD_REPLY_POR)
return "Keyboard reset failed, no POR";
/*
* Set keyboard controller mode. During this, the keyboard should be
* in the disabled state.
+ *
+ * Set up to try again if the keyboard asks for RESEND.
*/
- init_write_output(KBD_CMD_DISABLE);
- if (kbd_wait_for_input() != KBD_REPLY_ACK)
- return "Disable keyboard: no ACK";
+ do {
+ kbd_write_output(KBD_CMD_DISABLE);
+ status = kbd_wait_for_input();
+ if (status == KBD_REPLY_ACK)
+ break;
+ else if (status != KBD_REPLY_RESEND)
+ return "Disable keyboard: no ACK";
+ } while (1);
- init_write_command(KBD_CCMD_WRITE_MODE);
- init_write_output(KBD_MODE_KBD_INT
+ kbd_write_command(KBD_CCMD_WRITE_MODE);
+ kbd_write_output(KBD_MODE_KBD_INT
| KBD_MODE_SYS
| KBD_MODE_DISABLE_MOUSE
| KBD_MODE_KCC);
- init_write_output(KBD_CMD_ENABLE);
+ kbd_write_output(KBD_CMD_ENABLE);
if (kbd_wait_for_input() != KBD_REPLY_ACK)
return "Enable keyboard: no ACK";
@@ -173,10 +163,10 @@ static char *initialize_kbd2(void)
* Finally, set the typematic rate to maximum.
*/
- init_write_output(KBD_CMD_SET_RATE);
+ kbd_write_output(KBD_CMD_SET_RATE);
if (kbd_wait_for_input() != KBD_REPLY_ACK)
return "Set rate: no ACK";
- init_write_output(0x00);
+ kbd_write_output(0x00);
if (kbd_wait_for_input() != KBD_REPLY_ACK)
return "Set rate: no ACK";
@@ -195,7 +185,7 @@ void initialize_kbd(void)
printk(KERN_WARNING "initialize_kbd: %s\n", msg);
}
-#endif /* INIT_KBD */
+
unsigned char kbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
@@ -596,7 +586,11 @@ __initfunc(void pckbd_init_hw(void))
{
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
keyboard_setup();
-#ifdef INIT_KBD
- initialize_kbd();
-#endif
+ if (kbd_startup_reset) initialize_kbd();
+}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void kbd_reset_setup(char *str, int *ints))
+{
+ kbd_startup_reset = 1;
}
diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
index 194295576..1bd7ab8b2 100644
--- a/drivers/char/pc_keyb.h
+++ b/drivers/char/pc_keyb.h
@@ -17,7 +17,7 @@
#define KBD_INIT_TIMEOUT HZ /* Timeout in jiffies for initializing the keyboard */
#define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */
-#define KBD_TIMEOUT 250 /* Timeout in ms for keyboard command acknowledge */
+#define KBD_TIMEOUT 1000 /* Timeout in ms for keyboard command acknowledge */
/*
* Internal variables of the driver
diff --git a/drivers/char/pms.c b/drivers/char/pms.c
index 047ae09b2..c17cb20ae 100644
--- a/drivers/char/pms.c
+++ b/drivers/char/pms.c
@@ -1020,11 +1020,10 @@ static void shutdown_mediavision(void)
*/
#ifdef MODULE
-
-MODULE_PARM(io_port,"i");
-MODULE_PARM(mem_base,"i");
-
int init_module(void)
+#else
+void init_pms_cards(void)
+#endif
{
printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
@@ -1040,9 +1039,14 @@ int init_module(void)
pms_device.width=320;
pms_swsense(75);
pms_resolution(320,240);
- return video_register_device((struct video_device *)&pms_device);
+ return video_register_device((struct video_device *)&pms_device, VFL_TYPE_GRABBER);
}
+#ifdef MODULE
+
+MODULE_PARM(io_port,"i");
+MODULE_PARM(mem_base,"i");
+
void cleanup_module(void)
{
shutdown_mediavision();
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 53c95d5fa..fb136c3e8 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -7,6 +7,8 @@
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
*/
+#include <linux/module.h> /* For EXPORT_SYMBOL */
+
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -22,6 +24,9 @@
#include <asm/system.h>
#include <asm/bitops.h>
+#define BUILDING_PTY_C 1
+#include <linux/devpts_fs.h>
+
struct pty_struct {
int magic;
struct wait_queue * open_wait;
@@ -66,6 +71,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
if (tty->driver.subtype == PTY_TYPE_MASTER) {
tty_hangup(tty->link);
set_bit(TTY_OTHER_CLOSED, &tty->flags);
+ devpts_pty_kill(MINOR(tty->device) - tty->driver.minor_start);
}
}
@@ -363,6 +369,5 @@ __initfunc(int pty_init(void))
panic("Couldn't register compat pty driver");
if (tty_register_driver(&old_pty_slave_driver))
panic("Couldn't register compat pty slave driver");
-
return 0;
}
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 3b6f95f60..901077455 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -80,7 +80,6 @@
#include <linux/major.h>
#include <linux/ioport.h>
#ifdef ENABLE_PCI
-#include <linux/bios32.h>
#include <linux/pci.h>
#endif
#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
@@ -1875,31 +1874,10 @@ __initfunc(int register_PCI(int i, char bus, char device_fn))
unsigned int aiopio[MAX_AIOPS_PER_BOARD];
char *str;
CONTROLLER_t *ctlp;
- unsigned short vendor_id, device_id;
- int ret, error;
- unsigned int port;
-
- error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID,
- &vendor_id);
- ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID,
- &device_id);
- if (error == 0)
- error = ret;
- ret = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
- &port);
- rcktpt_io_addr[i] = (unsigned long) port;
- if (error == 0)
- error = ret;
-
- if (error) {
- printk("PCI RocketPort error: %s not initializing due to error"
- "reading configuration space\n",
- pcibios_strerror(error));
- return(0);
- }
+ struct pci_dev *dev = pci_find_slot(bus, device_fn);
- --rcktpt_io_addr[i];
- switch(device_id) {
+ rcktpt_io_addr[i] = dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+ switch(dev->device) {
case PCI_DEVICE_ID_RP4QUAD:
str = "Quadcable";
max_num_aiops = 1;
@@ -1935,7 +1913,7 @@ __initfunc(int register_PCI(int i, char bus, char device_fn))
num_aiops = sPCIInitController(ctlp, i,
aiopio, max_num_aiops, 0,
FREQ_DIS, 0);
- printk("Rocketport controller #%d found at %d:%d, "
+ printk("Rocketport controller #%d found at %02x:%02x, "
"%d AIOP(s) (PCI Rocketport %s)\n", i, bus, device_fn,
num_aiops, str);
if(num_aiops <= 0) {
@@ -2095,7 +2073,7 @@ __initfunc(int rp_init(void))
isa_boards_found++;
}
#ifdef ENABLE_PCI
- if (pcibios_present()) {
+ if (pci_present()) {
if(isa_boards_found < NUM_BOARDS)
pci_boards_found = init_PCI(isa_boards_found);
} else {
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index b81a8eb8f..746b93680 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -27,54 +27,18 @@
* 8/97: Fix bug in rs_set_termios with RTS
* Stanislav V. Voronyi <stas@uanet.kharkov.ua>
*
+ * 3/98: Change the IRQ detection, use of probe_irq_o*(),
+ * supress TIOCSERGWILD and TIOCSERSWILD
+ * Etienne Lorrain <etienne.lorrain@ibm.net>
+ *
+ * 4/98: Added changes to support the ARM architecture proposed by
+ * Russell King
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
*/
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#endif
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#ifdef CONFIG_MIPS_JAZZ
-#include <asm/bootinfo.h>
-#include <asm/jazz.h>
-#endif
-
-static char *serial_name = "Serial driver";
-static char *serial_version = "4.24";
-
-static DECLARE_TASK_QUEUE(tq_serial);
-
-static struct tty_driver serial_driver, callout_driver;
-static int serial_refcount;
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
/*
* Serial driver configuration section. Here are the various options:
*
@@ -92,6 +56,9 @@ static int serial_refcount;
* CONFIG_SERIAL_SHARE_IRQ
* Enables support for multiple serial ports on one IRQ
*
+ * CONFIG_SERIAL_DETECT_IRQ
+ * Enable the autodetection of IRQ on standart ports
+ *
* SERIAL_PARANOIA_CHECK
* Check the magic number for the async_structure where
* ever possible.
@@ -106,6 +73,7 @@ static int serial_refcount;
#define CONFIG_SERIAL_MANY_PORTS
#define CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_DETECT_IRQ
#define CONFIG_SERIAL_MULTIPORT
#define CONFIG_HUB6
#endif
@@ -139,7 +107,7 @@ static int serial_refcount;
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
-#define _INLINE_ inline
+#define SERIAL_INLINE
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
@@ -149,22 +117,70 @@ static int serial_refcount;
#endif
/*
+ * End of serial driver configuration section.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/serial.h>
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
+static char *serial_name = "Serial driver";
+static char *serial_version = "4.25";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/*
* IRQ_timeout - How long the timeout should be for each IRQ
* should be after the IRQ has been active.
*/
-static struct async_struct *IRQ_ports[16];
+static struct async_struct *IRQ_ports[NR_IRQS];
#ifdef CONFIG_SERIAL_MULTIPORT
-static struct rs_multiport_struct rs_multiport[16];
+static struct rs_multiport_struct rs_multiport[NR_IRQS];
#endif
-static int IRQ_timeout[16];
-static volatile int rs_irq_triggered;
-static volatile int rs_triggered;
-static int rs_wild_int_mask;
+static int IRQ_timeout[NR_IRQS];
#ifdef CONFIG_SERIAL_CONSOLE
static struct console sercons;
#endif
+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 rs_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -186,177 +202,10 @@ static struct serial_uart_config uart_config[] = {
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
{ 0, 0}
};
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD ( 1843200 / 16 )
-#define JAZZ_BASE_BAUD ( 8000000 / 16 ) /* ( 3072000 / 16) */
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-static struct serial_state *rs_table;
-static struct serial_state rs_table_std[] = {
- /* UART CLK PORT IRQ FLAGS */
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-#ifdef CONFIG_SERIAL_MANY_PORTS
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */
-
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */
-
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare; user configurable) */
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare; user configurable) */
-
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#ifdef CONFIG_HUB6
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
-#endif
-#endif /* CONFIG_SERIAL_MANY_PORTS */
-#ifdef CONFIG_MCA
- { 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS },
- { 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS },
- { 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS },
- { 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS },
- { 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS },
- { 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS },
-#endif
-};
-#ifdef CONFIG_MIPS_JAZZ
-static struct serial_state rs_table_jazz[] = {
- /* UART CLK PORT IRQ FLAGS */
- { 0, JAZZ_BASE_BAUD, JAZZ_SERIAL1_BASE, /* ttyS0 */
- JAZZ_SERIAL1_IRQ, STD_COM_FLAGS },
- { 0, JAZZ_BASE_BAUD, JAZZ_SERIAL2_BASE, /* ttyS1 */
- JAZZ_SERIAL2_IRQ, STD_COM_FLAGS },
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS2 */
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS3 */
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS4 */
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS5 */
-#ifdef CONFIG_SERIAL_MANY_PORTS
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS6 */
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS7 */
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS8 */
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS9 */
-
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS10 */
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS11 */
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS12 */
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS13 */
-
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS14 */
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS15 */
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS16 (spare; user configurable) */
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS17 (spare; user configurable) */
-
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS18 */
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS19 */
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS20 */
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS21 */
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS22 */
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS23 */
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS24 */
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS25 */
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS26 */
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS27 */
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS28 */
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS29 */
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS30 */
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS31 */
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS32 */
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS33 */
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#ifdef CONFIG_HUB6
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS34 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS35 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS36 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS37 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS38 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS39 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS40 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS41 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS42 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS43 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS44 */
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS45 */
-#endif
-#endif /* CONFIG_SERIAL_MANY_PORTS */
+static struct serial_state rs_table[] = {
+ SERIAL_PORT_DFNS /* Defined in serial.h */
};
-#endif /* CONFIG_MIPS_JAZZ */
#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
@@ -377,7 +226,7 @@ static struct termios *serial_termios_locked[NR_PORTS];
* buffer across all the serial ports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
-static unsigned char *tmp_buf = 0;
+static unsigned char *tmp_buf;
static struct semaphore tmp_buf_sem = MUTEX;
static inline int serial_paranoia_check(struct async_struct *info,
@@ -536,17 +385,6 @@ static void rs_start(struct tty_struct *tty)
*/
/*
- * This is the serial driver's interrupt routine while we are probing
- * for submarines.
- */
-static void rs_probe(int irq, void *dev_id, struct pt_regs * regs)
-{
- rs_irq_triggered = irq;
- rs_triggered |= 1 << irq;
- return;
-}
-
-/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver.
*/
@@ -1016,7 +854,7 @@ static void rs_timer(void)
unsigned int i;
if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
- for (i=1; i < 16; i++) {
+ for (i=1; i < NR_IRQS; i++) {
info = IRQ_ports[i];
if (!info)
continue;
@@ -1068,38 +906,6 @@ static void rs_timer(void)
*/
/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection. dontgrab is a mask of irq's _not_ to grab. Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
-static int grab_all_interrupts(int dontgrab)
-{
- int irq_lines = 0;
- int i, mask;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if (!(mask & dontgrab) && !request_irq(i, rs_probe, SA_INTERRUPT, "serial probe", NULL)) {
- irq_lines |= mask;
- }
- }
- return irq_lines;
-}
-
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
-static void free_all_interrupts(int irq_lines)
-{
- int i;
-
- for (i = 0; i < 16; i++) {
- if (irq_lines & (1 << i))
- free_irq(i, NULL);
- }
-}
-
-/*
* This routine figures out the correct timeout for a particular IRQ.
* It uses the smallest timeout of all of the serial ports in a
* particular interrupt chain. Now only used for IRQ 0....
@@ -1634,44 +1440,61 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (!tty || !info->xmit_buf || !tmp_buf)
return 0;
-
- if (from_user)
- down(&tmp_buf_sem);
+
save_flags(flags);
- while (1) {
- cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = MIN(count,
+ MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
- if (from_user) {
c -= copy_from_user(tmp_buf, buf, c);
if (!c) {
if (!ret)
ret = -EFAULT;
break;
}
+ cli();
c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- } else
+ info->xmit_head = ((info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = MIN(count,
+ MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- ret += c;
+ info->xmit_head = ((info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
}
- if (from_user)
- up(&tmp_buf_sem);
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
!(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
- restore_flags(flags);
return ret;
}
@@ -1852,10 +1675,9 @@ static int set_serial_info(struct async_struct * info,
goto check_and_exit;
}
- if (new_serial.irq == 2)
- new_serial.irq = 9;
+ new_serial.irq = irq_cannonicalize(new_serial.irq);
- if ((new_serial.irq > 15) || (new_serial.port > 0xffff) ||
+ if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
(new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
return -EINVAL;
}
@@ -1886,6 +1708,7 @@ static int set_serial_info(struct async_struct * info,
state->type = new_serial.type;
state->close_delay = new_serial.close_delay * HZ/100;
state->closing_wait = new_serial.closing_wait * HZ/100;
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
info->xmit_fifo_size = state->xmit_fifo_size =
new_serial.xmit_fifo_size;
@@ -2044,9 +1867,9 @@ static int do_autoconfig(struct async_struct * info)
shutdown(info);
- cli();
autoconfig(info->state);
- sti();
+ if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
+ info->state->irq = detect_uart_irq(info->state);
retval = startup(info);
if (retval)
@@ -2077,50 +1900,6 @@ static void rs_break(struct tty_struct *tty, int break_state)
restore_flags(flags);
}
-/*
- * This routine returns a bitfield of "wild interrupts". Basically,
- * any unclaimed interrupts which is flapping around.
- */
-static int check_wild_interrupts(int doprint)
-{
- int i, mask;
- int wild_interrupts = 0;
- int irq_lines;
- unsigned long timeout;
- unsigned long flags;
-
- /* Turn on interrupts (they may be off) */
- save_flags(flags); sti();
-
- irq_lines = grab_all_interrupts(0);
-
- /*
- * Delay for 0.1 seconds -- we use a busy loop since this may
- * occur during the bootup sequence
- */
- timeout = jiffies+HZ/10;
- while (timeout >= jiffies)
- ;
-
- rs_triggered = 0; /* Reset after letting things settle */
-
- timeout = jiffies+HZ/10;
- while (timeout >= jiffies)
- ;
-
- for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
- if ((rs_triggered & (1 << i)) &&
- (irq_lines & (1 << i))) {
- wild_interrupts |= mask;
- if (doprint)
- printk("Wild interrupt? (IRQ %d)\n", i);
- }
- }
- free_all_interrupts(irq_lines);
- restore_flags(flags);
- return wild_interrupts;
-}
-
#ifdef CONFIG_SERIAL_MULTIPORT
static int get_multiport_struct(struct async_struct * info,
struct serial_multiport_struct *retinfo)
@@ -2248,8 +2027,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return -ENODEV;
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -2271,23 +2049,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
case TIOCSERCONFIG:
return do_autoconfig(info);
- case TIOCSERGWILD:
- return put_user(rs_wild_int_mask,
- (unsigned int *) arg);
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
- case TIOCSERSWILD:
- if (!suser())
- return -EPERM;
- error = get_user(rs_wild_int_mask,
- (unsigned int *) arg);
- if (error)
- return error;
- if (rs_wild_int_mask < 0)
- rs_wild_int_mask = check_wild_interrupts(0);
- return 0;
-
case TIOCSERGSTRUCT:
if (copy_to_user((struct async_struct *) arg,
info, sizeof(struct async_struct)))
@@ -2309,7 +2073,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
- case TIOCMIWAIT:
+ case TIOCMIWAIT:
cli();
/* note the counters on entry */
cprev = info->state->icount;
@@ -2800,6 +2564,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
#endif
tty->driver_data = info;
info->tty = tty;
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
if (!tmp_buf) {
page = get_free_page(GFP_KERNEL);
@@ -2871,7 +2636,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
* /proc fs routines....
*/
-static int inline line_info(char *buf, struct serial_state *state)
+static inline int line_info(char *buf, struct serial_state *state)
{
struct async_struct *info = state->info, scr_info;
char stat_buf[30], control, status;
@@ -2999,7 +2764,10 @@ static _INLINE_ void show_serial_version(void)
#endif
#ifdef CONFIG_SERIAL_SHARE_IRQ
printk(" SHARE_IRQ");
+#endif
#define SERIAL_OPT
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+ printk(" DETECT_IRQ");
#endif
#ifdef SERIAL_OPT
printk(" enabled\n");
@@ -3010,105 +2778,54 @@ static _INLINE_ void show_serial_version(void)
}
/*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use. It is not
- * fool-proof, but it works a large part of the time.
+ * This routine detect the IRQ of a serial port by clearing OUT2 when
+ * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
+ * each time, as long as no other device permanently request the IRQ.
+ * If no IRQ is detected, or multiple IRQ appear, this function returns 0.
+ * The variable "state" and the field "state->port" should not be null.
*/
-static int get_auto_irq(struct async_struct *info)
+static unsigned detect_uart_irq (struct serial_state * state)
{
-
- unsigned char save_MCR, save_IER;
- unsigned long timeout;
-#ifdef CONFIG_SERIAL_MANY_PORTS
- unsigned char save_ICP=0;
- unsigned short ICP=0, port = info->port;
-#endif
+ int irq;
+ unsigned long irqs;
+ unsigned char save_mcr;
+ struct async_struct scr_info; /* serial_{in,out} because HUB6 */
-
- /*
- * Enable interrupts and see who answers
- */
- rs_irq_triggered = 0;
- cli();
- save_IER = serial_inp(info, UART_IER);
- save_MCR = serial_inp(info, UART_MCR);
#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT) {
- serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
- serial_outp(info, UART_IER, 0x0f); /* enable all intrs */
- ICP = (port & 0xFE0) | 0x01F;
+ unsigned char save_ICP=0; /* no warning */
+ unsigned short ICP=0;
+
+ if (state->flags & ASYNC_FOURPORT) {
+ ICP = (state->port & 0xFE0) | 0x01F;
save_ICP = inb_p(ICP);
outb_p(0x80, ICP);
(void) inb_p(ICP);
- } else
-#endif
- {
- serial_outp(info, UART_MCR,
- UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
- serial_outp(info, UART_IER, 0x0f); /* enable all intrs */
}
- sti();
- /*
- * Next, clear the interrupt registers.
- */
- (void)serial_inp(info, UART_LSR);
- (void)serial_inp(info, UART_RX);
- (void)serial_inp(info, UART_IIR);
- (void)serial_inp(info, UART_MSR);
-
- timeout = jiffies+ ((2*HZ)/100);
- while (timeout >= jiffies) {
- if (rs_irq_triggered)
- break;
- }
- /*
- * Now check to see if we got any business, and clean up.
- */
- cli();
- serial_outp(info, UART_IER, save_IER);
- serial_outp(info, UART_MCR, save_MCR);
-#ifdef CONFIG_SERIAL_MANY_PORTS
- if (info->flags & ASYNC_FOURPORT)
- outb_p(save_ICP, ICP);
#endif
- sti();
- return(rs_irq_triggered);
-}
+ scr_info.magic = SERIAL_MAGIC;
+ scr_info.port = state->port;
+ scr_info.flags = state->flags;
+#ifdef CONFIG_HUB6
+ scr_info.hub6 = state->hub6;
+#endif
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
-static int do_auto_irq(struct async_struct * info)
-{
- unsigned port = info->port;
- int irq_lines = 0;
- int irq_try_1 = 0, irq_try_2 = 0;
- int retries;
- unsigned long flags;
+ /* forget possible initially masked and pending IRQ */
+ probe_irq_off(probe_irq_on());
+ save_mcr = serial_inp(&scr_info, UART_MCR);
- if (!port)
- return 0;
+ serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+ irqs = probe_irq_on();
+ serial_outp(&scr_info, UART_MCR, 0);
+ udelay (1);
+ irq = probe_irq_off(irqs);
- /* Turn on interrupts (they may be off) */
- save_flags(flags); sti();
+ serial_outp(&scr_info, UART_MCR, save_mcr);
- irq_lines = grab_all_interrupts(rs_wild_int_mask);
-
- for (retries = 0; retries < 5; retries++) {
- if (!irq_try_1)
- irq_try_1 = get_auto_irq(info);
- if (!irq_try_2)
- irq_try_2 = get_auto_irq(info);
- if (irq_try_1 && irq_try_2) {
- if (irq_try_1 == irq_try_2)
- break;
- irq_try_1 = irq_try_2 = 0;
- }
- }
- restore_flags(flags);
- free_all_interrupts(irq_lines);
- return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+ if (state->flags & ASYNC_FOURPORT)
+ outb_p(save_ICP, ICP);
+#endif
+ return (irq > 0)? irq : 0;
}
/*
@@ -3134,6 +2851,9 @@ static void autoconfig(struct serial_state * state)
info->magic = SERIAL_MAGIC;
info->port = state->port;
info->flags = state->flags;
+#ifdef CONFIG_HUB6
+ info->hub6 = state->hub6;
+#endif
save_flags(flags); cli();
@@ -3179,13 +2899,6 @@ static void autoconfig(struct serial_state * state)
}
}
- /*
- * If the AUTO_IRQ flag is set, try to do the automatic IRQ
- * detection.
- */
- if (state->flags & ASYNC_AUTO_IRQ)
- state->irq = do_auto_irq(info);
-
scratch2 = serial_in(info, UART_LCR);
serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
@@ -3267,6 +2980,7 @@ static void autoconfig(struct serial_state * state)
serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
(void)serial_in(info, UART_RX);
+ serial_outp(info, UART_IER, 0);
restore_flags(flags);
}
@@ -3284,7 +2998,16 @@ __initfunc(int rs_init(void))
{
int i;
struct serial_state * state;
-
+ extern void atomwide_serial_init (void);
+ extern void dualsp_serial_init (void);
+
+#ifdef CONFIG_ATOMWIDE_SERIAL
+ atomwide_serial_init ();
+#endif
+#ifdef CONFIG_DUALSP_SERIAL
+ dualsp_serial_init ();
+#endif
+
rs_table = rs_table_std;
#ifdef __mips__
if (mips_machgroup == MACH_GROUP_JAZZ) {
@@ -3302,12 +3025,8 @@ __initfunc(int rs_init(void))
init_bh(SERIAL_BH, do_serial_bh);
timer_table[RS_TIMER].fn = rs_timer;
timer_table[RS_TIMER].expires = 0;
-#ifdef CONFIG_AUTO_IRQ
- rs_wild_int_mask = check_wild_interrupts(1);
-#endif
-/* printk("in rs_init()\n"); */
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < NR_IRQS; i++) {
IRQ_ports[i] = 0;
IRQ_timeout[i] = 0;
#ifdef CONFIG_SERIAL_MULTIPORT
@@ -3320,7 +3039,7 @@ __initfunc(int rs_init(void))
* The interrupt of the serial console port
* can't be shared.
*/
- if (sercons.flags & CON_FIRST) {
+ if (sercons.flags & CON_CONSDEV) {
for(i = 0; i < NR_PORTS; i++)
if (i != sercons.index &&
rs_table[i].irq == rs_table[sercons.index].irq)
@@ -3399,17 +3118,26 @@ __initfunc(int rs_init(void))
state->icount.rx = state->icount.tx = 0;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
- if (state->irq == 2)
- state->irq = 9;
- if (state->type == PORT_UNKNOWN) {
- if (!(state->flags & ASYNC_BOOT_AUTOCONF))
- continue;
- if (check_region(state->port,8))
- continue;
- autoconfig(state);
- if (state->type == PORT_UNKNOWN)
- continue;
+ state->irq = irq_cannonicalize(state->irq);
+ if (check_region(state->port,8)) {
+ state->type = PORT_UNKNOWN;
+ continue;
}
+ if ( (state->type == PORT_UNKNOWN)
+ && (state->flags & ASYNC_BOOT_AUTOCONF))
+ autoconfig(state);
+ }
+ /*
+ * Detect the IRQ only once every port is initialised,
+ * because some 16450 do not reset to 0 the MCR register.
+ */
+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ if (state->type == PORT_UNKNOWN)
+ continue;
+ if ( (state->flags & ASYNC_BOOT_AUTOCONF)
+ && (state->flags & ASYNC_AUTO_IRQ)
+ && (state->port != 0))
+ state->irq = detect_uart_irq(state);
printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
state->line,
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
@@ -3462,10 +3190,14 @@ int register_serial(struct serial_struct *req)
printk("register_serial(): autoconfig failed\n");
return -1;
}
+ restore_flags(flags);
+
+ if ((state->flags & ASYNC_AUTO_IRQ) && (state->port != 0))
+ state->irq = detect_uart_irq(state);
+
printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n",
state->line, state->port, state->irq,
uart_config[state->type].name);
- restore_flags(flags);
return state->line;
}
@@ -3705,7 +3437,7 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
* Divisor, bytesize and parity
*/
ser = rs_table + co->index;
- quot = BASE_BAUD / baud;
+ quot = ser->baud_base / baud;
cval = cflag & (CSIZE | CSTOPB);
#if defined(__powerpc__) || defined(__alpha__)
cval >>= 8;
@@ -3721,12 +3453,12 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
* Disable UART interrupts, set DTR and RTS high
* and set speed.
*/
- outb(0, ser->port + UART_IER);
- outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */
outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */
outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */
outb(cval, ser->port + UART_LCR); /* reset DLAB */
+ outb(0, ser->port + UART_IER);
+ outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
/*
* If we read 0xff from the LSR, there is no UART here.
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 67aeafc47..31fa5ab50 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -52,7 +52,6 @@
#ifdef CONFIG_PCI
#include <linux/pci.h>
-#include <linux/bios32.h>
#endif
/*****************************************************************************/
@@ -466,7 +465,7 @@ static inline int stl_initech(stlbrd_t *brdp);
#ifdef CONFIG_PCI
static inline int stl_findpcibrds(void);
-static inline int stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char devnr);
+static inline int stl_initpcibrd(int brdtype, struct pci_dev *dev);
#endif
/*
@@ -2530,16 +2529,16 @@ __initfunc(static int stl_brdinit(stlbrd_t *brdp))
* configuration space.
*/
-static inline int stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char devnr)
+static inline int stl_initpcibrd(int brdtype, struct pci_dev *dev)
{
unsigned int bar[4];
stlbrd_t *brdp;
- int i, rc;
+ int i;
unsigned char irq;
#if DEBUG
printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n",
- brdtype, busnr, devnr);
+ brdtype, dev->bus->number, dev->devfn);
#endif
brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t));
@@ -2559,22 +2558,9 @@ static inline int stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char
* boards use these in different ways, so we just read in the whole
* lot and then figure out what is what later.
*/
- for (i = 0; (i < 4); i++) {
- rc = pcibios_read_config_dword(busnr, devnr,
- (PCI_BASE_ADDRESS_0 + (i * 0x4)), &bar[i]);
- if (rc) {
- printk("STALLION: failed to read BAR register %d "
- "from PCI board, errno=%x\n", i, rc);
- return(0);
- }
- }
-
- rc = pcibios_read_config_byte(busnr, devnr, PCI_INTERRUPT_LINE, &irq);
- if (rc) {
- printk("STALLION: failed to read INTERRUPT register "
- "from PCI board, errno=%x\n", rc);
- return(0);
- }
+ for (i = 0; (i < 4); i++)
+ bar[i] = dev->base_address[i];
+ irq = dev->irq;
#if DEBUG
printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
@@ -2620,24 +2606,18 @@ static inline int stl_initpcibrd(int brdtype, unsigned char busnr, unsigned char
static inline int stl_findpcibrds()
{
- unsigned char busnr, devnr;
- unsigned short class;
- int i, rc, brdtypnr;
+ struct pci_dev *dev = NULL;
+ int i, rc;
#if DEBUG
printk("stl_findpcibrds()\n");
#endif
- if (! pcibios_present())
+ if (! pci_present())
return(0);
- for (i = 0; (i < stl_nrpcibrds); i++) {
- for (brdtypnr = 0; ; brdtypnr++) {
-
- rc = pcibios_find_device(stl_pcibrds[i].vendid,
- stl_pcibrds[i].devid, brdtypnr, &busnr, &devnr);
- if (rc)
- break;
+ for (i = 0; (i < stl_nrpcibrds); i++)
+ while ((dev = pci_find_device(stl_pcibrds[i].vendid, stl_pcibrds[i].devid, dev))) {
/*
* Check that we can handle more boards...
@@ -2653,22 +2633,13 @@ static inline int stl_findpcibrds()
* Found a device on the PCI bus that has our vendor and
* device ID. Need to check now that it is really us.
*/
- rc = pcibios_read_config_word(busnr, devnr,
- PCI_CLASS_DEVICE, &class);
- if (rc) {
- printk("STALLION: failed to read class type "
- "from PCI board, errno=%x\n", rc);
- continue;
- }
- if (class == PCI_CLASS_STORAGE_IDE)
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
continue;
- rc = stl_initpcibrd(stl_pcibrds[i].brdtype, busnr,
- devnr);
+ rc = stl_initpcibrd(stl_pcibrds[i].brdtype, dev);
if (rc)
return(rc);
}
- }
return(0);
}
diff --git a/drivers/char/tga.c b/drivers/char/tga.c
index 4fe1676f3..7bab07023 100644
--- a/drivers/char/tga.c
+++ b/drivers/char/tga.c
@@ -24,7 +24,6 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/ioport.h>
-#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/console.h>
@@ -137,7 +136,7 @@ extern struct console vt_console_driver;
#define TGA_F_HEIGHT_PADDED 18
int tga_type;
-unsigned int tga_mem_base;
+unsigned long tga_mem_base;
unsigned long tga_fb_base;
unsigned long tga_regs_base;
unsigned int tga_bpp, tga_fb_width, tga_fb_height, tga_fb_stride;
@@ -472,15 +471,12 @@ __initfunc(int con_is_present(void))
__initfunc(void
tga_console_init(void))
{
- unsigned char pci_bus, pci_devfn;
- int status;
+ struct pci_dev *dev;
/*
* first, find the TGA among the PCI devices...
*/
- status = pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
- 0, &pci_bus, &pci_devfn);
- if (status == PCIBIOS_DEVICE_NOT_FOUND) {
+ if (! (dev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL))) {
/* PANIC!!! */
printk("tga_console_init: TGA not found!!! :-(\n");
return;
@@ -489,14 +485,12 @@ tga_console_init(void))
/*
* read BASE_REG_0 for memory address
*/
- pcibios_read_config_dword(pci_bus, pci_devfn,
- PCI_BASE_ADDRESS_0, &tga_mem_base);
- tga_mem_base &= ~15;
+ tga_mem_base = dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
#ifdef DEBUG
- printk("tga_console_init: mem_base 0x%x\n", tga_mem_base);
+ printk("tga_console_init: mem_base 0x%lx\n", tga_mem_base);
#endif /* DEBUG */
- tga_type = (readl((unsigned long)tga_mem_base) >> 12) & 0x0f;
+ tga_type = (readl(tga_mem_base) >> 12) & 0x0f;
if (tga_type != 0 && tga_type != 1 && tga_type != 3) {
printk("TGA type (0x%x) unrecognized!\n", tga_type);
return;
@@ -561,9 +555,8 @@ tga_init_video(void))
int i, j, temp;
unsigned char *cbp;
- tga_regs_base = ((unsigned long)tga_mem_base + TGA_REGS_OFFSET);
- tga_fb_base =
- ((unsigned long)tga_mem_base + fb_offset_presets[tga_type]);
+ tga_regs_base = (tga_mem_base + TGA_REGS_OFFSET);
+ tga_fb_base = (tga_mem_base + fb_offset_presets[tga_type]);
/* first, disable video timing */
TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 364c5602e..bf2e642c4 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -66,6 +66,7 @@
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
#include <linux/file.h>
#include <linux/console.h>
#include <linux/timer.h>
@@ -130,12 +131,13 @@ static int tty_fasync(struct file * filp, int on);
/*
* This routine returns the name of tty.
*/
+#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
+ (tty)->driver.name_base)
+
char *tty_name(struct tty_struct *tty, char *buf)
{
if (tty)
- sprintf(buf, "%s%d", tty->driver.name,
- MINOR(tty->device) - tty->driver.minor_start +
- tty->driver.name_base);
+ sprintf(buf, "%s%d", tty->driver.name, TTY_NUMBER(tty));
else
strcpy(buf, "NULL tty");
return buf;
@@ -1209,7 +1211,7 @@ retry_open:
if (device == PTMX_DEV) {
/* find a free pty. */
struct tty_driver *driver = tty_drivers;
- int minor;
+ int minor, line;
/* find the pty driver */
for (driver=tty_drivers; driver; driver=driver->next)
@@ -1229,6 +1231,8 @@ retry_open:
return -EIO; /* no free ptys */
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+ line = minor - driver->minor_start;
+ devpts_pty_new(line, MKDEV(driver->other->major, line+driver->other->minor_start));
noctty = 1;
goto init_dev_done;
}
@@ -1284,9 +1288,17 @@ init_dev_done:
tty->pgrp = current->pgrp;
}
if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) &&
- (tty->driver.subtype == SERIAL_TYPE_CALLOUT)) {
- printk("Warning, %s opened, is a deprecated tty "
- "callout device\n", tty_name(tty, buf));
+ (tty->driver.subtype == SERIAL_TYPE_CALLOUT) &&
+ (tty->count == 1)) {
+ static int nr_warns = 0;
+ if (nr_warns < 5) {
+ printk(KERN_WARNING "tty_io.c: "
+ "process %d (%s) used obsolete /dev/%s - "
+ "update software to use /dev/ttyS%d\n",
+ current->pid, current->comm,
+ tty_name(tty, buf), TTY_NUMBER(tty));
+ nr_warns++;
+ }
}
return 0;
}
diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c
new file mode 100644
index 000000000..a942985c2
--- /dev/null
+++ b/drivers/char/tuner.c
@@ -0,0 +1,269 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+#include "i2c.h"
+#include <linux/videodev.h>
+
+#include "tuner.h"
+
+int debug = 0; /* insmod parameter */
+int type = 0; /* tuner type */
+
+#define dprintk if (debug) printk
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(type,"i");
+
+struct tuner
+{
+ struct i2c_bus *bus; /* where is our chip */
+ int addr;
+
+ int type; /* chip type */
+ int freq; /* keep track of the current settings */
+ int radio;
+};
+
+/* ---------------------------------------------------------------------- */
+
+struct tunertype
+{
+ char *name;
+ unsigned char Vendor;
+ unsigned char Type;
+
+ unsigned short thresh1; /* frequency Range for UHF,VHF-L, VHF_H */
+ unsigned short thresh2;
+ unsigned char VHF_L;
+ unsigned char VHF_H;
+ unsigned char UHF;
+ unsigned char config;
+ unsigned char I2C;
+ unsigned short IFPCoff;
+};
+
+/*
+ * The floats in the tuner struct are computed at compile time
+ * by gcc and cast back to integers. Thus we don't violate the
+ * "no float in kernel" rule.
+ */
+static struct tunertype tuners[] = {
+ {"Temic PAL", TEMIC, PAL,
+ 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623},
+ {"Philips PAL_I", Philips, PAL_I,
+ 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623},
+ {"Philips NTSC", Philips, NTSC,
+ 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732},
+ {"Philips SECAM", Philips, SECAM,
+ 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623},
+ {"NoTuner", NoTuner, NOTUNER,
+ 0 ,0 ,0x00,0x00,0x00,0x00,0x00,000},
+ {"Philips PAL", Philips, PAL,
+ 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623},
+ {"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},
+};
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_getstatus (struct tuner *t)
+{
+ return i2c_read(t->bus,t->addr+1);
+}
+
+#define TUNER_POR 0x80
+#define TUNER_FL 0x40
+#define TUNER_AFC 0x07
+
+static int tuner_islocked (struct tuner *t)
+{
+ return (tuner_getstatus (t) & TUNER_FL);
+}
+
+static int tuner_afcstatus (struct tuner *t)
+{
+ return (tuner_getstatus (t) & TUNER_AFC) - 2;
+}
+
+
+static void set_tv_freq(struct tuner *t, int freq)
+{
+ unsigned long flags;
+ u8 config;
+ u16 div;
+ struct tunertype *tun=&tuners[t->type];
+
+ if (freq < tun->thresh1)
+ config = tun->VHF_L;
+ else if (freq < tun->thresh2)
+ config = tun->VHF_H;
+ else
+ config = tun->UHF;
+
+ div=freq + (int)(16*38.9);
+ div&=0x7fff;
+
+ LOCK_I2C_BUS(t->bus);
+ if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
+ printk("tuner: i2c i/o error #1\n");
+ } else {
+ if (i2c_write(t->bus, t->addr, tun->config, config, 1))
+ printk("tuner: i2c i/o error #2\n");
+ }
+ UNLOCK_I2C_BUS(t->bus);
+}
+
+static void set_radio_freq(struct tuner *t, int freq)
+{
+ unsigned long flags;
+ u8 config;
+ u16 div;
+ struct tunertype *tun=&tuners[type];
+
+ config = 0xa5;
+ div=freq + (int)(16*10.7);
+ div&=0x7fff;
+
+ LOCK_I2C_BUS(t->bus);
+ if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) {
+ printk("tuner: i2c i/o error #1\n");
+ } else {
+ if (i2c_write(t->bus, t->addr, tun->config, config, 1))
+ printk("tuner: i2c i/o error #2\n");
+ }
+ if (debug) {
+ UNLOCK_I2C_BUS(t->bus);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/10;
+ schedule();
+ LOCK_I2C_BUS(t->bus);
+
+ if (tuner_islocked (t))
+ printk ("tuner: PLL locked\n");
+ else
+ printk ("tuner: PLL not locked\n");
+
+ printk ("tuner: AFC: %d\n", tuner_afcstatus (t));
+ }
+ UNLOCK_I2C_BUS(t->bus);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int tuner_attach(struct i2c_device *device)
+{
+ struct tuner *t;
+
+ /*
+ * For now we only try and attach these tuners to the BT848
+ * bus. This same module will however work different species
+ * of card using these chips. Just change the constraints
+ * (i2c doesn't have a totally clash free 'address' space)
+ */
+
+ if(device->bus->id!=I2C_BUSID_BT848)
+ return -EINVAL;
+
+ device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
+ if (NULL == t)
+ return -ENOMEM;
+ memset(t,0,sizeof(struct tuner));
+ strcpy(device->name,"tuner");
+ t->bus = device->bus;
+ t->addr = device->addr;
+ t->type = type;
+ dprintk("tuner: type is %d (%s)\n",t->type,tuners[t->type].name);
+
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int tuner_detach(struct i2c_device *device)
+{
+ struct tuner *t = (struct tuner*)device->data;
+ kfree(t);
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static int tuner_command(struct i2c_device *device,
+ unsigned int cmd, void *arg)
+{
+ struct tuner *t = (struct tuner*)device->data;
+ int *iarg = (int*)arg;
+
+ switch (cmd)
+ {
+ case TUNER_SET_TYPE:
+ t->type = *iarg;
+ dprintk("tuner: type set to %d (%s)\n",
+ t->type,tuners[t->type].name);
+ break;
+
+ case TUNER_SET_TVFREQ:
+ dprintk("tuner: tv freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_tv_freq(t,*iarg);
+ t->radio = 0;
+ t->freq = *iarg;
+ break;
+
+ case TUNER_SET_RADIOFREQ:
+ dprintk("tuner: radio freq set to %d.%02d\n",
+ (*iarg)/16,(*iarg)%16*100/16);
+ set_radio_freq(t,*iarg);
+ t->radio = 1;
+ t->freq = *iarg;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_tuner =
+{
+ "tuner", /* name */
+ I2C_DRIVERID_TUNER, /* ID */
+ 0xc0, 0xce, /* addr range */
+
+ tuner_attach,
+ tuner_detach,
+ tuner_command
+};
+
+#ifdef MODULE
+int init_module(void)
+#else
+int msp3400c_init(void)
+#endif
+{
+ i2c_register_driver(&i2c_driver_tuner);
+ return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+ i2c_unregister_driver(&i2c_driver_tuner);
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/char/tuner.h b/drivers/char/tuner.h
index e3e7b889f..3fb77de47 100644
--- a/drivers/char/tuner.h
+++ b/drivers/char/tuner.h
@@ -42,19 +42,8 @@
#define TEMIC 2
#define Sony 3
-struct tunertype {
- char *name;
- unchar Vendor;
- unchar Type;
-
- ushort thresh1; /* frequency Range for UHF,VHF-L, VHF_H */
- ushort thresh2;
- unchar VHF_L;
- unchar VHF_H;
- unchar UHF;
- unchar config;
- unchar I2C;
- ushort IFPCoff;
-};
-#endif
+#define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */
+#define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */
+#define TUNER_SET_RADIOFREQ _IOW('t',3,int) /* set radio freq */
+#endif
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index 9fd8b17f1..e9566da53 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -39,6 +39,9 @@ static struct video_device *video_device[VIDEO_NUM_DEVICES];
#ifdef CONFIG_VIDEO_BT848
extern int init_bttv_cards(struct video_init *);
#endif
+#ifdef CONFIG_VIDEO_SAA5249
+extern int init_saa_5249(struct video_init *);
+#endif
#ifdef CONFIG_VIDEO_CQCAM
extern int init_colour_qcams(struct video_init *);
#endif
@@ -50,6 +53,9 @@ static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
{"bttv", init_bttv_cards},
#endif
+#ifdef CONFIG_VIDEO_SAA5249
+ {"saa5249", init_saa_5249},
+#endif
#ifdef CONFIG_VIDEO_CQCAM
{"c-qcam", init_colour_qcams},
#endif
@@ -57,7 +63,7 @@ static struct video_init video_init_list[]={
{"bw-qcam", init_bw_qcams},
#endif
#ifdef CONFIG_VIDEO_PMS
- {"PMS", init_pms_cards}, /* not defined anywhere */
+ {"PMS", init_pms_cards},
#endif
{"end", NULL}
};
@@ -74,6 +80,8 @@ static ssize_t video_read(struct file *file,
return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
}
+
+
/*
* Write for now does nothing. No reason it shouldnt do overlay setting
* for some boards I guess..
@@ -162,18 +170,51 @@ static int video_ioctl(struct inode *inode, struct file *file,
/*
* We need to do MMAP support
*/
+
+
+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)];
+ if(vfl->mmap)
+ return vfl->mmap(vfl, (char *)vma->vm_start,
+ (unsigned long)(vma->vm_end-vma->vm_start));
+ return -EINVAL;
+}
/*
* Video For Linux device drivers request registration here.
*/
-int video_register_device(struct video_device *vfd)
+int video_register_device(struct video_device *vfd, int type)
{
int i=0;
- int base=0;
+ int base;
int err;
+ int end;
+
+ switch(type)
+ {
+ case VFL_TYPE_GRABBER:
+ base=0;
+ end=64;
+ break;
+ case VFL_TYPE_VTX:
+ base=192;
+ end=224;
+ break;
+ case VFL_TYPE_VBI:
+ base=224;
+ end=240;
+ break;
+ case VFL_TYPE_RADIO:
+ base=64;
+ end=128;
+ break;
+ default:
+ return -1;
+ }
- for(i=base;i<base+VIDEO_NUM_DEVICES;i++)
+ for(i=base;i<end;i++)
{
if(video_device[i]==NULL)
{
@@ -216,7 +257,7 @@ static struct file_operations video_fops=
NULL, /* readdir */
NULL, /* poll */
video_ioctl,
- NULL, /* mmap */
+ video_mmap,
video_open,
video_release
};
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 12924d2f5..6316be514 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -1188,20 +1188,14 @@ void complete_change_console(unsigned int new_console)
#ifdef CONFIG_SUN_CONSOLE
if (old_vc_mode != vt_cons[new_console]->vc_mode)
{
- extern void set_cursor(int currcons);
- extern void hide_cursor(void);
-
if (old_vc_mode == KD_GRAPHICS)
{
- extern void sun_clear_margin(void);
- extern void render_screen(void);
-
- sun_clear_margin();
- render_screen();
- set_cursor(fg_console);
+ suncons_ops.clear_margin();
+ suncons_ops.render_screen();
+ suncons_ops.set_cursor(fg_console);
}
else
- hide_cursor();
+ suncons_ops.hide_cursor();
}
#endif
/*