diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-12 23:15:27 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-12 23:15:27 +0000 |
commit | ae38fd1e4c98588314a42097c5a5e77dcef23561 (patch) | |
tree | f9f10c203bb9e5fbad4810d1f8774c08dfad20ff /drivers/char | |
parent | 466a823d79f41d0713b272e48fd73e494b0588e0 (diff) |
Merge with Linux 2.3.50.
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Config.in | 4 | ||||
-rw-r--r-- | drivers/char/Makefile | 20 | ||||
-rw-r--r-- | drivers/char/agp/agp.h | 1 | ||||
-rw-r--r-- | drivers/char/agp/agpgart_be.c | 3 | ||||
-rw-r--r-- | drivers/char/bttv.c | 1232 | ||||
-rw-r--r-- | drivers/char/bttv.h | 165 | ||||
-rw-r--r-- | drivers/char/console.c | 2 | ||||
-rw-r--r-- | drivers/char/epca.c | 5 | ||||
-rw-r--r-- | drivers/char/istallion.c | 4 | ||||
-rw-r--r-- | drivers/char/msp3400.c | 41 | ||||
-rw-r--r-- | drivers/char/ppdev.c | 10 | ||||
-rw-r--r-- | drivers/char/pty.c | 5 | ||||
-rw-r--r-- | drivers/char/sh-sci.c | 992 | ||||
-rw-r--r-- | drivers/char/sh-sci.h | 196 | ||||
-rw-r--r-- | drivers/char/stradis.c | 18 | ||||
-rw-r--r-- | drivers/char/tda9855.c | 455 | ||||
-rw-r--r-- | drivers/char/tda985x.c | 532 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 15 | ||||
-rw-r--r-- | drivers/char/tuner.c | 5 | ||||
-rw-r--r-- | drivers/char/videodev.c | 3 |
20 files changed, 2624 insertions, 1084 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 11f10b785..920546763 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -197,7 +197,9 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi comment 'Video Adapters' - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI + if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT + fi dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 9e3ffd93a..32c66c442 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -38,7 +38,7 @@ obj-y += tty_io.o n_tty.o tty_ioctl.o mem.o raw.o pty.o misc.o random.o export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o videodev.o \ - tty_io.o + tty_io.o bttv.o KEYMAP =defkeymap.o KEYBD =pc_keyb.o @@ -61,6 +61,20 @@ ifeq ($(ARCH),arm) SERIAL = endif +ifeq ($(ARCH),sh) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = + ifeq ($(CONFIG_SERIAL),y) + SERIAL = generic_serial.o sh-sci.o + else + ifeq ($(CONFIG_SERIAL),m) + SERIAL = sh-sci.o + endif + endif +endif + ifeq ($(CONFIG_DECSTATION),y) KEYBD = SERIAL = @@ -180,13 +194,11 @@ else endif endif -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o +obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tda8425.o tda985x.o tea6300.o ifeq ($(CONFIG_VIDEO_BT848),y) -L_I2C=y L_TUNERS=y else ifeq ($(CONFIG_VIDEO_BT848),m) - L_I2C=m L_TUNERS=m endif endif diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 31f481065..21a638fe2 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -226,6 +226,7 @@ struct agp_bridge_data { #define AMD_MMBASE 0x14 #define AMD_APSIZE 0xac #define AMD_MODECNTL 0xb0 +#define AMD_MODECNTL2 0xb2 #define AMD_GARTENABLE 0x02 /* In mmio region (16-bit register) */ #define AMD_ATTBASE 0x04 /* In mmio region (32-bit register) */ #define AMD_TLBFLUSH 0x0c /* In mmio region (32-bit register) */ diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index c478395f8..fc4312f64 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -1449,6 +1449,9 @@ static int amd_irongate_configure(void) /* Write the Sync register */ pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); + + /* Set indexing mode */ + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02); /* Write the enable register */ enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index c21198356..82f545ecc 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -3,7 +3,7 @@ Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 1999 Gerd Knorr <kraxel@goldbach.in-berlin.de> + (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.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 +20,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <linux/config.h> +#include <linux/version.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/errno.h> @@ -40,27 +42,28 @@ #include <linux/types.h> #include <linux/wrapper.h> #include <linux/interrupt.h> -#include <linux/version.h> #include <linux/kmod.h> #include <linux/vmalloc.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> -#include <linux/videodev.h> - +#ifdef LOCK_I2C_BUS +# error INSTALL ERROR +# error gcc uses the old, obsolete i2c.h include file. Please install the \ + new i2c stack. Please install it by patching the kernel, otherwise \ + gcc will not find the new header files. +#endif #include "bttv.h" #include "tuner.h" #define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define IDEBUG(x) /* Debug interrupt handler */ #define MIN(a,b) (((a)>(b))?(b):(a)) #define MAX(a,b) (((a)>(b))?(a):(b)) /* Anybody who uses more than four? */ #define BTTV_MAX 4 -static void bt848_set_risc_jmps(struct bttv *btv); +static void bt848_set_risc_jmps(struct bttv *btv, int state); static int bttv_num; /* number of Bt848s in use */ static struct bttv bttvs[BTTV_MAX]; @@ -74,7 +77,20 @@ MODULE_PARM(card,"1-4i"); MODULE_PARM(pll,"1-4i"); MODULE_PARM(bigendian,"i"); MODULE_PARM(fieldnr,"i"); +MODULE_PARM(verbose,"i"); +MODULE_PARM(debug,"i"); MODULE_PARM(autoload,"i"); +MODULE_PARM(gbuffers,"i"); +MODULE_PARM(gbufsize,"i"); + +EXPORT_SYMBOL(bttv_get_id); +EXPORT_SYMBOL(bttv_gpio_enable); +EXPORT_SYMBOL(bttv_read_gpio); +EXPORT_SYMBOL(bttv_write_gpio); +EXPORT_SYMBOL(bttv_get_gpio_queue); + +MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards"); +MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); #if defined(__sparc__) || defined(__powerpc__) static unsigned int bigendian=1; @@ -87,7 +103,15 @@ static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0}; static unsigned int fieldnr = 0; +static unsigned int verbose = 1; +static unsigned int debug = 0; +static unsigned int gbuffers = 2; +static unsigned int gbufsize = BTTV_MAX_FBUF; +#ifdef MODULE static unsigned int autoload = 1; +#else +static unsigned int autoload = 0; +#endif #define I2C_TIMING (0x7<<4) @@ -100,6 +124,101 @@ static unsigned int autoload = 1; #define BURSTOFFSET 76 +/* ----------------------------------------------------------------------- */ +/* Exported functions - for other modules which want to access the */ +/* gpio ports (IR for example) */ +/* see bttv.h for comments */ + +int bttv_get_id(unsigned int card) +{ + if (card >= bttv_num) { + return -1; + } + + return bttvs[card].type; +} + +int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + down(&btv->lock); + btaor(data, ~mask, BT848_GPIO_OUT_EN); + up(&btv->lock); + + return 0; +} + +int bttv_read_gpio(unsigned int card, unsigned long *data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + if(btv->shutdown) { + return -ENODEV; + } + + down(&btv->lock); + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because we set direct input on init */ + + *data = btread(BT848_GPIO_DATA); + + up(&btv->lock); + + return 0; +} + +int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return -EINVAL; + } + + btv = &bttvs[card]; + + down(&btv->lock); + +/* prior setting BT848_GPIO_REG_INP is (probably) not needed + because direct input is set on init */ + + btaor(data & mask, ~mask, BT848_GPIO_DATA); + + up(&btv->lock); + + return 0; +} + +WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card) +{ + struct bttv *btv; + + if (card >= bttv_num) { + return NULL; + } + + btv = &bttvs[card]; + + if (bttvs[card].shutdown) { + return NULL; + } + + return &btv->gpioq; +} + /*******************************/ /* Memory management functions */ /*******************************/ @@ -176,11 +295,11 @@ static inline unsigned long kvirt_to_pa(unsigned long adr) return ret; } -static void * rvmalloc(unsigned long size) +static void * rvmalloc(signed long size) { void * mem; unsigned long adr, page; - + mem=vmalloc(size); if (mem) { @@ -197,7 +316,7 @@ static void * rvmalloc(unsigned long size) return mem; } -static void rvfree(void * mem, unsigned long size) +static void rvfree(void * mem, signed long size) { unsigned long adr, page; @@ -227,7 +346,7 @@ static void rvfree(void * mem, unsigned long size) static int fbuffer_alloc(struct bttv *btv) { if(!btv->fbuffer) - btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); else printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", btv->nr); @@ -320,7 +439,8 @@ static int attach_inform(struct i2c_client *client) } if (btv->tuner_type != -1) call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); - printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); + if (verbose) + printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); return 0; } @@ -328,8 +448,9 @@ static int detach_inform(struct i2c_client *client) { struct bttv *btv = (struct bttv*)client->adapter->data; int i; - - printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); + + if (verbose) + printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); for (i = 0; i < I2C_CLIENTS_MAX; i++) { if (NULL != btv->i2c_clients[i] && btv->i2c_clients[i]->driver->id == client->driver->id) { @@ -395,19 +516,20 @@ static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) { unsigned char buffer = 0; - if (NULL != probe_for) + if (verbose && NULL != probe_for) printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", btv->nr,probe_for,addr); btv->i2c_client.addr = addr >> 1; if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { - if (NULL != probe_for) - printk("not found\n"); - else + if (NULL != probe_for) { + if (verbose) + printk("not found\n"); + } else printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", btv->nr,addr); return -1; } - if (NULL != probe_for) + if (verbose && NULL != probe_for) printk("found\n"); return buffer; } @@ -481,31 +603,70 @@ hauppauge_tuner[] = { TUNER_PHILIPS_PAL, "Philips FM1216" }, { TUNER_ABSENT, "Philips FM1216MF" }, { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_ABSENT, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_PAL, "Temic 4006FH5" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_ABSENT, "Temic 4039FR5" }, + { TUNER_ABSENT, "Philips FQ1216 ME" }, + { TUNER_TEMIC_PAL_I, "Temic 4066FY5" }, + { TUNER_ABSENT, "Philips TD1536" }, + { TUNER_ABSENT, "Philips TD1536D" }, + { TUNER_ABSENT, "Philips FMR1236" }, + { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Temic 4006FN5" }, + { TUNER_ABSENT, "Temic 4009FR5" }, + { TUNER_ABSENT, "Temic 4046FM5" }, }; static void hauppauge_eeprom(struct bttv *btv) { - readee(btv, eeprom_data, 0xa0); if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; - printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, - hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); + if (verbose) + printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, + hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); } } static void -hauppauge_msp_reset(struct bttv *btv) +hauppauge_boot_msp34xx(struct bttv *btv) { - /* Reset the MSP on some Hauppauge cards */ + int i; + + /* reset/enable the MSP on some Hauppauge cards */ /* Thanks to Kyösti Mälkki (kmalkki@cc.hut.fi)! */ - /* Can this hurt cards without one? What about Miros with MSP? */ btaor(32, ~32, BT848_GPIO_OUT_EN); btaor(0, ~32, BT848_GPIO_DATA); udelay(2500); btaor(32, ~32, BT848_GPIO_DATA); - /* btaor(0, ~32, BT848_GPIO_OUT_EN); */ + + if (verbose) + printk("bttv%d: Hauppauge msp34xx: reset line init\n",btv->nr); + + /* look if the msp3400 driver is already registered */ + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] != NULL && + btv->i2c_clients[i]->driver->id == I2C_DRIVERID_MSP3400) { + return; + } + } + + /* if not: look for the chip ... */ + if (I2CRead(btv, I2C_MSP3400, "MSP34xx")) { + /* ... if found re-register to trigger a i2c bus rescan, */ + /* this time with the msp34xx chip activated */ + i2c_bit_del_bus(&btv->i2c_adap); + i2c_bit_add_bus(&btv->i2c_adap); + } } @@ -528,7 +689,15 @@ static void init_PXC200(struct bttv *btv) /* GPIO inputs are pulled up, so no need to drive * reset pin any longer */ btwrite(0,BT848_GPIO_OUT_EN); - + + /* we could/should try and reset/control the AD pots? but + right now we simply turned off the crushing. Without + this the AGC drifts drifts + remember the EN is reverse logic --> + setting BT848_ADC_AGC_EN disable the AGC + tboult@eecs.lehigh.edu + */ + btwrite(BT848_ADC_RESERVED|BT848_ADC_AGC_EN, BT848_ADC); /* Initialise MAX517 DAC */ printk(KERN_INFO "Setting DAC reference voltage level ...\n"); @@ -555,19 +724,34 @@ static struct VENDOR { int id; char *name; } vendors[] = { - { 0x0070, "Hauppauge" }, - { 0x144f, "Askey" }, + { 0x0001, "ATI Technologies Inc" }, + { 0x10b4, "STB Systems Inc" }, + { 0x13eb, "Hauppauge Computer Works Inc" }, + { 0x1461, "Avermedia" }, + { 0x1850, "Chronos" }, + { 0x1852, "Typhoon" }, + { 0x3000, "Askey" }, + { 0x3002, "Askey" }, + { 0x6606, "Leadtek" }, { -1, NULL } }; static struct CARD { - int id; int vid; + int id; int cardnr; char *name; } cards[] = { - { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV Theater" }, - { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" }, + { 0x0001, 0x1002, BTTV_HAUPPAUGE878, "TV Wonder" }, + { 0x10b4, 0x2636, BTTV_HAUPPAUGE878, "???" }, + { 0x13eb, 0x0070, BTTV_HAUPPAUGE878, "WinTV" }, + { 0x1461, 0x0002, BTTV_AVERMEDIA98, "TVCapture 98" }, + { 0x1850, 0x1851, BTTV_CHRONOS_VS2, "Video Shuttle II" }, + { 0x1852, 0x1852, BTTV_TYPHOON_TVIEW, "TView TV/FM Tuner" }, + { 0x3000, 0x14ff, BTTV_MAGICTVIEW061, "TView 99" }, + { 0x3002, 0x144f, BTTV_MAGICTVIEW061, "Magic TView" }, + { 0x3002, 0x14ff, BTTV_PHOEBE_TVMAS, "TV Master" }, + { 0x6606, 0x217d, BTTV_WINFAST2000, "WinFast TV 2000" }, { -1, -1, -1, NULL } }; @@ -594,7 +778,7 @@ struct tvcard static struct tvcard tvcards[] = { /* 0x00 */ - { "unknown", + { " *** UNKNOWN *** ", 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, 1,1,1,1,0 }, { "MIRO PCTV", @@ -614,7 +798,7 @@ static struct tvcard tvcards[] = 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, 1,1,1,1,0 }, { "AVerMedia TVPhone", - 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0},0, + 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 4,11,11, 0},0, 1,1,1,1,0 }, { "MATRIX-Vision MV-Delta", 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, @@ -713,16 +897,32 @@ static struct tvcard tvcards[] = { "Terratec TerraTValue", 3, 1, 0, 2, 0xf00, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0, 1,1,1,1,0 }, + { "Leadtek WinFast 2000", + 3, 1, 0, 2, 0xfff000, { 2, 3, 1, 1,0}, + { 0x621000,0x620100,0x621100,0x620000,0xE210000,0x620000},0, + 1,1,1,1,1 }, + { "Chronos Video Shuttle II", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0, 0x1000, 0x1000, 0x0800},0, + 1,1,1,1,0 }, + + { "Typhoon TView TV/FM Tuner", + 3, 3, 0, 2, 0x1800, { 2, 3, 1, 1}, { 0, 0x800, 0, 0, 0x1800, 0 },0, + 1,1,1,1,0 }, + { "PixelView PlayTV pro", + 3, 1, 0, 2, 0xff, { 2, 3, 1, 1 }, + { 0x21, 0x20, 0x24, 0x2c, 0x29, 0x29 }, 0 } }; #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) static void -dump_eeprom(struct bttv *btv, int addr) +dump_eeprom(struct bttv *btv,int addr) { - int i,id1,id2,n1,n2; + int i; + if (verbose < 2) + return; + /* for debugging: dump eeprom to syslog */ printk(KERN_DEBUG "bttv%d: dump eeprom @ 0x%02x\n",btv->nr,addr); - readee(btv, eeprom_data,addr); for (i = 0; i < 256;) { printk(KERN_DEBUG " %02x:",i); do { @@ -730,35 +930,47 @@ dump_eeprom(struct bttv *btv, int addr) } while (i % 16); printk("\n"); } - id1 = (eeprom_data[252] << 8) | (eeprom_data[253]); - id2 = (eeprom_data[254] << 8) | (eeprom_data[255]); - if (id1 != 0 && id1 != 0xffff && - id2 != 0 && id2 != 0xffff) { - n1 = -1; - n2 = -1; - for (i = 0; vendors[i].id != -1; i++) - if (vendors[i].id == id2) - n2 = i; - for (i = 0; cards[i].id != -1; i++) - if (cards[i].id == id1 && - cards[i].vid == id2) - n1 = i; - if (n1 != -1 && n2 != -1) { - printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", - cards[n1].name,id1,vendors[n2].name,id2); - printk(KERN_INFO " => card=%d (%s)\n", - cards[n1].cardnr,tvcards[cards[n1].cardnr].name); -#if 1 - /* not yet, but that's the plan for autodetect... */ - btv->type = cards[n1].cardnr; -#endif - } else { - printk(KERN_INFO " id: %s (0x%04x), vendor: %s (0x%04x)\n", - (n1 != -1) ? cards[n1].name : "unknown", id1, - (n2 != -1) ? vendors[n2].name : "unknown", id2); - printk(KERN_INFO " please mail card type, id + vendor to "); - printk(" kraxel@goldbach.in-berlin.de\n"); - } +} + +static int +idcard_eeprom(struct bttv *btv) +{ + int i,id1,id2,n1,n2; + + id1 = (eeprom_data[254] << 8) | (eeprom_data[255]); + id2 = (eeprom_data[252] << 8) | (eeprom_data[253]); + if (id1 == 0 || id1 == 0xffff || + id2 == 0 || id2 == 0xffff) + return -1; + + /* look for the card */ + n1 = -1; n2 = -1; + for (i = 0; vendors[i].id != -1; i++) + if (vendors[i].id == id2) + n2 = i; + for (i = 0; cards[i].id != -1; i++) + if (cards[i].id == id1 && + cards[i].vid == id2) + n1 = i; + + if (n1 != -1 && n2 != -1) { + /* found it */ + printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n", + btv->nr,cards[n1].name,id1,vendors[n2].name,id2); + if (verbose) + printk(KERN_INFO "bttv%d: => card=%d (%s)\n", + btv->nr,cards[n1].cardnr, + tvcards[cards[n1].cardnr].name); + return cards[n1].cardnr; + } else { + /* 404 */ + printk(KERN_INFO "bttv%d: id: %s (0x%04x), vendor: %s (0x%04x)\n", + btv->nr, "unknown", id1, + (n2 != -1) ? vendors[n2].name : "unknown", id2); + printk(KERN_INFO "please mail id + vendor, board name and " + "the correct card= insmod option to " + "kraxel@goldbach.in-berlin.de\n"); + return -1; } } @@ -810,21 +1022,6 @@ extern inline void bt848_dma(struct bttv *btv, uint state) } -static void bt848_cap(struct bttv *btv, uint state) -{ - if (state) - { - btv->cap|=3; - bt848_set_risc_jmps(btv); - } - else - { - btv->cap&=~3; - bt848_set_risc_jmps(btv); - } -} - - /* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/ /* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C @@ -885,9 +1082,10 @@ static int set_pll(struct bttv *btv) /* printk("bttv%d: PLL: no change required\n",btv->nr); */ return 1; } - - printk("bttv%d: PLL: %d => %d ... ",btv->nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); + + if (verbose) + printk("bttv%d: PLL: %d => %d ... ",btv->nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); @@ -907,13 +1105,15 @@ static int set_pll(struct bttv *btv) { btwrite(0x08,BT848_TGCTRL); btv->pll.pll_current = btv->pll.pll_ofreq; - printk("ok\n"); + if (verbose) + printk("ok\n"); return 1; } mdelay(10); } btv->pll.pll_current = 0; - printk("oops\n"); + if (verbose) + printk("oops\n"); return -1; } @@ -1010,10 +1210,9 @@ static void make_vbitab(struct bttv *btv) unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; - DEBUG(printk(KERN_DEBUG "vbiodd: 0x%lx\n",(long)btv->vbi_odd)); - DEBUG(printk(KERN_DEBUG "vbievn: 0x%lx\n",(long)btv->vbi_even)); - DEBUG(printk(KERN_DEBUG "po: 0x%lx\n",(long)po)); - DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); + if (debug) + printk("bttv%d: vbi: po=%08lx pe=%08lx\n", + btv->nr,virt_to_bus(po), virt_to_bus(pe)); *(po++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(po++)=0; for (i=0; i<16; i++) @@ -1036,11 +1235,11 @@ static void make_vbitab(struct bttv *btv) DEBUG(printk(KERN_DEBUG "pe: 0x%lx\n",(long)pe)); } -int fmtbppx2[16] = { +static int fmtbppx2[16] = { 8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0 }; -int palette2fmt[] = { +static int palette2fmt[] = { 0, BT848_COLOR_FMT_Y8, BT848_COLOR_FMT_RGB8, @@ -1082,7 +1281,7 @@ static int make_rawrisctab(struct bttv *btv, unsigned int *ro, *(ro++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); *(ro++)=cpu_to_le32(kvirt_to_bus(vadr)); *(re++)=cpu_to_le32(BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL); - *(re++)=cpu_to_le32(kvirt_to_bus(vadr+BTTV_MAX_FBUF/2)); + *(re++)=cpu_to_le32(kvirt_to_bus(vadr+gbufsize/2)); vadr+=bpl; } @@ -1108,6 +1307,9 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, unsigned long vadr=(unsigned long) vbuf; int shift, csize; + if (debug) + printk("bttv%d: prisc: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); switch(fmt) { @@ -1140,7 +1342,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, } cbadr=vadr+(width*height); cradr=cbadr+csize; - inter = (height>btv->win.cropheight/2) ? 1 : 0; + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0; @@ -1158,7 +1360,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, if (inter) rp= (line&1) ? &re : &ro; else - rp= (line>=height) ? &re : &ro; + rp= (line>=height) ? &ro : &re; if(line&lmask) @@ -1222,9 +1424,12 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, return make_rawrisctab(btv, ro, re, vbuf); if (palette>=VIDEO_PALETTE_PLANAR) return make_prisctab(btv, ro, re, vbuf, width, height, palette); - - - inter = (height>btv->win.cropheight/2) ? 1 : 0; + + if (debug) + printk("bttv%d: vrisc: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); + + inter = (height>tvnorms[btv->win.norm].sheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); @@ -1237,7 +1442,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, if (inter) rp= (line&1) ? &re : &ro; else - rp= (line>=height) ? &re : &ro; + rp= (line>=height) ? &ro : &re; bl=PAGE_SIZE-((PAGE_SIZE-1)&vadr); if (bpl<=bl) @@ -1335,32 +1540,31 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) { - int i, line, x, y, bpl, width, height, inter; + int i, line, x, y, bpl, width, height, inter, maxw; unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len; unsigned long adr; - unsigned char *clipmap, cbit, lastbit, outofmem; + unsigned char *clipmap, *clipline, cbit, lastbit, outofmem; - if (btv->win.use_yuv) { - /* yuv-to-offscreen (BT848_COLOR_FMT_YUY2) */ - bpp = 2; - bpl = btv->win.win2.pitch; - adr = btv->win.vidadr + btv->win.win2.start; - } else { - bpp=btv->win.bpp; - if (bpp==15) /* handle 15bpp as 16bpp in calculations */ - bpp++; - bpl=btv->win.bpl; - adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; - } + /* take care: bpp != btv->win.bpp is allowed here */ + bpp = fmtbppx2[btv->win.color_fmt&0xf]/2; + bpl=btv->win.bpl; + adr=btv->win.vidadr + btv->win.x * btv->win.bpp + btv->win.y * bpl; inter=(btv->win.interlace&1)^1; width=btv->win.width; height=btv->win.height; + if (debug) + printk("bttv%d: make_clip: pal=%d size=%dx%d, bpl=%d bpp=%d\n", + btv->nr,btv->picture.palette,width,height,bpl,bpp); if(width > 1023) width = 1023; /* sanity check */ if(height > 625) height = 625; /* sanity check */ - ro=btv->risc_odd; - re=btv->risc_even; + ro=btv->risc_scr_odd; + re=btv->risc_scr_even; + + if (debug) + printk("bttv%d: clip: ro=%08lx re=%08lx\n", + btv->nr,virt_to_bus(ro), virt_to_bus(re)); if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ @@ -1380,16 +1584,15 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) /* clip against viewing window AND screen so we do not have to rely on the user program */ - if (!btv->win.use_yuv) { - clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? - (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height,1024,768); - if (btv->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); - if (btv->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); - } + maxw = (bpl - btv->win.x * btv->win.bpp) / bpp; + clip_draw_rectangle(clipmap, (width > maxw) ? maxw : width, + 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=cpu_to_le32(0); @@ -1401,12 +1604,30 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) { y = line>>inter; rp= (line&1) ? &re : &ro; - lastbit=(clipmap[y<<7]&1); - for(x=dx=1,sx=0; x<=width && !outofmem; x++) { - cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7))); - if (x < width && !lastbit == !cbit) + clipline = clipmap + (y<<7); /* running pointers ... */ + lastbit = *clipline & 1; + for(x=dx=0,sx=0; x<=width && !outofmem;) { + if (0 == (x&7)) { + /* check bytes not bits if we can ... */ + if (lastbit) { + while (0xff==*clipline && x<width-8) { + x += 8; + dx += 8; + clipline++; + } + } else { + while (0x00==*clipline && x<width-8) { + x += 8; + dx += 8; + clipline++; + } + } + } + cbit = *clipline & (1<<(x&7)); + if (x < width && !lastbit == !cbit) { dx++; - else { /* generate the dma controller code */ + } else { + /* generate the dma controller code */ len = dx * bpp; flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0); flags |= ((!sx) ? BT848_RISC_SOL : 0); @@ -1420,11 +1641,14 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) lastbit=cbit; sx += dx; dx = 1; - if (ro - btv->risc_odd > RISCMEM_LEN/2 - 16) + if (ro - btv->risc_scr_odd>RISCMEM_LEN/2 - 16) outofmem++; - if (re - btv->risc_even > RISCMEM_LEN/2 - 16) + if (re - btv->risc_scr_even>RISCMEM_LEN/2 - 16) outofmem++; } + x++; + if (0 == (x&7)) + clipline++; } if ((!inter)||(line&1)) adr+=bpl; @@ -1475,29 +1699,25 @@ static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc, } -static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, - u16 fmt, int no_irq_context) +static void bt848_set_geo(struct bttv *btv, + int no_irq_context) { u16 vscale, hscale; u32 xsf, sr; - u16 hdelay, vdelay; - u16 hactive, vactive; + u16 ewidth, eheight, owidth, oheight; + u16 format, bswap; + u16 hdelay; + u16 hactive; u16 inter; u8 crop, vtc; struct tvnorm *tvn; unsigned long flags; - if (!width || !height) - return; - save_flags(flags); cli(); tvn=&tvnorms[btv->win.norm]; - btv->win.cropheight=tvn->sheight; - btv->win.cropwidth=tvn->swidth; - btwrite(tvn->adelay, BT848_ADELAY); btwrite(tvn->bdelay, BT848_BDELAY); btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); @@ -1508,59 +1728,84 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, if (no_irq_context) set_pll(btv); - btwrite(fmt, BT848_COLOR_FMT); - if (bigendian && - fmt == BT848_COLOR_FMT_RGB32) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_WSWAP_ODD | - BT848_COLOR_CTL_WSWAP_EVEN | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else if (bigendian && - (fmt == BT848_COLOR_FMT_RGB16 || - fmt == BT848_COLOR_FMT_RGB15)) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else { - btwrite(0x10, BT848_COLOR_CTL); - } - 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; - vdelay=btv->win.cropy+tvn->vdelay; - - xsf = (hactive*tvn->scaledtwidth)/btv->win.cropwidth; - hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + btv->win.interlace = (btv->win.height>tvn->sheight/2) ? 1 : 0; + + if (0 == btv->risc_cap_odd && + 0 == btv->risc_cap_even) { + /* overlay only */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->win.width; + eheight = btv->win.height; + format = btv->win.color_fmt; + bswap = btv->fb_color_ctl; + } else if (-1 != btv->gq_grab && + 0 == btv->risc_cap_odd && + !btv->win.interlace && + btv->scr_on) { + /* odd field -> overlay, even field -> capture */ + owidth = btv->win.width; + oheight = btv->win.height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = (btv->win.color_fmt & 0xf0) | + (btv->gbuf[btv->gq_grab].fmt & 0x0f); + bswap = btv->fb_color_ctl & 0x0a; + } else { + /* capture only */ + owidth = btv->gbuf[btv->gq_grab].width; + oheight = btv->gbuf[btv->gq_grab].height; + ewidth = btv->gbuf[btv->gq_grab].width; + eheight = btv->gbuf[btv->gq_grab].height; + format = btv->gbuf[btv->gq_grab].fmt; + bswap = 0; + inter = (btv->win.height>tvn->sheight/2) ? 0 : 1; + } - hdelay=tvn->hdelayx1+btv->win.cropx; - hdelay=(hdelay*hactive)/btv->win.cropwidth; - hdelay&=0x3fe; + inter = (oheight>tvn->sheight/2) ? 0 : 1; - sr=((btv->win.cropheight>>inter)*512)/height-512; + /* odd field */ + hactive=owidth; + xsf = (hactive*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*hactive)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/oheight-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; + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, tvn->sheight, + hdelay, tvn->vdelay, crop); + + /* even field */ + hactive=ewidth; + xsf = (hactive*tvn->scaledtwidth)/tvn->swidth; + hscale = ((tvn->totalwidth*4096UL)/xsf-4096); + hdelay = tvn->hdelayx1; + hdelay = (hdelay*hactive)/tvn->swidth; + hdelay &= 0x3fe; + sr=((tvn->sheight>>inter)*512)/eheight-512; + vscale=(0x10000UL-sr)&0x1fff; + crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| + ((tvn->sheight>>4)&0x30)|((tvn->vdelay>>2)&0xc0); + vscale |= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; + bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, tvn->sheight, + hdelay, tvn->vdelay, crop); - 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); + btwrite(format, BT848_COLOR_FMT); + btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); restore_flags(flags); } -int bpp2fmt[4] = { +static int bpp2fmt[4] = { BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 }; @@ -1569,14 +1814,31 @@ static void bt848_set_winsize(struct bttv *btv) { unsigned short format; - if (btv->win.use_yuv) { - /* yuv-to-offscreen */ - format = BT848_COLOR_FMT_YUY2; + if (btv->picture.palette > 0 && btv->picture.palette <= VIDEO_PALETTE_YUV422) { + /* format set by VIDIOCSPICT */ + format = palette2fmt[btv->picture.palette]; } else { + /* use default for the given color depth */ format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : bpp2fmt[(btv->win.bpp-1)&3]; } btv->win.color_fmt = format; + if (bigendian && + format == BT848_COLOR_FMT_RGB32) { + btv->fb_color_ctl = + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else if (bigendian && + (format == BT848_COLOR_FMT_RGB16 || + format == BT848_COLOR_FMT_RGB15)) { + btv->fb_color_ctl = + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN; + } else { + btv->fb_color_ctl = 0; + } /* RGB8 seems to be a 9x5x5 GRB color cube starting at * color 16. Why the h... can't they even mention this in the @@ -1590,38 +1852,8 @@ static void bt848_set_winsize(struct bttv *btv) else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - bt848_set_geo(btv, btv->win.width, btv->win.height, format,1); -} - -/* - * Set TSA5522 synthesizer frequency in 1/16 Mhz steps - */ - -#if 0 -static void set_freq(struct bttv *btv, unsigned short freq) -{ - int naudio; - int fixme = freq; /* XXX */ - /* int oldAudio = btv->audio; */ - - /* mute */ - AUDIO(AUDC_SWITCH_MUTE,0); - - /* tune */ - if (btv->radio) { - TUNER(TUNER_SET_RADIOFREQ,&fixme); - } else { - TUNER(TUNER_SET_TVFREQ,&fixme); - } - - if (btv->radio) { - AUDIO(AUDC_SET_RADIO,0); - } else { - AUDIO(AUDC_SET_TVNORM,&(btv->win.norm)); - AUDIO(AUDC_NEWCHANNEL,0); - } + bt848_set_geo(btv,1); } -#endif /* @@ -1639,30 +1871,19 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) if(fbuffer_alloc(btv)) return -ENOBUFS; } - if(btv->grabbing >= MAX_GBUFFERS) - return -ENOBUFS; - - /* - * No grabbing past the end of the buffer! - */ - - if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0) + + if(mp->frame >= gbuffers || mp->frame < 0) return -EINVAL; + if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED) + return -EBUSY; if(mp->height <0 || mp->width <0) return -EINVAL; - -/* This doesn´t work like this for NTSC anyway. - So, better check the total image size ... -*/ -/* - if(mp->height>576 || mp->width>768+BURSTOFFSET) - return -EINVAL; -*/ if (mp->format >= PALETTEFMT_MAX) return -EINVAL; + if (mp->height*mp->width*fmtbppx2[palette2fmt[mp->format]&0x0f]/2 - > BTTV_MAX_FBUF) + > gbufsize) return -EINVAL; if(-1 == palette2fmt[mp->format]) return -EINVAL; @@ -1677,41 +1898,40 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) * Ok load up the BT848 */ - vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame); -/* if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) - return -EAGAIN;*/ - ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0); + vbuf=(unsigned int *)(btv->fbuffer+gbufsize*mp->frame); + ro=btv->gbuf[mp->frame].risc; re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); - /* bt848_set_risc_jmps(btv); */ + + if (debug) + printk("bttv%d: cap vgrab: queue %d\n",btv->nr,mp->frame); cli(); - btv->frame_stat[mp->frame] = GBUFFER_GRABBING; - if (btv->grabbing) { - btv->gfmt_next=palette2fmt[mp->format]; - btv->gwidth_next=mp->width; - btv->gheight_next=mp->height; - btv->gro_next=virt_to_bus(ro); - btv->gre_next=virt_to_bus(re); - btv->grf_next=mp->frame; - } else { - btv->gfmt=palette2fmt[mp->format]; - btv->gwidth=mp->width; - btv->gheight=mp->height; - btv->gro=virt_to_bus(ro); - btv->gre=virt_to_bus(re); - btv->grf=mp->frame; - } - if (!(btv->grabbing++)) { + btv->gbuf[mp->frame].stat = GBUFFER_GRABBING; + btv->gbuf[mp->frame].fmt = palette2fmt[mp->format]; + btv->gbuf[mp->frame].width = mp->width; + btv->gbuf[mp->frame].height = mp->height; + btv->gbuf[mp->frame].ro = virt_to_bus(ro); + btv->gbuf[mp->frame].re = virt_to_bus(re); + +#if 1 + if (mp->height <= tvnorms[btv->win.norm].sheight/2 && + mp->format != VIDEO_PALETTE_RAW) + btv->gbuf[mp->frame].ro = 0; +#endif + + if (btv->gq_in == btv->gq_out) { if(mp->format>=VIDEO_PALETTE_COMPONENT) { btor(BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btor(BT848_VSCALE_COMB, BT848_O_VSCALE_HI); } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } + btv->gqueue[btv->gq_in++] = mp->frame; + btv->gq_in = btv->gq_in % MAX_GBUFFERS; + sti(); btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); - /* interruptible_sleep_on(&btv->capq); */ return 0; } @@ -1787,16 +2007,16 @@ static int bttv_open(struct video_device *dev, int flags) if (btv->user) goto out_unlock; - btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize); ret = -ENOMEM; if (!btv->fbuffer) goto out_unlock; - btv->grabbing = 0; - btv->grab = 0; - btv->lastgrab = 0; - for (i = 0; i < MAX_GBUFFERS; i++) - btv->frame_stat[i] = GBUFFER_UNUSED; + btv->gq_in = 0; + btv->gq_out = 0; + btv->gq_grab = -1; + for (i = 0; i < gbuffers; i++) + btv->gbuf[i].stat = GBUFFER_UNUSED; burst(0); btv->user++; @@ -1815,8 +2035,10 @@ static void bttv_close(struct video_device *dev) down(&btv->lock); btv->user--; - btv->cap&=~3; - bt848_set_risc_jmps(btv); + btv->scr_on = 0; + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); /* * A word of warning. At this point the chip @@ -1841,7 +2063,7 @@ static void bttv_close(struct video_device *dev) */ if(btv->fbuffer) - rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF); + rvfree((void *) btv->fbuffer, gbuffers*gbufsize); btv->fbuffer=0; up(&btv->lock); MOD_DEC_USE_COUNT; @@ -1901,7 +2123,9 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data) static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct bttv *btv=(struct bttv *)dev; - int i; + int i,ret; + + if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); switch (cmd) { case VIDIOCGCAP: @@ -2021,17 +2245,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCGPICT: { struct video_picture p=btv->picture; - if(btv->win.depth==8) - p.palette=VIDEO_PALETTE_HI240; - if(btv->win.depth==15) - p.palette=VIDEO_PALETTE_RGB555; - if(btv->win.depth==16) - p.palette=VIDEO_PALETTE_RGB565; - if(btv->win.depth==24) - p.palette=VIDEO_PALETTE_RGB24; - if(btv->win.depth==32) - p.palette=VIDEO_PALETTE_RGB32; - if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; @@ -2041,6 +2254,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) struct video_picture p; if(copy_from_user(&p, arg,sizeof(p))) return -EFAULT; + if (p.palette > PALETTEFMT_MAX) + return -EINVAL; down(&btv->lock); /* We want -128 to 127 we get 0-65535 */ bt848_bright(btv, (p.brightness>>8)-128); @@ -2059,7 +2274,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct video_window vw; struct video_clip *vcp = NULL; - int on; if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; @@ -2067,25 +2281,24 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if(vw.flags || vw.width < 16 || vw.height < 16) { down(&btv->lock); - bt848_cap(btv,0); + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return -EINVAL; - } + } if (btv->win.bpp < 4) { /* adjust and align writes */ vw.x = (vw.x + 3) & ~3; vw.width &= ~3; } down(&btv->lock); - btv->win.use_yuv=0; btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; btv->win.height=vw.height; - on=(btv->cap&3); - - bt848_cap(btv,0); + bt848_set_risc_jmps(btv,0); + bt848_set_winsize(btv); up(&btv->lock); @@ -2115,39 +2328,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) make_clip_tab(btv, vcp, vw.clipcount); if (vw.clipcount != 0) vfree(vcp); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); - up(&btv->lock); - return 0; - } - case VIDIOCSWIN2: - { - /* experimental -- right now it handles unclipped yuv data only */ - struct video_window2 vo; - __u32 fbsize; - int on; - - if(copy_from_user(&vo,arg,sizeof(vo))) - return -EFAULT; - - fbsize = btv->win.sheight * btv->win.bpl; - if (vo.start + vo.pitch*vo.height > fbsize) - return -EINVAL; - if (vo.palette != VIDEO_PALETTE_YUV422) - return -EINVAL; - - down(&btv->lock); - btv->win.use_yuv=1; - memcpy(&btv->win.win2,&vo,sizeof(vo)); - btv->win.width=vo.width; - btv->win.height=vo.height; - - on=(btv->cap&3); - bt848_cap(btv,0); - bt848_set_winsize(btv); - make_clip_tab(btv, NULL, 0); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return 0; } @@ -2174,13 +2355,14 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) return -EFAULT; if(btv->win.vidadr == 0) return -EINVAL; - if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0)) + if (btv->win.width==0 || btv->win.height==0) return -EINVAL; down(&btv->lock); - if(v==0) - bt848_cap(btv,0); - else - bt848_cap(btv,1); + if (v == 1 && btv->win.vidadr != 0) + btv->scr_on = 1; + if (v == 0) + btv->scr_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); return 0; } @@ -2217,9 +2399,19 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) btv->win.bpp=((v.depth+7)&0x38)/8; btv->win.depth=v.depth; btv->win.bpl=v.bytesperline; - - 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)); + + /* set sefault color format */ + switch (btv->win.bpp) { + case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; + case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; + case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; + case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; + case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; + } + + if (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_winsize(btv); up(&btv->lock); return 0; @@ -2273,19 +2465,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.step = 4096; } -#if 0 -#warning this should be handled by tda9855.c - else if (btv->audio_chip == TDA9850) { - unsigned char ALR1; - v.flags|=VIDEO_AUDIO_VOLUME; - ALR1 = I2CRead(btv, I2C_TDA9850|1); - v.mode = VIDEO_SOUND_MONO; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0; - v.volume = 32768; /* fixme */ - v.step = 4096; - } -#endif if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; @@ -2354,23 +2533,8 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) udelay(10); data &= ~WINVIEW_PT2254_STROBE; btwrite(data, BT848_GPIO_DATA); - -#if 0 -#warning this should be handled by tda9855.c - } else if (btv->audio_chip == TDA9850) { - unsigned char con3 = 0; - if (v.mode & VIDEO_SOUND_LANG1) - con3 = 0x80; /* sap */ - if (v.mode & VIDEO_SOUND_STEREO) - con3 = 0x40; /* stereo */ - I2CWrite(btv, I2C_TDA9850, - TDA9850_CON3, con3, 1); - if (v.flags & VIDEO_AUDIO_VOLUME) - I2CWrite(btv, I2C_TDA9850, - TDA9850_CON4, - (v.volume>>12) & 15, 1); -#endif } + btv->audio_dev=v; up(&btv->lock); return 0; @@ -2379,19 +2543,27 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCSYNC: if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; - switch (btv->frame_stat[i]) { + if (i < 0 || i >= gbuffers) + return -EINVAL; + switch (btv->gbuf[i].stat) { case GBUFFER_UNUSED: return -EINVAL; case GBUFFER_GRABBING: - while(btv->frame_stat[i]==GBUFFER_GRABBING) { + while(btv->gbuf[i].stat==GBUFFER_GRABBING) { + if (debug) + printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); interruptible_sleep_on(&btv->capq); if(signal_pending(current)) return -EINTR; } - /* fall */ + /* fall throuth */ case GBUFFER_DONE: - btv->frame_stat[i] = GBUFFER_UNUSED; - break; + case GBUFFER_ERROR: + ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; + if (debug) + printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); + btv->gbuf[i].stat = GBUFFER_UNUSED; + return ret; } return 0; @@ -2422,8 +2594,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) int ret; if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) return -EFAULT; - if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) - return -EBUSY; down(&btv->lock); ret = vgrab(btv, &vm); up(&btv->lock); @@ -2434,10 +2604,10 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct video_mbuf vm; memset(&vm, 0 , sizeof(vm)); - vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS; - vm.frames=MAX_GBUFFERS; - vm.offsets[0]=0; - vm.offsets[1]=BTTV_MAX_FBUF; + vm.size=gbufsize*gbuffers; + vm.frames=gbuffers; + for (i = 0; i < gbuffers; i++) + vm.offsets[i]=i*gbufsize; if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; @@ -2510,7 +2680,7 @@ static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) unsigned long start=(unsigned long) adr; unsigned long page,pos; - if (size>2*BTTV_MAX_FBUF) + if (size>gbuffers*gbufsize) return -EINVAL; if (!btv->fbuffer) { if(fbuffer_alloc(btv)) @@ -2623,8 +2793,8 @@ static int vbi_open(struct video_device *dev, int flags) down(&btv->lock); btv->vbip=VBIBUF_SIZE; - btv->cap|=0x0c; - bt848_set_risc_jmps(btv); + btv->vbi_on = 1; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); MOD_INC_USE_COUNT; @@ -2636,8 +2806,8 @@ static void vbi_close(struct video_device *dev) struct bttv *btv=(struct bttv *)(dev-2); down(&btv->lock); - btv->cap&=~0x0c; - bt848_set_risc_jmps(btv); + btv->vbi_on = 0; + bt848_set_risc_jmps(btv,-1); up(&btv->lock); MOD_DEC_USE_COUNT; @@ -2875,26 +3045,12 @@ static void init_tda9840(struct bttv *btv) 7a - external */ } - -#if 0 -#warning this should be handled by tda9855.c -static void init_tda9850(struct bttv *btv) -{ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ - I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ - I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); -} -#endif - /* Figure out card and tuner type */ static void idcard(int i) { struct bttv *btv = &bttvs[i]; + int type,eeprom = 0; btwrite(0, BT848_GPIO_OUT_EN); DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA))); @@ -2903,40 +3059,36 @@ static void idcard(int i) if (card[i] >= 0 && card[i] < TVCARDS) btv->type=card[i]; - /* 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, I2C_HAUPEE, "eeprom")>=0) - { - if(btv->id>849) - btv->type=BTTV_HAUPPAUGE878; - else + /* If we were asked to auto-detect, then do so! */ + if (btv->type == BTTV_UNKNOWN) { + + /* many bt878 cards have a eeprom @ 0xa0 => read ID + and try to identify it */ + if (I2CRead(btv, I2C_HAUPEE, "eeprom") >= 0) { + eeprom = 0xa0; + readee(btv,eeprom_data,0xa0); + dump_eeprom(btv,0xa0); /* DEBUG */ + type = idcard_eeprom(btv); + if (-1 != type) { + btv->type = type; + } else if (btv->id <= 849) { + /* for unknown bt848, assume old Hauppauge */ btv->type=BTTV_HAUPPAUGE; + } + /* STB cards have a eeprom @ 0xae */ } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) { btv->type=BTTV_STB; + } -#if 0 /* bad idea: 0xc0 is used for the tuner on _many_ boards */ - } else if (I2CRead(btv, I2C_VHX)>=0) { - btv->type=BTTV_VHX; -#endif - - } else { - if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */ +#if 0 + /* check for msp34xx */ + if (I2CRead(btv, 0x80, "msp3400")>=0) btv->type = BTTV_MIROPRO; else - btv->type = BTTV_MIRO; - } - } - -#if 1 - /* DEBUG: dump eeprom content if available */ - if (I2CRead(btv, 0xa0, "eeprom")>=0) { - dump_eeprom(btv,0xa0); - } + btv->type = BTTV_MIRO; #endif + } /* print which board we have found */ printk(KERN_INFO "bttv%d: model: ",btv->nr); @@ -2955,8 +3107,12 @@ static void idcard(int i) btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; } if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { - hauppauge_msp_reset(btv); + if (0xa0 != eeprom) { + eeprom = 0xa0; + readee(btv,eeprom_data,0xa0); + } hauppauge_eeprom(btv); + hauppauge_boot_msp34xx(btv); } if (btv->type == BTTV_MAXI) { /* PHILIPS FI1216MK2 tuner (PAL/SECAM) */ @@ -2973,7 +3129,11 @@ static void idcard(int i) btv->type == BTTV_CONFERENCETV || btv->type == BTTV_PIXVIEWPLAYTV || btv->type == BTTV_AVERMEDIA98 || - btv->type == BTTV_MAGICTVIEW061) { + btv->type == BTTV_MAGICTVIEW061 || + btv->type == BTTV_CHRONOS_VS2 || + btv->type == BTTV_TYPHOON_TVIEW || + btv->type == BTTV_PXELVWPLTVPRO || + btv->type == BTTV_WINFAST2000) { btv->pll.pll_ifreq=28636363; btv->pll.pll_crystal=BT848_IFORM_XT0; } @@ -3005,7 +3165,7 @@ static void idcard(int i) if (tvcards[btv->type].tda985x && I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { if (autoload) - request_module("tda9855"); + request_module("tda985x"); } if (tvcards[btv->type].tea63xx /* && @@ -3023,9 +3183,19 @@ static void idcard(int i) } -static void bt848_set_risc_jmps(struct bttv *btv) +static void bt848_set_risc_jmps(struct bttv *btv, int flags) { - int flags=btv->cap; + if (-1 == flags) { + /* defaults */ + flags = 0; + if (btv->scr_on) + flags |= 0x03; + if (btv->vbi_on) + flags |= 0x0c; + } + + if (debug) printk("bttv%d: set_risc_jmp %08lx:", + btv->nr,virt_to_bus(btv->risc_jmp)); /* Sync to start of odd field */ btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC @@ -3034,17 +3204,27 @@ static void bt848_set_risc_jmps(struct bttv *btv) /* Jump to odd vbi sub */ btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); - if (flags&8) + if (flags&8) { + if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); - else + } else { + if (debug) printk(" -----------"); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); + } /* Jump to odd sub */ btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); - if (flags&2) - btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd)); - else + if (0 != btv->risc_cap_odd) { + if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); + flags |= 3; + btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); + } else if (flags&2) { + if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); + btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); + } else { + if (debug) printk(" -----------"); btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); + } /* Sync to start of even field */ @@ -3054,22 +3234,34 @@ static void bt848_set_risc_jmps(struct bttv *btv) /* Jump to even vbi sub */ btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); - if (flags&4) + if (flags&4) { + if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); - else + } else { + if (debug) printk(" -----------"); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); + } /* Jump to even sub */ btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); - if (flags&1) - btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_even)); - else + if (0 != btv->risc_cap_even) { + if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); + flags |= 3; + btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); + } else if (flags&1) { + if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); + btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); + } else { + if (debug) printk(" -----------"); btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); + } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable cpaturing and DMA */ + if (debug) printk(" flags=0x%x dma=%s\n", + flags,(flags&0x0f) ? "on" : "off"); btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -3110,24 +3302,29 @@ init_video_dev(struct bttv *btv) static int init_bt848(int i) { struct bttv *btv = &bttvs[i]; + int j; btv->user=0; init_MUTEX(&btv->lock); -#if 0 /* dump current state of the gpio registers before changing them, * might help to make a new card work */ - printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", - i, - btread(BT848_GPIO_OUT_EN), - btread(BT848_GPIO_DATA), - btread(BT848_GPIO_REG_INP)); -#endif + if (verbose >= 2) + printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", + i, + btread(BT848_GPIO_OUT_EN), + btread(BT848_GPIO_DATA), + btread(BT848_GPIO_REG_INP)); /* reset the bt848 */ btwrite(0, BT848_SRESET); DEBUG(printk(KERN_DEBUG "bttv%d: bt848_mem: 0x%lx\n",i,(unsigned long) btv->bt848_mem)); + /* not registered yet */ + btv->video_dev.minor = -1; + btv->radio_dev.minor = -1; + btv->vbi_dev.minor = -1; + /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ btv->win.interlace=1; @@ -3135,10 +3332,6 @@ static int init_bt848(int i) btv->win.y=0; btv->win.width=768; /* 640 */ btv->win.height=576; /* 480 */ - btv->win.cropwidth=768; /* 640 */ - btv->win.cropheight=576; /* 480 */ - btv->win.cropx=0; - btv->win.cropy=0; btv->win.bpp=2; btv->win.depth=16; btv->win.color_fmt=BT848_COLOR_FMT_RGB16; @@ -3146,27 +3339,24 @@ static int init_bt848(int i) btv->win.swidth=1024; btv->win.sheight=768; btv->win.vidadr=0; - btv->cap=0; + btv->vbi_on=0; + btv->scr_on=0; - btv->gmode=0; - btv->risc_odd=0; - btv->risc_even=0; + btv->risc_scr_odd=0; + btv->risc_scr_even=0; + btv->risc_cap_odd=0; + btv->risc_cap_even=0; btv->risc_jmp=0; btv->vbibuf=0; - btv->grisc=0; - btv->grabbing=0; - btv->grabcount=0; - btv->grab=0; - btv->lastgrab=0; btv->field=btv->last_field=0; /* i2c */ btv->tuner_type=-1; init_bttv_i2c(btv); - if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + if (!(btv->risc_scr_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; - if (!(btv->risc_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + if (!(btv->risc_scr_even=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) return -1; @@ -3180,9 +3370,13 @@ static int init_bt848(int i) btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE); if (!btv->vbibuf) return -1; - if (!(btv->grisc=(unsigned int *) kmalloc(32768, GFP_KERNEL))) + if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) return -1; - + for (j = 0; j < gbuffers; j++) { + if (!(btv->gbuf[j].risc = kmalloc(16384,GFP_KERNEL))) + return -1; + } + memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random memory to the user */ @@ -3194,7 +3388,14 @@ static int init_bt848(int i) /* btwrite(0, BT848_TDEC); */ btwrite(0x10, BT848_COLOR_CTL); btwrite(0x00, BT848_CAP_CTL); - btwrite(0xac, BT848_GPIO_DMA_CTL); + /* set planar and packed mode trigger points and */ + /* set rising edge of inverted GPINTR pin as irq trigger */ + btwrite(BT848_GPIO_DMA_CTL_PKTP_32| + BT848_GPIO_DMA_CTL_PLTP1_16| + BT848_GPIO_DMA_CTL_PLTP23_16| + BT848_GPIO_DMA_CTL_GPINTC| + BT848_GPIO_DMA_CTL_GPINTI, + BT848_GPIO_DMA_CTL); /* select direct input */ btwrite(0x00, BT848_GPIO_REG_INP); @@ -3229,13 +3430,14 @@ static int init_bt848(int i) /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ (fieldnr ? BT848_INT_VSYNC : 0)| + BT848_INT_GPINT| BT848_INT_SCERR| BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| BT848_INT_FMTCHG|BT848_INT_HLOCK, BT848_INT_MASK); make_vbitab(btv); - bt848_set_risc_jmps(btv); + bt848_set_risc_jmps(btv,-1); /* * Now add the template and register the device unit. @@ -3262,12 +3464,17 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) if (!astat) return; btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat)); - IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat)); + IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat)); + IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); /* get device status bits */ dstat=btread(BT848_DSTATUS); + if (astat&BT848_INT_GPINT) { + IDEBUG(printk ("bttv%d: IRQ_GPINT\n", btv->nr)); + wake_up_interruptible(&btv->gpioq); + } + if (astat&BT848_INT_FMTCHG) { IDEBUG(printk ("bttv%d: IRQ_FMTCHG\n", btv->nr)); @@ -3283,13 +3490,21 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) IDEBUG(printk ("bttv%d: IRQ_VSYNC\n", btv->nr)); btv->field++; } - if (astat&BT848_INT_SCERR) { - IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr)); - bt848_dma(btv, 0); - bt848_dma(btv, 1); + if (astat&(BT848_INT_SCERR|BT848_INT_OCERR)) { + printk("bttv%d: irq:%s%s risc_count=%08x\n",btv->nr, + (astat&BT848_INT_SCERR) ? " SCERR" : "", + (astat&BT848_INT_OCERR) ? " OCERR" : "", + btread(BT848_RISC_COUNT)); + bt848_set_risc_jmps(btv,0); + btwrite(0, BT848_SRESET); + btwrite(virt_to_bus(btv->risc_jmp), + BT848_RISC_STRT_ADD); + bt848_set_geo(btv,0); + bt848_set_risc_jmps(btv,-1); +#if 0 wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); - +#endif } if (astat&BT848_INT_RISCI) { @@ -3307,41 +3522,48 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) /* captured full frame */ if (stat&(2<<28)) { - /*wake_up_interruptible(&btv->capq);*/ btv->last_field=btv->field; - btv->grab++; - btv->frame_stat[btv->grf] = GBUFFER_DONE; - if ((--btv->grabbing)) + if (debug) + printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); + btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; + btv->gq_grab = -1; + if (btv->gq_in != btv->gq_out) { - btv->gfmt = btv->gfmt_next; - btv->gwidth = btv->gwidth_next; - btv->gheight = btv->gheight_next; - btv->gro = btv->gro_next; - btv->gre = btv->gre_next; - btv->grf = btv->grf_next; - btv->risc_jmp[5]=cpu_to_le32(btv->gro); - btv->risc_jmp[11]=cpu_to_le32(btv->gre); - bt848_set_geo(btv, btv->gwidth, - btv->gheight, - btv->gfmt,0); + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } else { - bt848_set_risc_jmps(btv); + btv->risc_cap_odd = 0; + btv->risc_cap_even = 0; + bt848_set_risc_jmps(btv,-1); btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI); - bt848_set_geo(btv, btv->win.width, - btv->win.height, - btv->win.color_fmt,0); + bt848_set_geo(btv,0); + btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } wake_up_interruptible(&btv->capq); break; } if (stat&(8<<28)) { - btv->risc_jmp[5]=cpu_to_le32(btv->gro); - btv->risc_jmp[11]=cpu_to_le32(btv->gre); - btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); - bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt,0); + btv->gq_grab = btv->gqueue[btv->gq_out++]; + btv->gq_out = btv->gq_out % MAX_GBUFFERS; + if (debug) + printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; + btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; + bt848_set_risc_jmps(btv,-1); + bt848_set_geo(btv,0); + btwrite(BT848_COLOR_CTL_GAMMA, + BT848_COLOR_CTL); } } if (astat&BT848_INT_OCERR) @@ -3427,6 +3649,9 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) init_waitqueue_head(&btv->capqe); btv->vbip=VBIBUF_SIZE; + init_waitqueue_head(&btv->gpioq); + btv->shutdown=0; + btv->id=dev->device; btv->irq=dev->irq; btv->bt848_adr=dev->resource[0].start; @@ -3544,15 +3769,17 @@ static int find_bt848(void) static void release_bttv(void) { u8 command; - int i; + int i,j; struct bttv *btv; for (i=0;i<bttv_num; i++) { btv=&bttvs[i]; - /* turn off all capturing, DMA and IRQs */ + /* unregister i2c_bus */ + i2c_bit_del_bus(&btv->i2c_adap); + /* turn off all capturing, DMA and IRQs */ btand(~15, BT848_GPIO_DMA_CTL); /* first disable interrupts before unmapping the memory! */ @@ -3560,9 +3787,6 @@ static void release_bttv(void) btwrite(0xffffffffUL,BT848_INT_STAT); btwrite(0x0, BT848_GPIO_OUT_EN); - /* unregister i2c_bus */ - i2c_bit_del_bus(&btv->i2c_adap); - /* disable PCI bus-mastering */ pci_read_config_byte(btv->dev, PCI_COMMAND, &command); /* Should this be &=~ ?? */ @@ -3570,14 +3794,17 @@ static void release_bttv(void) pci_write_config_byte(btv->dev, PCI_COMMAND, command); /* unmap and free memory */ - if (btv->grisc) - kfree((void *) btv->grisc); - - if (btv->risc_odd) - kfree((void *) btv->risc_odd); + for (j = 0; j < gbuffers; j++) + if (btv->gbuf[j].risc) + kfree(btv->gbuf[j].risc); + if (btv->gbuf) + kfree((void *) btv->gbuf); + + if (btv->risc_scr_odd) + kfree((void *) btv->risc_scr_odd); - if (btv->risc_even) - kfree((void *) btv->risc_even); + if (btv->risc_scr_even) + kfree((void *) btv->risc_scr_even); DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%p.\n", btv->risc_jmp)); if (btv->risc_jmp) @@ -3599,6 +3826,13 @@ static void release_bttv(void) video_unregister_device(&btv->vbi_dev); if (radio[btv->nr] && btv->radio_dev.minor != -1) video_unregister_device(&btv->radio_dev); + + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + btv->shutdown=1; + wake_up(&btv->gpioq); } } @@ -3614,6 +3848,14 @@ int init_bttv_cards(struct video_init *unused) (BTTV_VERSION_CODE >> 16) & 0xff, (BTTV_VERSION_CODE >> 8) & 0xff, BTTV_VERSION_CODE & 0xff); + if (gbuffers < 2 || gbuffers > MAX_GBUFFERS) + gbuffers = 2; + if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF) + gbufsize = BTTV_MAX_FBUF; + if (verbose) + printk(KERN_INFO "bttv: using %d buffers with %dk (%dk total) for capture\n", + gbuffers,gbufsize/1024,gbuffers*gbufsize/1024); + handle_chipset(); if (find_bt848()<=0) return -EIO; diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h index 309e93e95..ab3d88ab5 100644 --- a/drivers/char/bttv.h +++ b/drivers/char/bttv.h @@ -21,45 +21,67 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE 0x00070d +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,21) #include <linux/types.h> #include <linux/wait.h> +#include <linux/videodev.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> #include "audiochip.h" #include "bt848.h" +#define WAIT_QUEUE wait_queue_head_t -/* experimental, interface might change */ -#ifndef VIDIOCSWIN2 -#define VIDIOCSWIN2 _IOW('v',28,struct video_window2) -struct video_window2 -{ - __u16 palette; /* Palette (aka video format) in use */ - __u32 start; /* start address, relative to video_buffer.base */ - __u32 pitch; - __u32 width; - __u32 height; - __u32 flags; - - struct video_clip *clips; - int clipcount; -}; -#endif +/* returns card type, + for possible values see lines below beginning with #define BTTV_UNKNOWN + returns negative value if error ocurred +*/ +extern int bttv_get_id(unsigned int card); +/* sets GPOE register (BT848_GPIO_OUT_EN) to new value: + data | (current_GPOE_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_gpio_enable(unsigned int card, + unsigned long mask, unsigned long data); + +/* fills data with GPDATA register contents + returns negative value if error ocurred +*/ +extern int bttv_read_gpio(unsigned int card, unsigned long *data); + +/* sets GPDATA register to new value: + (data & mask) | (current_GPDATA_value & ~mask) + returns negative value if error ocurred +*/ +extern int bttv_write_gpio(unsigned int card, + unsigned long mask, unsigned long data); + +/* returns pointer to task queue which can be used as parameter to + interruptible_sleep_on + in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated + (wake_up_interruptible) and following call to the function bttv_read_gpio + should return new value of GPDATA, + returns NULL value if error ocurred or queue is not available + WARNING: because there is no buffer for GPIO data, one MUST + process data ASAP +*/ +extern WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card); -#define WAIT_QUEUE wait_queue_head_t #ifndef O_NONCAP #define O_NONCAP O_TRUNC #endif -#define MAX_GBUFFERS 2 +#define MAX_GBUFFERS 64 #define RISCMEM_LEN (32744*2) #define VBI_MAXLINES 16 #define VBIBUF_SIZE (2048*VBI_MAXLINES*2) #define BTTV_MAX_FBUF 0x208000 +#define I2C_CLIENTS_MAX 8 #ifdef __KERNEL__ @@ -69,17 +91,12 @@ struct bttv_window ushort width, height; ushort bpp, bpl; ushort swidth, sheight; - short cropx, cropy; - ushort cropwidth, cropheight; unsigned long vidadr; ushort freq; int norm; int interlace; int color_fmt; ushort depth; - - int use_yuv; - struct video_window2 win2; }; struct bttv_pll_info { @@ -89,7 +106,21 @@ struct bttv_pll_info { unsigned int pll_current; /* Currently programmed ofreq */ }; -#define I2C_CLIENTS_MAX 8 +struct bttv_gbuf { + int stat; +#define GBUFFER_UNUSED 0 +#define GBUFFER_GRABBING 1 +#define GBUFFER_DONE 2 +#define GBUFFER_ERROR 3 + + u16 width; + u16 height; + u16 fmt; + + u32 *risc; + unsigned long ro; + unsigned long re; +}; struct bttv { @@ -125,6 +156,7 @@ struct bttv unsigned char *vbibuf; struct bttv_window win; + int fb_color_ctl; int type; /* card type */ int audio; /* audio mode */ int audio_chip; /* set to one of the chips supported by bttv.c */ @@ -141,34 +173,18 @@ struct bttv WAIT_QUEUE capqe; int vbip; - u32 *risc_odd; - u32 *risc_even; - int cap; + u32 *risc_scr_odd; + u32 *risc_scr_even; + u32 risc_cap_odd; + u32 risc_cap_even; + int scr_on; + int vbi_on; struct video_clip *cliprecs; - struct gbuffer *ogbuffers; - struct gbuffer *egbuffers; - u16 gwidth, gheight, gfmt; - u16 gwidth_next, gheight_next, gfmt_next; - u32 *grisc; - - unsigned long gro; - unsigned long gre; - unsigned long gro_next; - unsigned long gre_next; - - int grf,grf_next; /* frame numbers in grab queue */ - int frame_stat[MAX_GBUFFERS]; -#define GBUFFER_UNUSED 0 -#define GBUFFER_GRABBING 1 -#define GBUFFER_DONE 2 - + struct bttv_gbuf *gbuf; + int gqueue[MAX_GBUFFERS]; + int gq_in,gq_out,gq_grab; char *fbuffer; - int gmode; - int grabbing; - int lastgrab; - int grab; - int grabcount; struct bttv_pll_info pll; unsigned int Fsc; @@ -176,12 +192,12 @@ struct bttv unsigned int last_field; /* number of last grabbed field */ int i2c_command; int triton1; + + WAIT_QUEUE gpioq; + int shutdown; }; #endif -/*The following should be done in more portable way. It depends on define - of _ALPHA_BTTV in the Makefile.*/ - #if defined(__powerpc__) /* big-endian */ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) { @@ -193,14 +209,9 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define btwrite(dat,adr) io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat)) #define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr))) #else -#ifdef _ALPHA_BTTV -#define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) -#define btread(adr) readl(btv->bt848_adr+(adr)) -#else #define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) #define btread(adr) readl(btv->bt848_mem+(adr)) #endif -#endif #define btand(dat,adr) btwrite((dat) & btread(adr), adr) #define btor(dat,adr) btwrite((dat) | btread(adr), adr) @@ -243,10 +254,19 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define BTTV_PHOEBE_TVMAS 0x16 #define BTTV_MODTEC_205 0x17 #define BTTV_MAGICTVIEW061 0x18 - +#define BTTV_VOBIS_BOOSTAR 0x19 +#define BTTV_HAUPPAUG_WCAM 0x1a #define BTTV_MAXI 0x1b #define BTTV_TERRATV 0x1c #define BTTV_PXC200 0x1d +#define BTTV_FLYVIDEO_98 0x1e +#define BTTV_IPROTV 0x1f +#define BTTV_INTEL_C_S_PCI 0x20 +#define BTTV_TERRATVALUE 0x21 +#define BTTV_WINFAST2000 0x22 +#define BTTV_CHRONOS_VS2 0x23 +#define BTTV_TYPHOON_TVIEW 0x24 +#define BTTV_PXELVWPLTVPRO 0x25 #define AUDIO_TUNER 0x00 @@ -279,27 +299,6 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define TDA9840_STADJ 0x03 #define TDA9840_TEST 0x04 -#define TDA9850_CON1 0x04 -#define TDA9850_CON2 0x05 -#define TDA9850_CON3 0x06 -#define TDA9850_CON4 0x07 -#define TDA9850_ALI1 0x08 -#define TDA9850_ALI2 0x09 -#define TDA9850_ALI3 0x0a - -#define TDA8425_VL 0x00 -#define TDA8425_VR 0x01 -#define TDA8425_BA 0x02 -#define TDA8425_TR 0x03 -#define TDA8425_S1 0x08 - -#define TEA6300_VL 0x00 /* volume control left */ -#define TEA6300_VR 0x01 /* volume control right */ -#define TEA6300_BA 0x02 /* bass control */ -#define TEA6300_TR 0x03 /* treble control */ -#define TEA6300_FA 0x04 /* fader control */ -#define TEA6300_SW 0x05 /* mute and source switch */ - #define PT2254_L_CHANEL 0x10 #define PT2254_R_CHANEL 0x08 #define PT2254_DBS_IN_2 0x400 @@ -309,3 +308,9 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define WINVIEW_PT2254_STROBE 0x80 #endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/console.c b/drivers/char/console.c index a1c9f3cf3..9d8bf6cb0 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -2564,7 +2564,7 @@ void __init con_init_devfs (void) int i; for (i = 0; i < console_driver.num; i++) - tty_register_devfs (&console_driver, 0, + tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY, console_driver.minor_start + i); } diff --git a/drivers/char/epca.c b/drivers/char/epca.c index e8de397bf..31cd5546c 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1545,13 +1545,14 @@ int __init init_module() } /* End init_module */ #endif -#ifdef MODULE -/* -------------------- Begin cleanup_module ---------------------- */ #ifdef ENABLE_PCI static struct pci_driver epca_driver; #endif +#ifdef MODULE +/* -------------------- Begin cleanup_module ---------------------- */ + void cleanup_module() { /* Begin cleanup_module */ diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 0b1ab10e1..ad9452390 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -142,6 +142,8 @@ static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t); */ #define STLI_EISAPROBE 0 +static devfs_handle_t devfs_handle = NULL; + /*****************************************************************************/ /* @@ -830,8 +832,6 @@ int init_module() /*****************************************************************************/ -static devfs_handle_t devfs_handle = NULL; - void cleanup_module() { stlibrd_t *brdp; diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 2be8b2798..8de178bb6 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -480,7 +480,7 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode) break; case VIDEO_SOUND_MONO: if (msp->mode == MSP_MODE_AM_NICAM) { - printk("msp3400: switching to AM mono\n"); + dprintk("msp3400: switching to AM mono\n"); /* AM mono decoding is handled by tuner, not MSP chip */ /* so let's redirect sound from tuner via SCART */ /* volume prescale for SCART */ @@ -723,7 +723,7 @@ static int msp3400c_thread(void *data) /* some time for the tuner to sync */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -750,13 +750,15 @@ static int msp3400c_thread(void *data) msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); + schedule_timeout(HZ/10); if (signal_pending(current)) goto done; if (msp->restart) msp->restart = 0; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; if (val1 < val) val1 = val, max1 = this; dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); @@ -785,13 +787,15 @@ static int msp3400c_thread(void *data) msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/25); + schedule_timeout(HZ/10); if (signal_pending(current)) goto done; if (msp->restart) goto restart; val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); + if (val > 32768) + val -= 65536; if (val2 < val) val2 = val, max2 = this; dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); @@ -974,7 +978,7 @@ static int msp3410d_thread(void *data) /* some time for the tuner to sync */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/10); + schedule_timeout(HZ/5); if (signal_pending(current)) goto done; @@ -1041,10 +1045,9 @@ static int msp3410d_thread(void *data) for (i = 0; modelist[i].name != NULL; i++) if (modelist[i].retval == val) break; - if (debug) - printk("msp3410: current mode: %s (0x%04x)\n", - modelist[i].name ? modelist[i].name : "unknown", - val); + dprintk("msp3410: current mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown", + val); msp->main = modelist[i].main; msp->second = modelist[i].second; @@ -1242,6 +1245,7 @@ static int msp3400c_mixer_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); + struct i2c_client *client; struct msp3400c *msp; int i; @@ -1249,12 +1253,17 @@ msp3400c_mixer_open(struct inode *inode, struct file *file) for (i = 0; i < MSP3400_MAX; i++) { msp = msps[i]->data; if (msp->mixer_num == minor) { - file->private_data = msps[i]; + client = msps[i]; + file->private_data = client; break; } } if (MSP3400_MAX == i) return -ENODEV; + + /* lock bttv in memory while the mixer is in use */ + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); MOD_INC_USE_COUNT; return 0; @@ -1263,6 +1272,10 @@ msp3400c_mixer_open(struct inode *inode, struct file *file) static int msp3400c_mixer_release(struct inode *inode, struct file *file) { + struct i2c_client *client = file->private_data; + + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); MOD_DEC_USE_COUNT; return 0; } @@ -1274,10 +1287,10 @@ msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin) } static struct file_operations msp3400c_mixer_fops = { - llseek: msp3400c_mixer_llseek, - ioctl: msp3400c_mixer_ioctl, - open: msp3400c_mixer_open, - release: msp3400c_mixer_release, + llseek: msp3400c_mixer_llseek, + ioctl: msp3400c_mixer_ioctl, + open: msp3400c_mixer_open, + release: msp3400c_mixer_release, }; #endif diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index d73c09695..59853da1f 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -83,7 +83,7 @@ struct pp_struct { /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) -static inline void enable_irq (struct pp_struct *pp) +static inline void pp_enable_irq (struct pp_struct *pp) { struct parport *port = pp->pdev->port; port->ops->enable_irq (port); @@ -144,7 +144,7 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count, } kfree (kbuffer); - enable_irq (pp); + pp_enable_irq (pp); return bytes_read; } @@ -197,7 +197,7 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count, } kfree (kbuffer); - enable_irq (pp); + pp_enable_irq (pp); return bytes_written; } @@ -292,7 +292,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, /* For interrupt-reporting to work, we need to be * informed of each interrupt. */ - enable_irq (pp); + pp_enable_irq (pp); /* We may need to fix up the state machine. */ info = &pp->pdev->port->ieee1284; @@ -441,7 +441,7 @@ static int pp_ioctl(struct inode *inode, struct file *file, ret = -ENXIO; break; } - enable_irq (pp); + pp_enable_irq (pp); return ret; case PPWCTLONIRQ: diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 77cdb7a51..8f25926e9 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -329,9 +329,10 @@ static int pty_open(struct tty_struct *tty, struct file * filp) clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&pty->open_wait); set_bit(TTY_THROTTLED, &tty->flags); - /* register a slave for the master */ + /* Register a slave for the master */ if (tty->driver.major == PTY_MASTER_MAJOR) - tty_register_devfs(&tty->link->driver, DEVFS_FL_WAIT, + tty_register_devfs(&tty->link->driver, + DEVFS_FL_AUTO_OWNER | DEVFS_FL_WAIT, tty->link->driver.minor_start + MINOR(tty->device)-tty->driver.minor_start); retval = 0; diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c new file mode 100644 index 000000000..827be953a --- /dev/null +++ b/drivers/char/sh-sci.c @@ -0,0 +1,992 @@ +/* $Id: sh-sci.c,v 1.32 2000-03-05 13:56:18+09 gniibe Exp $ + * + * linux/drivers/char/sh-sci.c + * + * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) + * Copyright (C) 1999, 2000 Niibe Yutaka + * + * TTY code is based on sx.c (Specialix SX driver) by: + * + * (C) 1998 R.E.Wolff@BitWizard.nl + * + */ + +#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/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> +#include <linux/console.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> + +#include "generic_serial.h" +#include "sh-sci.h" + +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +static void gdb_detach(void); +#endif + +struct sci_port sci_ports[1]; + +/* Function prototypes */ +static void sci_disable_tx_interrupts(void *ptr); +static void sci_enable_tx_interrupts(void *ptr); +static void sci_disable_rx_interrupts(void *ptr); +static void sci_enable_rx_interrupts(void *ptr); +static int sci_get_CD(void *ptr); +static void sci_shutdown_port(void *ptr); +static void sci_set_real_termios(void *ptr); +static void sci_hungup(void *ptr); +static void sci_close(void *ptr); +static int sci_chars_in_buffer(void *ptr); +static int sci_init_drivers(void); + +static struct tty_driver sci_driver, sci_callout_driver; + +#define SCI_NPORTS 1 +static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, }; +static struct termios *sci_termios[2]; /* nomal, locked */ + +int sci_refcount; +int sci_debug = 0; + +#ifdef MODULE +MODULE_PARM(sci_debug, "i"); +#endif + +static struct real_driver sci_real_driver = { + sci_disable_tx_interrupts, + sci_enable_tx_interrupts, + sci_disable_rx_interrupts, + sci_enable_rx_interrupts, + sci_get_CD, + sci_shutdown_port, + sci_set_real_termios, + sci_chars_in_buffer, + sci_close, + sci_hungup, + NULL +}; + +static void sci_setsignals(struct sci_port *port, int dtr, int rts) +{ + /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ + /* We use SCIF's hardware for CTS/RTS, so don't need any for that. */ + /* If you have signals for DTR and DCD, please implement here. */ + ; +} + +static int sci_getsignals(struct sci_port *port) +{ + /* This routine is used for geting signals of: DTR, DCD, DSR, RI, + and CTS/RTS */ + + return TIOCM_DTR|TIOCM_RTS|TIOCM_DSR; +/* + (((o_stat & OP_DTR)?TIOCM_DTR:0) | + ((o_stat & OP_RTS)?TIOCM_RTS:0) | + ((i_stat & IP_CTS)?TIOCM_CTS:0) | + ((i_stat & IP_DCD)?TIOCM_CAR:0) | + ((i_stat & IP_DSR)?TIOCM_DSR:0) | + ((i_stat & IP_RI) ?TIOCM_RNG:0) +*/ +} + +static void sci_set_baud(struct sci_port *port) +{ + int t; + + switch (port->gs.baud) { + case 0: + t = -1; + break; + case 2400: + t = BPS_2400; + break; + case 4800: + t = BPS_4800; + break; + case 9600: + t = BPS_9600; + break; + case 19200: + t = BPS_19200; + break; + case 38400: + t = BPS_38400; + break; + default: + printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", port->gs.baud); + case 115200: + t = BPS_115200; + break; + } + + if (t > 0) { + sci_setsignals (port, 1, -1); + ctrl_outb(t, SCBRR); + ctrl_outw(0xa400, RFCR); /* Refresh counter clear */ + while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER) + ; + } else { + sci_setsignals (port, 0, -1); + } +} + +static void sci_set_termios_cflag(struct sci_port *port) +{ + unsigned short status; + unsigned short smr_val=0; +#if defined(CONFIG_SH_SCIF_SERIAL) + unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */ +#endif + + do + status = ctrl_in(SC_SR); + while (!(status & SCI_TEND)); + + port->old_cflag = port->gs.tty->termios->c_cflag; + + ctrl_out(0x00, SCSCR); /* TE=0, RE=0, CKE1=0 */ +#if defined(CONFIG_SH_SCIF_SERIAL) + ctrl_out(fcr_val, SCFCR); + fcr_val = 0; +#endif + + if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7) + smr_val |= 0x40; + if (C_PARENB(port->gs.tty)) + smr_val |= 0x20; + if (C_PARODD(port->gs.tty)) + smr_val |= 0x10; + if (C_CSTOPB(port->gs.tty)) + smr_val |= 0x08; + ctrl_out(smr_val, SCSMR); + +#if defined(CONFIG_SH_SCIF_SERIAL) + if (C_CRTSCTS(port->gs.tty)) + fcr_val |= 0x08; + ctrl_out(fcr_val, SCFCR); +#endif + + sci_set_baud(port); + ctrl_out(SCSCR_INIT, SCSCR); /* TIE=0,RIE=0,TE=1,RE=1 */ +#if 0 /* defined(CONFIG_SH_SCIF_SERIAL) */ + ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */ +#endif + sci_enable_rx_interrupts(port); +} + +static void sci_set_real_termios(void *ptr) +{ + struct sci_port *port = ptr; + + if (port->old_cflag != port->gs.tty->termios->c_cflag) + sci_set_termios_cflag(port); + + /* Tell line discipline whether we will do input cooking */ + if (I_OTHER(port->gs.tty)) + clear_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + else + set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags); + +/* Tell line discipline whether we will do output cooking. + * If OPOST is set and no other output flags are set then we can do output + * processing. Even if only *one* other flag in the O_OTHER group is set + * we do cooking in software. + */ + if (O_OPOST(port->gs.tty) && !O_OTHER(port->gs.tty)) + set_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); + else + clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags); +} + +/* ********************************************************************** * + * the interrupt related routines * + * ********************************************************************** */ + +static void sci_transmit_chars(struct sci_port *port) +{ + int count, i; + int txroom; + unsigned long flags; + unsigned short status; + unsigned short ctrl; + unsigned char c; + + status = ctrl_in(SC_SR); + if (!(status & SCI_TD_E)) { + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + if (port->gs.xmit_cnt == 0) { + ctrl &= ~SCI_CTRL_FLAGS_TIE; + port->gs.flags &= ~GS_TX_INTEN; + } else + ctrl |= SCI_CTRL_FLAGS_TIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); + return; + } + + while (1) { + count = port->gs.xmit_cnt; +#if defined(CONFIG_SH_SCIF_SERIAL) + txroom = 16 - (ctrl_inw(SCFDR)>>8); +#else + txroom = (ctrl_in(SC_SR)&SCI_TD_E)?1:0; +#endif + if (count > txroom) + count = txroom; + + /* Don't copy pas the end of the source buffer */ + if (count > SERIAL_XMIT_SIZE - port->gs.xmit_tail) + count = SERIAL_XMIT_SIZE - port->gs.xmit_tail; + + /* If for one reason or another, we can't copy more data, we're done! */ + if (count == 0) + break; + + for (i=0; i<count; i++) { + c = port->gs.xmit_buf[port->gs.xmit_tail + i]; + ctrl_outb(c, SC_TDR); + } + ctrl_out(SCI_TD_E_CLEAR, SC_SR); + + /* Update the kernel buffer end */ + port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1); + + /* This one last. (this is essential) + It would allow others to start putting more data into the buffer! */ + port->gs.xmit_cnt -= count; + } + + if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { + if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + port->gs.tty->ldisc.write_wakeup) + (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); + wake_up_interruptible(&port->gs.tty->write_wait); + } + + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + if (port->gs.xmit_cnt == 0) { + ctrl &= ~SCI_CTRL_FLAGS_TIE; + port->gs.flags &= ~GS_TX_INTEN; + } else { +#if defined(CONFIG_SH_SCIF_SERIAL) + ctrl_in(SC_SR); /* Dummy read */ + ctrl_out(SCI_TD_E_CLEAR, SC_SR); +#endif + ctrl |= SCI_CTRL_FLAGS_TIE; + } + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static inline void sci_receive_chars(struct sci_port *port) +{ + int i, count; + struct tty_struct *tty; + int copied=0; + unsigned short status; + + status = ctrl_in(SC_SR); + if (!(status & SCI_RD_F)) + return; + + tty = port->gs.tty; + while (1) { +#if defined(CONFIG_SH_SCIF_SERIAL) + count = ctrl_inw(SCFDR)&0x001f; +#else + count = (ctrl_in(SC_SR)&SCI_RD_F)?1:0; +#endif + + /* Don't copy more bytes than there is room for in the buffer */ + if (tty->flip.count + count > TTY_FLIPBUF_SIZE) + count = TTY_FLIPBUF_SIZE - tty->flip.count; + + /* If for one reason or another, we can't copy more data, we're done! */ + if (count == 0) + break; + + for (i=0; i<count; i++) + tty->flip.char_buf_ptr[i] = ctrl_inb(SC_RDR); + ctrl_in(SC_SR); /* dummy read */ + ctrl_out(SCI_RDRF_CLEAR, SC_SR); + + memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); + + /* Update the kernel buffer end */ + tty->flip.count += count; + tty->flip.char_buf_ptr += count; + tty->flip.flag_buf_ptr += count; + + copied += count; + } + + if (copied) + /* Tell the rest of the system the news. New characters! */ + tty_flip_buffer_push(tty); +} + +static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct sci_port *port = ptr; + + if (port->gs.flags & GS_ACTIVE) + if (!(port->gs.flags & SCI_RX_THROTTLE)) + sci_receive_chars(port); +} + +static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct sci_port *port = ptr; + + if (port->gs.flags & GS_ACTIVE) + if (port->gs.xmit_cnt) { + sci_transmit_chars(port); + } +} + +static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + /* Handle errors */ + if (ctrl_in(SC_SR) & SCI_ERRORS) + ctrl_out(SCI_ERROR_CLEAR, SC_SR); + + /* Kick the transmission */ + sci_tx_interrupt(irq, ptr, regs); +} + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the generic_serial driver * + * ********************************************************************** */ + +static void sci_disable_tx_interrupts(void *ptr) +{ + unsigned long flags; + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + ctrl &= ~SCI_CTRL_FLAGS_TIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static void sci_enable_tx_interrupts(void *ptr) +{ + struct sci_port *port = ptr; + + disable_irq(SCI_TXI_IRQ); + sci_transmit_chars(port); + enable_irq(SCI_TXI_IRQ); +} + +static void sci_disable_rx_interrupts(void * ptr) +{ + unsigned long flags; + unsigned short ctrl; + + /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + ctrl &= ~SCI_CTRL_FLAGS_RIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static void sci_enable_rx_interrupts(void * ptr) +{ + unsigned long flags; + unsigned short ctrl; + + /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ + save_and_cli(flags); + ctrl = ctrl_in(SCSCR); + ctrl |= SCI_CTRL_FLAGS_RIE; + ctrl_out(ctrl, SCSCR); + restore_flags(flags); +} + +static int sci_get_CD(void * ptr) +{ + /* If you have signal for CD (Carrier Detect), please change here. */ + return 1; +} + +static int sci_chars_in_buffer(void * ptr) +{ +#if defined(CONFIG_SH_SCIF_SERIAL) + return (ctrl_inw(SCFDR) >> 8) + ((ctrl_in(SC_SR) & SCI_TEND)? 0: 1); +#else + return (ctrl_in(SC_SR) & SCI_TEND)? 0: 1; +#endif +} + +static void sci_shutdown_port(void * ptr) +{ + struct sci_port *port = ptr; + + port->gs.flags &= ~ GS_ACTIVE; + if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) + sci_setsignals(port, 0, 0); +} + +/* ********************************************************************** * + * Here are the routines that actually * + * interface with the rest of the system * + * ********************************************************************** */ + +static int sci_open(struct tty_struct * tty, struct file * filp) +{ + struct sci_port *port; + int retval, line; + + line = MINOR(tty->device) - SCI_MINOR_START; + + if ((line < 0) || (line >= SCI_NPORTS)) + return -ENODEV; + + port = &sci_ports[line]; + + tty->driver_data = port; + port->gs.tty = tty; + port->gs.count++; + + /* + * Start up serial port + */ + retval = gs_init_port(&port->gs); + if (retval) { + port->gs.count--; + return retval; + } + + port->gs.flags |= GS_ACTIVE; + sci_setsignals(port, 1,1); + + if (port->gs.count == 1) { + MOD_INC_USE_COUNT; + } + + retval = block_til_ready(port, filp); + + if (retval) { + MOD_DEC_USE_COUNT; + port->gs.count--; + return retval; + } + + if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->gs.normal_termios; + else + *tty->termios = port->gs.callout_termios; + sci_set_real_termios(port); + } + + sci_enable_rx_interrupts(port); + + port->gs.session = current->session; + port->gs.pgrp = current->pgrp; + + return 0; +} + +static void sci_hungup(void *ptr) +{ + MOD_DEC_USE_COUNT; +} + +static void sci_close(void *ptr) +{ + MOD_DEC_USE_COUNT; +} + +static int sci_ioctl(struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int rc; + struct sci_port *port = tty->driver_data; + int ival; + + rc = 0; + switch (cmd) { + case TIOCGSOFTCAR: + rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; + case TIOCSSOFTCAR: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(int))) == 0) { + get_user(ival, (unsigned int *) arg); + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) == 0) + gs_getserial(&port->gs, (struct serial_struct *) arg); + break; + case TIOCSSERIAL: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct))) == 0) + rc = gs_setserial(&port->gs, + (struct serial_struct *) arg); + break; + case TIOCMGET: + if ((rc = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) == 0) { + ival = sci_getsignals(port); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1), + ((ival & TIOCM_RTS) ? 1 : -1)); + } + break; + case TIOCMBIC: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *) arg); + sci_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1), + ((ival & TIOCM_RTS) ? 0 : -1)); + } + break; + case TIOCMSET: + if ((rc = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int))) == 0) { + get_user(ival, (unsigned int *)arg); + sci_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; + + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + +static void sci_throttle(struct tty_struct * tty) +{ + struct sci_port *port = (struct sci_port *)tty->driver_data; + + /* If the port is using any type of input flow + * control then throttle the port. + */ + if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty)) ) + port->gs.flags |= SCI_RX_THROTTLE; +} + +static void sci_unthrottle(struct tty_struct * tty) +{ + struct sci_port *port = (struct sci_port *)tty->driver_data; + + /* Always unthrottle even if flow control is not enabled on + * this port in case we disabled flow control while the port + * was throttled + */ + port->gs.flags &= ~SCI_RX_THROTTLE; + return; +} + +/* ********************************************************************** * + * Here are the initialization routines. * + * ********************************************************************** */ + +static int sci_init_drivers(void) +{ + int error; + struct sci_port *port; + + memset(&sci_driver, 0, sizeof(sci_driver)); + sci_driver.magic = TTY_DRIVER_MAGIC; + sci_driver.driver_name = "serial"; + sci_driver.name = "ttyS"; + sci_driver.major = TTY_MAJOR; + sci_driver.minor_start = SCI_MINOR_START; + sci_driver.num = 1; + sci_driver.type = TTY_DRIVER_TYPE_SERIAL; + sci_driver.subtype = SERIAL_TYPE_NORMAL; + sci_driver.init_termios = tty_std_termios; + sci_driver.init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; + sci_driver.flags = TTY_DRIVER_REAL_RAW; + sci_driver.refcount = &sci_refcount; + sci_driver.table = sci_table; + sci_driver.termios = &sci_termios[0]; + sci_driver.termios_locked = &sci_termios[1]; + sci_termios[0] = sci_termios[1] = NULL; + + sci_driver.open = sci_open; + sci_driver.close = gs_close; + sci_driver.write = gs_write; + sci_driver.put_char = gs_put_char; + sci_driver.flush_chars = gs_flush_chars; + sci_driver.write_room = gs_write_room; + sci_driver.chars_in_buffer = gs_chars_in_buffer; + sci_driver.flush_buffer = gs_flush_buffer; + sci_driver.ioctl = sci_ioctl; + sci_driver.throttle = sci_throttle; + sci_driver.unthrottle = sci_unthrottle; + sci_driver.set_termios = gs_set_termios; + sci_driver.stop = gs_stop; + sci_driver.start = gs_start; + sci_driver.hangup = gs_hangup; + + sci_callout_driver = sci_driver; + sci_callout_driver.name = "cua"; + sci_callout_driver.major = TTYAUX_MAJOR; + sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if ((error = tty_register_driver(&sci_driver))) { + printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&sci_callout_driver))) { + tty_unregister_driver(&sci_driver); + printk(KERN_ERR "sci: Couldn't register SCI callout driver, error = %d\n", + error); + return 1; + } + + port = &sci_ports[0]; + port->gs.callout_termios = tty_std_termios; + port->gs.normal_termios = tty_std_termios; + port->gs.magic = SCI_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->gs.rd = &sci_real_driver; + init_waitqueue_head(&port->gs.open_wait); + init_waitqueue_head(&port->gs.close_wait); + port->old_cflag = 0; + + return 0; +} + +#ifdef MODULE +#define sci_init init_module +#else +#define sci_init rs_init +#endif + +int __init sci_init(void) +{ + struct sci_port *port; + int i; + + for (i=SCI_ERI_IRQ; i<SCI_IRQ_END; i++) + set_ipr_data(i, SCI_IPR_OFFSET, SCI_PRIORITY); + + port = &sci_ports[0]; + + if (request_irq(SCI_ERI_IRQ, sci_er_interrupt, SA_INTERRUPT, + "serial", port)) { + printk(KERN_ERR "sci: Cannot allocate error irq.\n"); + return -ENODEV; + } + if (request_irq(SCI_RXI_IRQ, sci_rx_interrupt, SA_INTERRUPT, + "serial", port)) { + printk(KERN_ERR "sci: Cannot allocate rx irq.\n"); + return -ENODEV; + } + if (request_irq(SCI_TXI_IRQ, sci_tx_interrupt, SA_INTERRUPT, + "serial", port)) { + printk(KERN_ERR "sci: Cannot allocate tx irq.\n"); + return -ENODEV; + } + /* XXX: How about BRI interrupt?? */ + + sci_init_drivers(); + +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + gdb_detach(); +#endif + return 0; /* Return -EIO when not detected */ +} + +#ifdef MODULE +#undef func_enter +#undef func_exit + +void cleanup_module(void) +{ + int i; + + for (i=SCI_ERI_IRQ; i<SCI_TEI_IRQ; i++) /* XXX: irq_end?? */ + free_irq(i, port); + + tty_unregister_driver(&sci_driver); + tty_unregister_driver(&sci_callout_driver); +} + +#include "generic_serial.c" +#endif + +#ifdef CONFIG_SERIAL_CONSOLE +/* + * ------------------------------------------------------------ + * Serial console driver for SH-3/SH-4 SCI (with no FIFO) + * ------------------------------------------------------------ + */ + +static inline void put_char(char c) +{ + unsigned long flags; + unsigned short status; + + save_and_cli(flags); + + do + status = ctrl_in(SC_SR); + while (!(status & SCI_TD_E)); + + ctrl_outb(c, SC_TDR); + ctrl_out(SCI_TD_E_CLEAR, SC_SR); + + restore_flags(flags); +} + +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +static int in_gdb = 1; + +static inline void handle_error(void) +{ /* Clear error flags */ + ctrl_out(SCI_ERROR_CLEAR, SC_SR); +} + +static inline int get_char(void) +{ + unsigned long flags; + unsigned short status; + int c; + + save_and_cli(flags); + do { + status = ctrl_in(SC_SR); + if (status & SCI_ERRORS) { + handle_error(); + continue; + } + } while (!(status & SCI_RD_F)); + c = ctrl_inb(SC_RDR); + ctrl_out(SCI_RDRF_CLEAR, SC_SR); + restore_flags(flags); + + return c; +} + +/* Taken from sh-stub.c of GDB 4.18 */ +static const char hexchars[] = "0123456789abcdef"; +static char highhex(int x) +{ + return hexchars[(x >> 4) & 0xf]; +} + +static char lowhex(int x) +{ + return hexchars[x & 0xf]; +} + +static void gdb_detach(void) +{ + asm volatile("trapa #0xff"); + + if (in_gdb == 1) { + in_gdb = 0; + get_char(); + put_char('\r'); + put_char('\n'); + } +} +#endif + +/* send the packet in buffer. The host get's one chance to read it. + This routine does not wait for a positive acknowledge. */ + +static void +put_string(const char *buffer, int count) +{ + int i; + const unsigned char *p = buffer; +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + int checksum; + +if (in_gdb) { + /* $<packet info>#<checksum>. */ + do { + unsigned char c; + put_char('$'); + put_char('O'); /* 'O'utput to console */ + checksum = 'O'; + + for (i=0; i<count; i++) { /* Don't use run length encoding */ + int h, l; + + c = *p++; + h = highhex(c); + l = lowhex(c); + put_char(h); + put_char(l); + checksum += h + l; + } + put_char('#'); + put_char(highhex(checksum)); + put_char(lowhex(checksum)); + } while (get_char() != '+'); +} else +#endif + for (i=0; i<count; i++) { + if (*p == 10) + put_char('\r'); + put_char(*p++); + } +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + put_string(s, count); +} + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + /* Not implemented yet */ + return 0; +} + +static kdev_t serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, SCI_MINOR_START + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init serial_console_setup(struct console *co, char *options) +{ + int baud = 115200; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + char *s; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch (baud) { + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch (bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch (parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* XXX: set baud, char, and parity here. */ + return 0; +} + +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ + +void __init serial_console_init(void) +{ + register_console(&sercons); +} +#endif /* CONFIG_SERIAL_CONSOLE */ diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h new file mode 100644 index 000000000..9239e41d7 --- /dev/null +++ b/drivers/char/sh-sci.h @@ -0,0 +1,196 @@ +/* $Id: sh-sci.h,v 1.5 2000-03-05 13:54:32+09 gniibe Exp $ + * + * linux/drivers/char/sh-sci.h + * + * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) + * Copyright (C) 1999, 2000 Niibe Yutaka + * Copyright (C) 2000 Greg Banks + * + */ +#include <linux/config.h> + +#if defined(CONFIG_SH_SCI_SERIAL) +#if defined(__sh3__) +#define SCSMR (volatile unsigned char *)0xfffffe80 +#define SCBRR 0xfffffe82 +#define SCSCR (volatile unsigned char *)0xfffffe84 +#define SC_TDR 0xfffffe86 +#define SC_SR (volatile unsigned char *)0xfffffe88 +#define SC_RDR 0xfffffe8a +#define SCSPTR 0xffffff7c + +#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ + +#elif defined(__SH4__) +Not yet. +#endif + +#define SCI_TD_E 0x80 +#define SCI_RD_F 0x40 +#define SCI_ORER 0x20 +#define SCI_FER 0x10 +#define SCI_PER 0x08 +#define SCI_TEND 0x04 + +#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) +#define SCI_TD_E_CLEAR 0x78 +#define SCI_RDRF_CLEAR 0xbc +#define SCI_ERROR_CLEAR 0xc4 + +#define SCI_CTRL_FLAGS_TIE 0x80 +#define SCI_CTRL_FLAGS_RIE 0x40 +#define SCI_CTRL_FLAGS_TE 0x20 +#define SCI_CTRL_FLAGS_RE 0x10 +/* TEIE=0x04 */ +#define SCI_CTRL_FLAGS_CKE1 0x02 +#define SCI_CTRL_FLAGS_CKE0 0x01 + +#define RFCR 0xffffff74 + +#define SCI_ERI_IRQ 23 +#define SCI_RXI_IRQ 24 +#define SCI_TXI_IRQ 25 +#define SCI_TEI_IRQ 26 +#define SCI_IRQ_END 27 + +#define SCI_IPR_OFFSET (16+4) +#endif + +#if defined(CONFIG_SH_SCIF_SERIAL) +#if defined(__sh3__) +#define SCSMR (volatile unsigned char *)0xA4000150 +#define SCBRR 0xA4000152 +#define SCSCR (volatile unsigned char *)0xA4000154 +#define SC_TDR 0xA4000156 +#define SC_SR (volatile unsigned short *)0xA4000158 +#define SC_RDR 0xA400015A +#define SCFCR (volatile unsigned char *)0xA400015C +#define SCFDR 0xA400015E +#undef SCSPTR /* Is there any register for RTS?? */ +#undef SCLSR + +#define RFCR 0xffffff74 + +#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ + /* 0x33 when external clock is used */ +#define SCI_IPR_OFFSET (64+4) + +#elif defined(__SH4__) +#define SCSMR (volatile unsigned short *)0xFFE80000 +#define SCBRR 0xFFE80004 +#define SCSCR (volatile unsigned short *)0xFFE80008 +#define SC_TDR 0xFFE8000C +#define SC_SR (volatile unsigned short *)0xFFE80010 +#define SC_RDR 0xFFE80014 +#define SCFCR (volatile unsigned short *)0xFFE80018 +#define SCFDR 0xFFE8001C +#define SCSPTR 0xFFE80020 +#define SCLSR 0xFFE80024 + +#define RFCR 0xFF800028 + +#define SCSCR_INIT 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +#define SCI_IPR_OFFSET (32+4) + +#endif + +#define SCI_ER 0x0080 +#define SCI_TEND 0x0040 +#define SCI_TD_E 0x0020 +#define SCI_BRK 0x0010 +#define SCI_FER 0x0008 +#define SCI_PER 0x0004 +#define SCI_RD_F 0x0002 +#define SCI_DR 0x0001 + +#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ER | SCI_BRK) +#define SCI_TD_E_CLEAR 0x00df +#define SCI_TEND_CLEAR 0x00bf +#define SCI_RDRF_CLEAR 0x00fc +#define SCI_ERROR_CLEAR 0x0063 + +#define SCI_CTRL_FLAGS_TIE 0x80 +#define SCI_CTRL_FLAGS_RIE 0x40 +#define SCI_CTRL_FLAGS_TE 0x20 +#define SCI_CTRL_FLAGS_RE 0x10 +#define SCI_CTRL_FLAGS_REIE 0x08 +#define SCI_CTRL_FLAGS_CKE1 0x02 + +#if defined(__sh3__) +#define SCI_ERI_IRQ 56 +#define SCI_RXI_IRQ 57 +#define SCI_BRI_IRQ 58 +#define SCI_TXI_IRQ 59 +#define SCI_IRQ_END 60 +#elif defined(__SH4__) +#define SCI_ERI_IRQ 40 +#define SCI_RXI_IRQ 41 +#define SCI_BRI_IRQ 42 +#define SCI_TXI_IRQ 43 +#define SCI_IRQ_END 44 +#endif +#endif + +#define SCI_PRIORITY 3 + +#define SCI_MINOR_START 64 +#define SCI_RX_THROTTLE 0x0000001 + +#define O_OTHER(tty) \ + ((O_OLCUC(tty)) ||\ + (O_ONLCR(tty)) ||\ + (O_OCRNL(tty)) ||\ + (O_ONOCR(tty)) ||\ + (O_ONLRET(tty)) ||\ + (O_OFILL(tty)) ||\ + (O_OFDEL(tty)) ||\ + (O_NLDLY(tty)) ||\ + (O_CRDLY(tty)) ||\ + (O_TABDLY(tty)) ||\ + (O_BSDLY(tty)) ||\ + (O_VTDLY(tty)) ||\ + (O_FFDLY(tty))) + +#define I_OTHER(tty) \ + ((I_INLCR(tty)) ||\ + (I_IGNCR(tty)) ||\ + (I_ICRNL(tty)) ||\ + (I_IUCLC(tty)) ||\ + (L_ISIG(tty))) + +#define SCI_MAGIC 0xbabeface + +struct sci_port { + struct gs_port gs; + unsigned int old_cflag; +}; + +#define WAIT_RFCR_COUNTER 200 + +/* + * Values for the BitRate Register (SCBRR) + * + * The values are actually divisors for a frequency which can + * be internal to the SH3 (14.7456MHz) or derived from an external + * clock source. This driver assumes the internal clock is used; + * to support using an external clock source, config options or + * possibly command-line options would need to be added. + * + * Also, to support speeds below 2400 (why?) the lower 2 bits of + * the SCSMR register would also need to be set to non-zero values. + * + * -- Greg Banks 27Feb2000 + */ + +#if defined(__sh3__) +#define BPS_2400 191 +#define BPS_4800 95 +#define BPS_9600 47 +#define BPS_19200 23 +#define BPS_38400 11 +#define BPS_115200 3 +#elif defined(__SH4__) +/* Values for SH-4 please! */ + +#define BPS_115200 8 +#endif diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c index b63f35436..6d98f9323 100644 --- a/drivers/char/stradis.c +++ b/drivers/char/stradis.c @@ -28,6 +28,7 @@ #include <linux/major.h> #include <linux/malloc.h> #include <linux/mm.h> +#include <linux/init.h> #include <linux/poll.h> #include <linux/pci.h> #include <linux/signal.h> @@ -2236,13 +2237,9 @@ static void release_saa(void) } } -#ifdef MODULE -int init_module(void) -{ -#else -int init_stradis_cards(struct video_init *unused) + +static int __init stradis_init (void) { -#endif struct pci_dev *dev = NULL; int result = 0, i; @@ -2269,11 +2266,14 @@ int init_stradis_cards(struct video_init *unused) return 0; } -#ifdef MODULE -void cleanup_module(void) + +static void __exit stradis_exit (void) { release_saa(); printk(KERN_INFO "stradis: module cleanup complete\n"); } -#endif + +module_init(stradis_init); +module_exit(stradis_exit); + diff --git a/drivers/char/tda9855.c b/drivers/char/tda9855.c deleted file mode 100644 index dfdee66dc..000000000 --- a/drivers/char/tda9855.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * For the TDA9855 chip (afaik, only the Diamond DTV2000 has this) - * This driver will not complain if used with a TDA9850 or any - * other i2c device with the same address. - * - * Copyright (c) 1999 Steve VanDeBogart (vandebo@uclink.berkeley.edu) - * This code is placed under the terms of the GNU General Public License - * Based on tda8425.c by Greg Alexander (c) 1998 - * - * TODO: - * Fix channel change bug - sound goes out when changeing channels, mute - * and unmote to fix. - * Fine tune sound - * Get rest of capabilities into video_audio struct... - * - * Revision: 0.1 - */ - -#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 <linux/videodev.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> - -#include "bttv.h" -#include "audiochip.h" - - -MODULE_PARM(debug,"i"); -static int debug = 0; /* insmod parameter */ - -/* Addresses to scan */ -#define I2C_TDA9855_L 0xb4 -#define I2C_TDA9855_H 0xb6 -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = { - I2C_TDA9855_L >> 1, - I2C_TDA9855_H >> 1, - I2C_CLIENT_END}; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static struct i2c_client_address_data addr_data = { - normal_i2c, normal_i2c_range, - probe, probe_range, - ignore, ignore_range, - force -}; - -struct tda9855 { - int addr; - int rvol, lvol; - int bass, treble, sub; - int c1, c2, c3; - int a1, a2, a3; -}; - -static struct i2c_driver driver; -static struct i2c_client client_template; - - -#define dprintk if (debug) printk - - /* subaddresses */ -#define TDA9855_VR 0x00 /* Volume, right */ -#define TDA9855_VL 0x01 /* Volume, left */ -#define TDA9855_BA 0x02 /* Bass */ -#define TDA9855_TR 0x03 /* Treble */ -#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ -#define TDA9855_C1 0x05 /* Control 1 */ -#define TDA9855_C2 0x06 /* Control 2 */ -#define TDA9855_C3 0x07 /* Control 3 */ -#define TDA9855_A1 0x08 /* Alignmnet 1*/ -#define TDA9855_A2 0x09 /* Alignmnet 2*/ -#define TDA9855_A3 0x0a /* Alignmnet 3*/ - /* Masks for bits in subaddresses */ -/* VR */ /* VL */ -/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) - * in 1dB steps - mute is 0x27 */ - -/* BA */ -/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) - * in .5dB steps - 0 is 0x0E */ - -/* TR */ -/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) - * in 3dB steps - 0 is 0x7 */ - -/* SW */ -/* 4 bits << 2 control subwoofer/surraound gain from -14db (0x1) to 14db (0xf) - * in 3dB steps - mute is 0x0 */ - -/* C1 */ -#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ -#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ -#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ -#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ - /* Bits 0 to 3 select various combinations - * of line in and line out, only the - * interesting ones are defined */ -#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ -#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ - -/* C2 */ -#define TDA9855_SAP 3<<6 /* Selects SAP output, mute if not received */ -#define TDA9855_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ -#define TDA9855_MONO 0 /* Forces Mono output */ -#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ -#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ -#define TDA9855_LMU 1<<3 /* Mute at LOR and LOL */ -#define TDA9855_LINEAR 0 /* Linear Stereo */ -#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ -#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ -#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ -#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ - -/* C3 */ -/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) - * in .5dB steps - 0 is 0x7 */ - -/* A1 and A2 (read/write) */ -/* lower 5 bites are wideband and spectral expander alignment - * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ -#define TDA9855_STP 1<<5 /* Stereo Pilot/detect (read-only) */ -#define TDA9855_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ -#define TDA9855_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ - -/* A3 */ -/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), - * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ -/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), - * 1200ohm (0x1), 2100ohm (0x3) */ -#define TDA9855_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral) */ - - -/* Begin code */ - -static int tda9855_write(struct i2c_client *client, int subaddr, int val) -{ - unsigned char buffer[2]; - - buffer[0] = subaddr; - buffer[1] = val; - if (2 != i2c_master_send(client,buffer,2)) { - printk(KERN_WARNING "tda9855: I/O error, trying (write %d 0x%x)\n", - subaddr, val); - return -1; - } - return 0; -} - -static int tda9855_read(struct i2c_client *client) -{ - unsigned char buffer; - - if (1 != i2c_master_recv(client,&buffer,1)) { - printk(KERN_WARNING "tda9855: I/O error, trying (read)\n"); - return -1; - } - return buffer; -} - -static int tda9855_set(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - unsigned char buf[16]; - - dprintk(KERN_INFO "tda9855_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",t->rvol,t->lvol,t->bass,t->treble,t->sub, - t->c1,t->c2,t->c3,t->a1,t->a2,t->a3); - buf[0] = TDA9855_VR; - buf[1] = t->rvol; - buf[2] = t->lvol; - buf[3] = t->bass; - buf[4] = t->treble; - buf[5] = t->sub; - buf[6] = t->c1; - buf[7] = t->c2; - buf[8] = t->c3; - buf[9] = t->a1; - buf[10] = t->a2; - buf[11] = t->a3; - if (12 != i2c_master_send(client,buf,12)) { - printk(KERN_WARNING "tda9855: I/O error, trying tda9855_set\n"); - return -1; - } - return 0; -} - -static void do_tda9855_init(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - - t->rvol=0x6f; /* 0dB */ - t->lvol=0x6f; /* 0dB */ - t->bass=0x0e; /* 0dB */ - t->treble=(0x07 << 1); /* 0dB */ - t->sub=0x8 << 2; /* 0dB */ - t->c1=TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT; - /* Set Mute, AVL, Loudness off, Internal sound */ - t->c2=TDA9855_STEREO | TDA9855_LINEAR; /* Set Stereo liner mode */ - t->c3=0x07; /* 0dB input gain */ - t->a1=0x10; /* Select nominal wideband expander */ - t->a2=0x10; /* Select nominal spectral expander and 30mV trigger */ - t->a3=0x3; /* Set: nominal timinig current, 420ohm AVL attack */ - tda9855_write(client, TDA9855_C1, TDA9855_MUTE); /* mute */ - tda9855_set(client); -} - -/* *********************** * - * i2c interface functions * - * *********************** */ - -static int tda9855_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) -{ - struct tda9855 *t; - struct i2c_client *client; - - client = kmalloc(sizeof *client,GFP_KERNEL); - if (!client) - return -ENOMEM; - memcpy(client,&client_template,sizeof(struct i2c_client)); - client->adapter = adap; - client->addr = addr; - - client->data = t = kmalloc(sizeof *t,GFP_KERNEL); - if (!t) - return -ENOMEM; - memset(t,0,sizeof *t); - do_tda9855_init(client); - MOD_INC_USE_COUNT; - strcpy(client->name,"TDA9855"); - printk(KERN_INFO "tda9855: init\n"); - - i2c_attach_client(client); - return 0; -} - -static int tda9855_probe(struct i2c_adapter *adap) -{ - if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) - return i2c_probe(adap, &addr_data, tda9855_attach); - return 0; -} - -static int tda9855_detach(struct i2c_client *client) -{ - struct tda9855 *t = client->data; - - do_tda9855_init(client); - i2c_detach_client(client); - - kfree(t); - kfree(client); - MOD_DEC_USE_COUNT; - return 0; -} - -static int tda9855_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct tda9855 *t = client->data; -#if 0 - __u16 *sarg = arg; -#endif - - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - int left,right; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - - /* min is 0x27 max is 0x7f, vstep is 2e8 */ - left = (t->lvol-0x27)*0x2e8; - right = (t->rvol-0x27)*0x2e8; - va->volume=MAX(left,right); - va->balance=(32768*MIN(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(left<right)? - (65535-va->balance) : va->balance; - va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ - va->treble = ((t->treble>>1)-0x3)*0x1c71; - - va->mode = ((TDA9855_STP | TDA9855_SAPP) & - tda9855_read(client)) >> 4; - va->mode |= VIDEO_SOUND_MONO; - break; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - int left,right; - - left = (MIN(65536 - va->balance,32768) * - va->volume) / 32768; - right = (MIN(va->balance,32768) * - va->volume) / 32768; - t->lvol = left/0x2e8+0x27; - t->rvol = right/0x2e8+0x27; - t->bass = va->bass/0xccc+0x6; - t->treble = (va->treble/0x1c71+0x3)<<1; - tda9855_write(client,TDA9855_VL,t->lvol); - tda9855_write(client,TDA9855_VR,t->rvol); - tda9855_write(client,TDA9855_BA, t->bass); - tda9855_write(client,TDA9855_TR,t->treble); - - switch (va->mode) { - case VIDEO_SOUND_MONO: - t->c2= TDA9855_MONO | (t->c2 & 0x3f); - break; - case VIDEO_SOUND_STEREO: - t->c2= TDA9855_STEREO | (t->c2 & 0x3f); - break; - case VIDEO_SOUND_LANG1: - t->c2= TDA9855_SAP | (t->c2 & 0x3f); - break; - } - tda9855_write(client,TDA9855_C2,t->c2); - break; - } - -#if 0 - /* --- old, obsolete interface --- */ - case AUDC_GET_VOLUME_LEFT: - *sarg = (t->lvol-0x27)*0x2e8; /* min is 0x27 max is 0x7f, vstep is 2e8 */ - break; - case AUDC_GET_VOLUME_RIGHT: - *sarg = (t->rvol-0x27)*0x2e8; - break; - case AUDC_SET_VOLUME_LEFT: - t->lvol = *sarg/0x2e8+0x27; - break; - case AUDC_SET_VOLUME_RIGHT: - t->rvol = *sarg/0x2e8+0x27; - break; - case AUDC_GET_BASS: - *sarg = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ - break; - case AUDC_SET_BASS: - t->bass = *sarg/0xccc+0x6; - tda9855_write(client,TDA9855_BA, t->bass); - break; - case AUDC_GET_TREBLE: - *sarg = ((t->treble>>1)-0x3)*0x1c71; - break; - case AUDC_SET_TREBLE: - t->treble = (*sarg/0x1c71+0x3)<<1; - tda9855_write(client,TDA9855_TR,t->treble); - break; - case AUDC_GET_STEREO: - *sarg = ((TDA9855_STP | TDA9855_SAPP) & - tda9855_read(client)) >> 4; - if(*sarg==0) *sarg=VIDEO_SOUND_MONO; - break; - case AUDC_SET_STEREO: - if(*sarg==VIDEO_SOUND_MONO) - t->c2= TDA9855_MONO | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set mono */ - else if(*sarg==VIDEO_SOUND_STEREO) - t->c2= TDA9855_STEREO | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set stereo */ - else if(*sarg==VIDEO_SOUND_LANG2) - t->c2= TDA9855_SAP | (t->c2 & 0x3f); - /* Mask out the sap and stereo bits and set sap */ - tda9855_write(client,TDA9855_C2,t->c2); - break; - case AUDC_SET_INPUT: - dprintk(KERN_INFO "tda9855: SET_INPUT with 0x%04x\n",*sarg); - if((*sarg & (AUDIO_MUTE | AUDIO_OFF))!=0) - t->c1|=TDA9855_MUTE; - else - t->c1= t->c1 & 0x7f; /* won't work --> (~TDA9855_MUTE); */ - if((*sarg & AUDIO_INTERN) == AUDIO_INTERN) - t->c1=(t->c1 & ~0x7) | TDA9855_INT; /* 0x7 is a mask for the int/ext */ - if((*sarg & AUDIO_EXTERN) == AUDIO_EXTERN) - t->c1=(t->c1 & ~0x7) | TDA9855_EXT; /* 0x7 is a mask for the int/ext */ - tda9855_write(client,TDA9855_C1,t->c1); - break; - case AUDC_SWITCH_MUTE: - if((t->c1 & ~TDA9855_MUTE) == 0) - t->c1|=TDA9855_MUTE; - else - t->c1&=~TDA9855_MUTE; - tda9855_write(client,TDA9855_C1,t->c1); - break; - -/* TDA9855 unsupported: */ -/* case AUDC_NEWCHANNEL: - case AUDC_SET_RADIO: - case AUDC_GET_DC: -*/ -#endif - default: - /* nothing */ - } - return 0; -} - - -static struct i2c_driver driver = { - "i2c tda9855 driver", - I2C_DRIVERID_TDA9855, - I2C_DF_NOTIFY, - tda9855_probe, - tda9855_detach, - tda9855_command, -}; - -static struct i2c_client client_template = -{ - "(unset)", /* name */ - -1, - 0, - 0, - NULL, - &driver -}; - -#ifdef MODULE -int init_module(void) -#else -int tda9855_init(void) -#endif -{ - i2c_add_driver(&driver); - return 0; -} - -#ifdef MODULE -void cleanup_module(void) -{ - i2c_del_driver(&driver); -} -#endif - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/char/tda985x.c b/drivers/char/tda985x.c new file mode 100644 index 000000000..62bcf15ba --- /dev/null +++ b/drivers/char/tda985x.c @@ -0,0 +1,532 @@ +/* + * For the TDA9850 and TDA9855 chips + * (The TDA9855 is used on the Diamond DTV2000 and the TDA9850 is used + * on STB cards. Other cards probably use these chips as well.) + * This driver will not complain if used with any + * other i2c device with the same address. + * + * Copyright (c) 1999 Gerd Knorr + * TDA9850 code and TDA9855.c merger by Eric Sandeen (eric_sandeen@bigfoot.com) + * This code is placed under the terms of the GNU General Public License + * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * Which was based on tda8425.c by Greg Alexander (c) 1998 + * + * OPTIONS: + * debug - set to 1 if you'd like to see debug messages + * chip - set to 9850 or 9855 to select your chip (default 9855) + * + * TODO: + * Fix channel change bug - sound goes out when changeing channels, mute + * and unmote to fix. - Is this still here? + * Fine tune sound + * Get rest of capabilities into video_audio struct... + * + * Revision: 0.4 - check for correct chip= insmod value + * also cleaned up comments a bit + * Revision: 0.3 - took out extraneous tda985x_write in tda985x_command + * Revision: 0.2 - added insmod option chip= + * Revision: 0.1 - original version + */ + +#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 <linux/videodev.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include "bttv.h" +#include "audiochip.h" + +MODULE_PARM(debug,"i"); +MODULE_PARM(chip,"i"); +MODULE_PARM_DESC(chip, "Type of chip to handle: 9850 or 9855"); + +static int debug = 0; /* insmod parameter */ +static int chip = 9855; /* insmod parameter */ + +/* Addresses to scan */ +#define I2C_TDA985x_L 0xb4 +#define I2C_TDA985x_H 0xb6 +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = { + I2C_TDA985x_L >> 1, + I2C_TDA985x_H >> 1, + I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +/* This is a superset of the TDA9850 and TDA9855 members */ + +struct tda985x { + int addr; + int rvol, lvol; + int bass, treble, sub; + int c4, c5, c6, c7; + int a1, a2, a3; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define dprintk if (debug) printk + +/* The TDA9850 and TDA9855 are both made by Philips Semiconductor + * http://www.semiconductors.philips.com + * TDA9850: I2C-bus controlled BTSC stereo/SAP decoder + * TDA9855: I2C-bus controlled BTSC stereo/SAP decoder and audio processor + * + * The TDA9850 has more or less a subset of the functions that the TDA9855 + * has. As a result, we can re-use many of these defines. Anything with + * TDA9855 is specific to that chip, anything with TDA9850 is specific + * to that chip, and anything with TDA985x is valid for either. + * + * To complicate things further, the TDA9850 uses labels C1 through C4 + * for subaddresses 0x04 through 0x07, while the TDA9855 uses + * C1 through C3 for subadresses 0x05 through 0x07 - quite confusing. + * To help keep things straight, I have renamed the various C[1,4] labels + * to C[4,7] so that the numerical label matches the hex value of the + * subaddress for both chips. At least the A[1,3] labels line up. :) + */ + + /* subaddresses for TDA9855 */ +#define TDA9855_VR 0x00 /* Volume, right */ +#define TDA9855_VL 0x01 /* Volume, left */ +#define TDA9855_BA 0x02 /* Bass */ +#define TDA9855_TR 0x03 /* Treble */ +#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ + + /* subaddresses for TDA9850 */ +#define TDA9850_C4 0x04 /* Control 1 for TDA9850 */ + + /* subaddesses for both chips */ +#define TDA985x_C5 0x05 /* Control 2 for TDA9850, Control 1 for TDA9855 */ +#define TDA985x_C6 0x06 /* Control 3 for TDA9850, Control 2 for TDA9855 */ +#define TDA985x_C7 0x07 /* Control 4 for TDA9850, Control 3 for TDA9855 */ +#define TDA985x_A1 0x08 /* Alignment 1 for both chips */ +#define TDA985x_A2 0x09 /* Alignment 2 for both chips */ +#define TDA985x_A3 0x0a /* Alignment 3 for both chips */ + + /* Masks for bits in TDA9855 subaddresses */ +/* 0x00 - VR in TDA9855 */ +/* 0x01 - VL in TDA9855 */ +/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) + * in 1dB steps - mute is 0x27 */ + + +/* 0x02 - BA in TDA9855 */ +/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) + * in .5dB steps - 0 is 0x0E */ + + +/* 0x03 - TR in TDA9855 */ +/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) + * in 3dB steps - 0 is 0x7 */ + + /* Masks for bits in both chips' subaddresses */ +/* 0x04 - SW in TDA9855, C4/Control 1 in TDA9850 */ +/* Unique to TDA9855: */ +/* 4 bits << 2 control subwoofer/surround gain from -14db (0x1) to 14db (0xf) + * in 3dB steps - mute is 0x0 */ + +/* Unique to TDA9850: */ +/* lower 4 bits control stereo noise threshold, over which stereo turns off + * set to values of 0x00 through 0x0f for Ster1 through Ster16 */ + + +/* 0x05 - C5 - Control 1 in TDA9855 , Control 2 in TDA9850*/ +/* Unique to TDA9855: */ +#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ +#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ +#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ +#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ + /* Bits 0 to 3 select various combinations + * of line in and line out, only the + * interesting ones are defined */ +#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ +#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ + +/* Unique to TDA9850: */ +/* lower 4 bits contol SAP noise threshold, over which SAP turns off + * set to values of 0x00 through 0x0f for SAP1 through SAP16 */ + + +/* 0x06 - C6 - Control 2 in TDA9855, Control 3 in TDA9850 */ +/* Common to TDA9855 and TDA9850: */ +#define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ +#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ +#define TDA985x_MONO 0 /* Forces Mono output */ +#define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ + +/* Unique to TDA9855: */ +#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ +#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ +#define TDA9855_LINEAR 0 /* Linear Stereo */ +#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ +#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ +#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ +#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ + + +/* 0x07 - C7 - Control 3 in TDA9855, Control 4 in TDA9850 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) + * in .5dB steps - 0dB is 0x7 */ + + +/* 0x08, 0x09 - A1 and A2 (read/write) */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 5 bites are wideband and spectral expander alignment + * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ +#define TDA985x_STP 1<<5 /* Stereo Pilot/detect (read-only) */ +#define TDA985x_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ +#define TDA985x_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ + + +/* 0x0a - A3 */ +/* Common to both TDA9855 and TDA9850: */ +/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), + * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ +#define TDA985x_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral */ + +/* Unique to TDA9855: */ +/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), + * 1200ohm (0x1), 2100ohm (0x3) */ + + +/* Begin code */ + +static int tda985x_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + dprintk("In tda985x_write\n"); + dprintk("Writing %d 0x%x\n", subaddr, val); + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda985x: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +static int tda985x_read(struct i2c_client *client) +{ + unsigned char buffer; + dprintk("In tda985x_read\n"); + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda985x: I/O error, trying (read)\n"); + return -1; + } + dprintk("Read 0x%02x\n", buffer); + return buffer; +} + +static int tda985x_set(struct i2c_client *client) +{ + struct tda985x *t = client->data; + unsigned char buf[16]; + dprintk("In tda985x_set\n"); + + if (chip == 9855) + { + dprintk(KERN_INFO + "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->rvol,t->lvol,t->bass,t->treble,t->sub, + t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9855_VR; + buf[1] = t->rvol; + buf[2] = t->lvol; + buf[3] = t->bass; + buf[4] = t->treble; + buf[5] = t->sub; + buf[6] = t->c5; + buf[7] = t->c6; + buf[8] = t->c7; + buf[9] = t->a1; + buf[10] = t->a2; + buf[11] = t->a3; + if (12 != i2c_master_send(client,buf,12)) { + printk(KERN_WARNING "tda9855: I/O error, trying tda985x_set\n"); + return -1; + } + } + + else if (chip == 9850) + { + dprintk(KERN_INFO + "tda985x_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", + t->c4,t->c5,t->c6,t->c7,t->a1,t->a2,t->a3); + buf[0] = TDA9850_C4; + buf[1] = t->c4; + buf[2] = t->c5; + buf[3] = t->c6; + buf[4] = t->c7; + buf[5] = t->a1; + buf[6] = t->a2; + buf[7] = t->a3; + if (8 != i2c_master_send(client,buf,8)) { + printk(KERN_WARNING "tda9850: I/O error, trying tda985x_set\n"); + return -1; + } + } + + return 0; +} + +static void do_tda985x_init(struct i2c_client *client) +{ + struct tda985x *t = client->data; + dprintk("In tda985x_init\n"); + + if (chip == 9855) + { + printk("Using tda9855 options\n"); + t->rvol = 0x6f; /* 0dB */ + t->lvol = 0x6f; /* 0dB */ + t->bass = 0x0e; /* 0dB */ + t->treble = (0x07 << 1); /* 0dB */ + t->sub = 0x8 << 2; /* 0dB */ + t->c5 = TDA9855_MUTE | TDA9855_AVL | + TDA9855_LOUD | TDA9855_INT; + /* Set Mute, AVL, Loudness off, Internal sound */ + t->c6 = TDA985x_STEREO | TDA9855_LINEAR | + TDA9855_TZCM | TDA9855_VZCM; + /* Stereo linear mode, also wait til zero crossings */ + t->c7 = 0x07; /* 0dB input gain */ + } + + else if (chip == 9850) + { + printk("Using tda9850 options\n"); + t->c4 = 0x08; /* Set stereo noise thresh to nominal */ + t->c5 = 0x08; /* Set SAP noise threshold to nominal */ + t->c6 = TDA985x_STEREO; /* Select Stereo mode for decoder */ + t->c7 = 0x07; /* 0dB input gain */ + } + + /* The following is valid for both chip types */ + t->a1 = 0x10; /* Select nominal wideband expander */ + t->a2 = 0x10; /* Select nominal spectral expander and 30mV trigger */ + t->a3 = 0x3; /* Set: nominal timing current, 420ohm AVL attack */ + + tda985x_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda985x_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda985x *t; + struct i2c_client *client; + dprintk("In tda985x_attach\n"); + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + do_tda985x_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA985x"); + printk(KERN_INFO "tda985x: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda985x_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda985x_attach); + return 0; +} + +static int tda985x_detach(struct i2c_client *client) +{ + struct tda985x *t = client->data; + + do_tda985x_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda985x_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda985x *t = client->data; + dprintk("In tda985x_command...\n"); +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + dprintk("VIDIOCGAUDIO\n"); + if (chip == 9855) + { + int left,right; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is 0x27 max is 0x7f, vstep is 2e8 */ + left = (t->lvol-0x27)*0x2e8; + right = (t->rvol-0x27)*0x2e8; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(left<right)? + (65535-va->balance) : va->balance; + va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max 0x19 */ + va->treble = ((t->treble>>1)-0x3)*0x1c71; + } + + /* Valid for both chips: */ + { + va->mode = ((TDA985x_STP | TDA985x_SAPP) & + tda985x_read(client)) >> 4; + /* Add mono mode regardless of SAP and stereo */ + /* Allows forced mono */ + va->mode |= VIDEO_SOUND_MONO; + } + + break; /* VIDIOCGAUDIO case */ + } + + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + dprintk("VIDEOCSAUDIO...\n"); + if (chip == 9855) + { + int left,right; + + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = left/0x2e8+0x27; + t->rvol = right/0x2e8+0x27; + t->bass = va->bass/0xccc+0x6; + t->treble = (va->treble/0x1c71+0x3)<<1; + tda985x_write(client,TDA9855_VL,t->lvol); + tda985x_write(client,TDA9855_VR,t->rvol); + tda985x_write(client,TDA9855_BA, t->bass); + tda985x_write(client,TDA9855_TR,t->treble); + } + + /* The following is valid for both chips */ + + switch (va->mode) { + case VIDEO_SOUND_MONO: + dprintk("VIDEO_SOUND_MONO\n"); + t->c6= TDA985x_MONO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_STEREO: + dprintk("VIDEO_SOUND_STEREO\n"); + t->c6= TDA985x_STEREO | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + case VIDEO_SOUND_LANG1: + dprintk("VIDEO_SOUND_LANG1\n"); + t->c6= TDA985x_SAP | (t->c6 & 0x3f); + tda985x_write(client,TDA985x_C6,t->c6); + break; + } /* End of (va->mode) switch */ + + break; + + } /* end of VIDEOCSAUDIO case */ + + default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ + + /* nothing */ + dprintk("Default\n"); + + } /* end of (cmd) switch */ + + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda985x driver", + I2C_DRIVERID_TDA9855, /* Get new one for TDA985x? */ + I2C_DF_NOTIFY, + tda985x_probe, + tda985x_detach, + tda985x_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda985x_init(void) +#endif +{ + if ( (chip != 9850) && (chip != 9855) ) + { + printk(KERN_ERR "tda985x: chip parameter must be 9850 or 9855\n"); + return -EINVAL; + } + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 705d876b3..ed504dcfe 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1321,7 +1321,7 @@ retry_open: set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ minor -= driver->minor_start; devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start)); - tty_register_devfs(&pts_driver[major], 0, + tty_register_devfs(&pts_driver[major], DEVFS_FL_NO_PERSISTENCE, pts_driver[major].minor_start + minor); noctty = 1; goto init_dev_done; @@ -2003,7 +2003,6 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags, struct tty_struct tty; char buf[32]; - flags |= DEVFS_FL_DEFAULT; tty.driver = *driver; tty.device = MKDEV (driver->major, minor); switch (tty.device) { @@ -2012,28 +2011,22 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags, mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; break; default: - flags |= DEVFS_FL_AUTO_OWNER; break; } - if ((minor < driver->minor_start) || - (minor >= driver->minor_start + driver->num)) { + if ( (minor < driver->minor_start) || + (minor >= driver->minor_start + driver->num) ) { printk(KERN_ERR "Attempt to register invalid minor number " "with devfs (%d:%d).\n", (int)driver->major,(int)minor); return; } - if (driver->type == TTY_DRIVER_TYPE_CONSOLE) { - flags |= DEVFS_FL_AOPEN_NOTIFY; - flags &= ~DEVFS_FL_AUTO_OWNER; - } # ifdef CONFIG_UNIX98_PTYS if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) && (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) { - flags &= ~DEVFS_FL_AUTO_OWNER; uid = current->uid; gid = current->gid; } # endif - devfs_register (NULL, tty_name (&tty, buf), 0, flags, + devfs_register (NULL, tty_name (&tty, buf), 0,flags | DEVFS_FL_DEFAULT, driver->major, minor, mode, uid, gid, &tty_fops, NULL); #endif /* CONFIG_DEVFS_FS */ diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c index 99dc750ee..dfea37d63 100644 --- a/drivers/char/tuner.c +++ b/drivers/char/tuner.c @@ -12,6 +12,7 @@ #include <linux/videodev.h> #include "tuner.h" +#include "audiochip.h" /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; @@ -334,6 +335,9 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) t->type,tuners[t->type].name); strncpy(client->name, tuners[t->type].name, sizeof(client->name)); break; + case AUDC_SET_RADIO: + t->radio = 1; + break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a @@ -342,6 +346,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct video_channel *vc = arg; + t->radio = 0; if (t->type == TUNER_PHILIPS_SECAM) { t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0; set_tv_freq(client,t->freq); diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index cfcdbfcde..f0b1aaf4d 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -60,9 +60,6 @@ static struct video_init video_init_list[]={ {"i2c-tuner", i2c_tuner_init}, {"bttv", init_bttv_cards}, #endif -#ifdef CONFIG_VIDEO_STRADIS - {"stradis", init_stradis_cards}, -#endif #ifdef CONFIG_VIDEO_BWQCAM {"bw-qcam", init_bw_qcams}, #endif |