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