summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/ChangeLog20
-rw-r--r--drivers/char/Config.in40
-rw-r--r--drivers/char/Makefile77
-rw-r--r--drivers/char/README.epca2
-rw-r--r--drivers/char/adbmouse.c304
-rw-r--r--drivers/char/amikeyb.c19
-rw-r--r--drivers/char/apm_bios.c5
-rw-r--r--drivers/char/atarimouse.c26
-rw-r--r--drivers/char/bt848.h21
-rw-r--r--drivers/char/bttv.c775
-rw-r--r--drivers/char/bttv.h61
-rw-r--r--drivers/char/bw-qcam.c5
-rw-r--r--drivers/char/c-qcam.c17
-rw-r--r--drivers/char/conmakehash.c1
-rw-r--r--drivers/char/console.c2986
-rw-r--r--drivers/char/console_macros.h71
-rw-r--r--drivers/char/consolemap.c481
-rw-r--r--drivers/char/cyclades.c994
-rw-r--r--drivers/char/dn_keyb.c14
-rw-r--r--drivers/char/dsp56k.c50
-rw-r--r--drivers/char/epca.c2
-rw-r--r--drivers/char/esp.c314
-rw-r--r--drivers/char/esp.h107
-rw-r--r--drivers/char/fbmem.c652
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.c2
-rw-r--r--drivers/char/ftape/lowlevel/ftape_syms.c2
-rw-r--r--drivers/char/ftape/zftape/zftape_syms.c2
-rw-r--r--drivers/char/h8.c71
-rw-r--r--drivers/char/h8.h2
-rw-r--r--drivers/char/hfmodem/Makefile2
-rw-r--r--drivers/char/hfmodem/refclock.c41
-rw-r--r--drivers/char/i2c.c11
-rw-r--r--drivers/char/i2c.h166
-rw-r--r--drivers/char/istallion.c47
-rw-r--r--drivers/char/joystick.c298
-rw-r--r--drivers/char/keyboard.c73
-rw-r--r--drivers/char/lp.c108
-rw-r--r--drivers/char/lp_intern.c131
-rw-r--r--drivers/char/lp_m68k.c106
-rw-r--r--drivers/char/mac_SCC.c1543
-rw-r--r--drivers/char/mac_SCC.h321
-rw-r--r--drivers/char/macmouse.c2
-rw-r--r--drivers/char/mem.c56
-rw-r--r--drivers/char/misc.c21
-rw-r--r--drivers/char/msp3400.c972
-rw-r--r--drivers/char/msp3400.h5
-rw-r--r--drivers/char/n_tty.c55
-rw-r--r--drivers/char/nvram.c21
-rw-r--r--drivers/char/pc_keyb.c23
-rw-r--r--drivers/char/pc_keyb.h2
-rw-r--r--drivers/char/pcwd.c4
-rw-r--r--drivers/char/pcxx.c2
-rw-r--r--drivers/char/pms.c3
-rw-r--r--drivers/char/psaux.c2
-rw-r--r--drivers/char/pty.c148
-rw-r--r--drivers/char/radio-aimslab.c373
-rw-r--r--drivers/char/radio-aztech.c324
-rw-r--r--drivers/char/radio-rtrack2.c272
-rw-r--r--drivers/char/radio-sf16fmi.c285
-rw-r--r--drivers/char/radio-zoltrix.c333
-rw-r--r--drivers/char/radio.c234
-rw-r--r--drivers/char/random.c1071
-rw-r--r--drivers/char/rocket.c191
-rw-r--r--drivers/char/rocket_int.h90
-rw-r--r--drivers/char/rsf16fmi.h13
-rw-r--r--drivers/char/rtc.c11
-rw-r--r--drivers/char/rtrack.c213
-rw-r--r--drivers/char/rtrack.h25
-rw-r--r--drivers/char/saa5249.c707
-rw-r--r--drivers/char/selection.c99
-rw-r--r--drivers/char/serial.c243
-rw-r--r--drivers/char/stallion.c16
-rw-r--r--drivers/char/sysrq.c6
-rw-r--r--drivers/char/tga.c1169
-rw-r--r--drivers/char/tty_io.c111
-rw-r--r--drivers/char/tuner.c10
-rw-r--r--drivers/char/vc_screen.c94
-rw-r--r--drivers/char/vesa_blank.c290
-rw-r--r--drivers/char/vga.c705
-rw-r--r--drivers/char/videodev.c78
-rw-r--r--drivers/char/vt.c288
-rw-r--r--drivers/char/wdt.c2
82 files changed, 11192 insertions, 7347 deletions
diff --git a/drivers/char/ChangeLog b/drivers/char/ChangeLog
index 95d6741c5..eddd9e674 100644
--- a/drivers/char/ChangeLog
+++ b/drivers/char/ChangeLog
@@ -33,13 +33,13 @@ Sat Nov 22 07:53:36 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
it.
* serial.c (autoconfig): Change 16750 test to hopefully eliminate
- false results by people with strange 16550A's being
- detected as 16750's. Hopefully 16750's will still be
- detected as 16750, and other wierd UART's won't get poorly
+ false results by people with strange 16550As being
+ detected as 16750s. Hopefully 16750s will still be
+ detected as 16750, and other weird UARTs won't get poorly
autodetected. If this doesn't work, I'll have to disable
- the auto identification for the 16750....
+ the auto identification for the 16750.
- * tty_io.c (tty_hangup): Now do actually do the tty hangup
+ * tty_io.c (tty_hangup): Now actually do the tty hangup
processing during the timer processing, and disable
interrupts while doing the hangup processing. This avoids
several nasty race conditions which happened when the
@@ -84,7 +84,7 @@ Thu Feb 27 01:53:08 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
* serial.c (change_speed): Add support for the termios flag
CMSPAR, which allows the user to select stick parity.
- (i.e, if PARODD is set, the the parity bit is always 1; if
+ (i.e, if PARODD is set, the parity bit is always 1; if
PARRODD is not set, then the parity bit is always 0).
Wed Feb 26 19:03:10 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
@@ -129,7 +129,7 @@ Wed Feb 12 14:50:44 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
* serial.c: Update routines to use the new 2.1 memory access
routines.
-Wed Dec 4 07:51:52 1996 Theodre Ts'o <tytso@localhost.mit.edu>
+Wed Dec 4 07:51:52 1996 Theodore Ts'o <tytso@localhost.mit.edu>
* serial.c (change_speed): Use save_flags(); cli() and
restore_flags() in order to ensure we don't accidentally
@@ -139,7 +139,7 @@ Wed Dec 4 07:51:52 1996 Theodre Ts'o <tytso@localhost.mit.edu>
should be off this whole time, but we eventually will want
to reduce this window.
-Thu Nov 21 10:05:22 1996 Theodre Ts'o <tytso@localhost.mit.edu>
+Thu Nov 21 10:05:22 1996 Theodore Ts'o <tytso@localhost.mit.edu>
* tty_ioctl.c (tty_wait_until_sent): Always check the driver
wait_until_ready routine, even if there are no characters
@@ -174,7 +174,7 @@ Thu Nov 21 10:05:22 1996 Theodre Ts'o <tytso@localhost.mit.edu>
DTR and RTS. DTR and RTS are only be changed on the
transition to or from the B0 state.
(rs_close): Wait for the characters to drain based on
- info->timeout. At low baud rates (50bps), it may take a
+ info->timeout. At low baud rates (50 bps), it may take a
long time for the FIFO to completely drain out!
(rs_wait_until_sent): Fixed timeout handling. Now
releases control to the scheduler, but checks frequently
@@ -479,7 +479,7 @@ Sat Feb 18 12:13:51 1995 Theodore Y. Ts'o (tytso@rt-11)
Fri Feb 17 09:34:09 1995 Theodore Y. Ts'o (tytso@rt-11)
* serial.c (rs_interrupt_single, rs_interrupt, rs_interrupt_multi):
- Change the the number of passes made from 64 to be 256,
+ Change the number of passes made from 64 to be 256,
configurable with the #define RS_ISR_PASS_LIMIT.
* serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index fad48a260..eef6d8f66 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -39,14 +39,10 @@ if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
bool 'Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
fi
tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
- if [ "$CONFIG_ESPSERIAL" = "y" -o "$CONFIG_ESPSERIAL" = "m" ]; then
- int ' DMA channel' CONFIG_ESPSERIAL_DMA_CHANNEL 1
- int ' Receive FIFO trigger level' CONFIG_ESPSERIAL_RX_TRIGGER 768
- int ' Transmit FIFO trigger level' CONFIG_ESPSERIAL_TX_TRIGGER 768
- int ' Hardware flow off level' CONFIG_ESPSERIAL_FLOW_OFF 1016
- int ' Hardware flow on level' CONFIG_ESPSERIAL_FLOW_ON 944
- int ' Receiver timeout' CONFIG_ESPSERIAL_RX_TMOUT 128
- fi
+fi
+bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
fi
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
@@ -114,31 +110,35 @@ bool 'Enhanced Real Time Clock Support' CONFIG_RTC
if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
bool 'Tadpole ANA H8 Support' CONFIG_H8
fi
+
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
+ if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then
+ hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 20f
+ fi
+ dep_tristate 'Aztech/Packard Bell Radio' CONFIG_RADIO_AZTECH $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then
+ hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
+ fi
dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV
dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV
fi
dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
- #dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
- if [ "$CONFIG_VIDEO_SAA5249" != "n" ]; then
- define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_SAA5249
+ dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
+ dep_tristate 'SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
+ hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
fi
- if [ "$CONFIG_VIDEO_BT848" != "n" ]; then
- define_bool CONFIG_BUS_I2C $CONFIG_VIDEO_BT848
+ dep_tristate 'Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
+ if [ "$CONFIG_RADIO_ZOLTRIX" != "n" ]; then
+ hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
fi
fi
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'PC joystick support' CONFIG_JOYSTICK
-bool 'Radio Device Support' CONFIG_MISC_RADIO
-if [ "$CONFIG_MISC_RADIO" != "n" ]; then
- bool ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK
- if [ "$CONFIG_RADIO_RTRACK" != "n" ]; then
- hex ' RadioTrack i/o port (0x20f or 0x30f)' CONFIG_RADIO_RTRACK_PORT 0x20f
- fi
-fi
mainmenu_option next_comment
comment 'Ftape, the floppy tape device driver'
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index b598d7769..9f2a484e0 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -24,8 +24,11 @@ L_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o
LX_OBJS := pty.o
ifdef CONFIG_VT
-L_OBJS += console.o vt.o vc_screen.o consolemap.o consolemap_deftbl.o
-LX_OBJS += selection.o
+L_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o
+LX_OBJS += console.o selection.o
+endif
+ifdef CONFIG_FB
+ LX_OBJS += fbmem.o
endif
ifeq ($(CONFIG_SERIAL),y)
@@ -249,6 +252,16 @@ ifdef CONFIG_SGI_GRAPHICS
M = y
endif
+ifeq ($(CONFIG_MACMOUSE),y)
+M = y
+L_OBJS += macmouse.o
+else
+ ifeq ($(CONFIG_MACMOUSE),m)
+ M_OBJS += macmouse.o
+ MM = m
+ endif
+endif
+
ifdef CONFIG_SUN_MOUSE
M = y
endif
@@ -309,26 +322,30 @@ else
endif
ifeq ($(CONFIG_BUS_I2C),y)
- LX_OBJS += i2c.o
+ L_I2C=y
else
ifeq ($(CONFIG_BUS_I2C),m)
- MX_OBJS += i2c.o
+ M_I2C=y
endif
endif
ifeq ($(CONFIG_VIDEO_BT848),y)
L_OBJS += bttv.o msp3400.o tuner.o
+L_I2C=y
else
ifeq ($(CONFIG_VIDEO_BT848),m)
M_OBJS += bttv.o msp3400.o tuner.o
+ M_I2C=y
endif
endif
ifeq ($(CONFIG_VIDEO_SAA5249),y)
L_OBJS += saa5249.o
+L_I2C=y
else
ifeq ($(CONFIG_VIDEO_SAA5249),m)
M_OBJS += saa5249.o
+ M_I2C=y
endif
endif
@@ -356,12 +373,37 @@ else
endif
endif
-ifeq ($(CONFIG_MISC_RADIO),y)
-L_OBJS += radio.o
- ifeq ($(CONFIG_RADIO_RTRACK),y)
- L_OBJS += rtrack.o
+ifeq ($(CONFIG_RADIO_AZTECH),y)
+L_OBJS += radio-aztech.o
+else
+ ifeq ($(CONFIG_RADIO_AZTECH),m)
+ M_OBJS += radio-aztech.o
endif
-endif
+endif
+
+ifeq ($(CONFIG_RADIO_SF16FMI),y)
+L_OBJS += radio-sf16fmi.o
+else
+ ifeq ($(CONFIG_RADIO_SF16FMI),m)
+ M_OBJS += radio-sf16fmi.o
+ endif
+endif
+
+ifeq ($(CONFIG_RADIO_RTRACK),y)
+L_OBJS += radio-aimslab.o
+else
+ ifeq ($(CONFIG_RADIO_RTRACK),m)
+ M_OBJS += radio-aimslab.o
+ endif
+endif
+
+ifeq ($(CONFIG_RADIO_ZOLTRIX),y)
+L_OBJS += radio-zoltrix.o
+else
+ ifeq ($(CONFIG_RADIO_ZOLTRIX),m)
+ M_OBJS += radio-zoltrix.o
+ endif
+endif
ifeq ($(CONFIG_QIC02_TAPE),y)
L_OBJS += tpqic02.o
@@ -401,16 +443,15 @@ else
endif
endif
-ifdef CONFIG_VT
- ifdef CONFIG_TGA_CONSOLE
- L_OBJS += tga.o
- else
- ifdef CONFIG_VGA_CONSOLE
- L_OBJS += vga.o vesa_blank.o
- endif
- endif
+ifeq ($(L_I2C),y)
+LX_OBJS += i2c.o
+else
+ ifeq ($(M_I2C),y)
+ MX_OBJS += i2c.o
+ endif
endif
+
ifeq ($(CONFIG_HFMODEM),y)
ALL_SUB_DIRS += hfmodem
SUB_DIRS += hfmodem
@@ -427,7 +468,7 @@ include $(TOPDIR)/Rules.make
fastdep:
conmakehash: conmakehash.c
- $(HOSTCC) -o conmakehash conmakehash.c
+ $(HOSTCC) $(HOSTCFLAGS) -o conmakehash conmakehash.c
consolemap_deftbl.c: $(FONTMAPFILE) conmakehash
./conmakehash $(FONTMAPFILE) > consolemap_deftbl.c
diff --git a/drivers/char/README.epca b/drivers/char/README.epca
index 3561608f1..0efccae58 100644
--- a/drivers/char/README.epca
+++ b/drivers/char/README.epca
@@ -44,7 +44,7 @@ The four user programs listed below are described in this document:
as it does not require the rebuilding of the kernel. In order to use lilo
to configure Digi boards at boot time an appropriate append command should
be added to /etc/lilo.conf below the appropriate label decleration.
- See footer 4. The append commands format is a string of comma seperated
+ See footer 4. The append commands format is a string of comma separated
identifiers or integers used to configure supported boards. These six
values in order are:
diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c
new file mode 100644
index 000000000..35e0c833b
--- /dev/null
+++ b/drivers/char/adbmouse.c
@@ -0,0 +1,304 @@
+/*
+ * Macintosh ADB Mouse driver for Linux
+ *
+ * 27 Oct 1997 Michael Schmitz
+ * logitech fixes by anthony tong
+ *
+ * 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/adb_mouse.h>
+#include <asm/segment.h>
+#include <asm/processor.h>
+
+static struct mouse_status mouse;
+static int adb_mouse_x_threshold = 2, adb_mouse_y_threshold = 2;
+static int adb_mouse_buttons = 0;
+
+extern void (*adb_mouse_interrupt_hook) (char *, int);
+
+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 adb_mouse_interrupt(char *buf, int nb)
+{
+ static int buttons = 7;
+
+ /*
+ 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 (nb > 0) { /* real packet : use buttons? */
+ if (console_loglevel >= 8)
+ printk("adb_mouse: real data; ");
+ /* button 1 (left, bit 2) : always significant ! */
+ buttons = (buttons&3) | (buf[1] & 0x80 ? 4 : 0); /* 1+2 unchanged */
+ /* button 2 (middle) */
+ buttons = (buttons&5) | (buf[2] & 0x80 ? 2 : 0); /* 2+3 unchanged */
+ /* button 3 (right) present?
+ * on a logitech mouseman, the right and mid buttons sometimes behave
+ * strangely until they both have been pressed after booting. */
+ /* data valid only if extended mouse format ! (buf[3] = 0 else) */
+ if ( nb == 6 )
+ buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
+ } else { /* fake packet : use 2+3 */
+ if (console_loglevel >= 8)
+ printk("adb_mouse: fake data; ");
+ /* 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[2] & 0x80 ? 1 : 0) |
+ (buf[3] & 0x80 ? 2 : 0));
+ }
+
+ add_mouse_randomness(((~buttons & 7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
+ mouse.buttons = buttons & 7;
+ mouse.dx += ((buf[2]&0x7f) < 64 ? (buf[2]&0x7f) : (buf[2]&0x7f)-128 );
+ mouse.dy -= ((buf[1]&0x7f) < 64 ? (buf[1]&0x7f) : (buf[1]&0x7f)-128 );
+
+ if (console_loglevel >= 8)
+ printk(" %X %X %X buttons %x dx %d dy %d \n",
+ buf[1], buf[2], buf[3], mouse.buttons, mouse.dx, mouse.dy);
+
+ mouse.ready = 1;
+ wake_up_interruptible(&mouse.wait);
+ if (mouse.fasyncptr)
+ kill_fasync(mouse.fasyncptr, SIGIO);
+
+}
+
+static int fasync_mouse(struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(filp, on, &mouse.fasyncptr);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static int release_mouse(struct inode *inode, struct file *file)
+{
+ fasync_mouse(file, 0);
+ if (--mouse.active)
+ return 0;
+
+ adb_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;
+ adb_mouse_buttons = 0;
+ MOD_INC_USE_COUNT;
+ adb_mouse_interrupt_hook = adb_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 adb_mouse_fops = {
+ NULL, /* mouse_seek */
+ read_mouse,
+ write_mouse,
+ NULL, /* mouse_readdir */
+ mouse_poll,
+ NULL, /* mouse_ioctl */
+ NULL, /* mouse_mmap */
+ open_mouse,
+ release_mouse,
+ NULL,
+ fasync_mouse,
+};
+
+#define ADB_MOUSE_MINOR 10
+
+static struct miscdevice adb_mouse = {
+ ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
+};
+
+__initfunc(int adb_mouse_init(void))
+{
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.wait = NULL;
+
+ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+ return -ENODEV;
+ printk(KERN_INFO "Macintosh ADB mouse installed.\n");
+ misc_register(&adb_mouse);
+ return 0;
+}
+
+
+#define MIN_THRESHOLD 1
+#define MAX_THRESHOLD 20 /* more seems not reasonable... */
+
+__initfunc(void adb_mouse_setup(char *str, int *ints))
+{
+ if (ints[0] < 1) {
+ printk( "adb_mouse_setup: no arguments!\n" );
+ return;
+ }
+ else if (ints[0] > 2) {
+ printk( "adb_mouse_setup: too many arguments\n" );
+ }
+
+ if (ints[1] < MIN_THRESHOLD || ints[1] > MAX_THRESHOLD)
+ printk( "adb_mouse_setup: bad threshold value (ignored)\n" );
+ else {
+ adb_mouse_x_threshold = ints[1];
+ adb_mouse_y_threshold = ints[1];
+ if (ints[0] > 1) {
+ if (ints[2] < MIN_THRESHOLD || ints[2] > MAX_THRESHOLD)
+ printk("adb_mouse_setup: bad threshold value (ignored)\n" );
+ else
+ adb_mouse_y_threshold = ints[2];
+ }
+ }
+
+}
+
+#ifdef MODULE
+#include <asm/setup.h>
+
+int init_module(void)
+{
+ return adb_mouse_init();
+}
+
+void cleanup_module(void)
+{
+ misc_deregister(&adb_mouse);
+}
+#endif
diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c
index 9647caf90..164fc5df5 100644
--- a/drivers/char/amikeyb.c
+++ b/drivers/char/amikeyb.c
@@ -301,13 +301,13 @@ __initfunc(int amiga_keyb_init(void))
return -EIO;
/* setup key map */
- memcpy(plain_map, amiplain_map, sizeof(plain_map));
- memcpy(shift_map, amishift_map, sizeof(shift_map));
- memcpy(altgr_map, amialtgr_map, sizeof(altgr_map));
- memcpy(ctrl_map, amictrl_map, sizeof(ctrl_map));
- memcpy(shift_ctrl_map, amishift_ctrl_map, sizeof(shift_ctrl_map));
- memcpy(alt_map, amialt_map, sizeof(alt_map));
- memcpy(ctrl_alt_map, amictrl_alt_map, sizeof(ctrl_alt_map));
+ memcpy(key_maps[0], amiplain_map, sizeof(plain_map));
+ memcpy(key_maps[1], amishift_map, sizeof(plain_map));
+ memcpy(key_maps[2], amialtgr_map, sizeof(plain_map));
+ memcpy(key_maps[4], amictrl_map, sizeof(plain_map));
+ memcpy(key_maps[5], amishift_ctrl_map, sizeof(plain_map));
+ memcpy(key_maps[8], amialt_map, sizeof(plain_map));
+ memcpy(key_maps[12], amictrl_alt_map, sizeof(plain_map));
/*
* Initialize serial data direction.
@@ -341,3 +341,8 @@ int amiga_kbdrate( struct kbd_repeat *k )
return( 0 );
}
+
+/* for "kbd-reset" cmdline param */
+__initfunc(void amiga_kbd_reset_setup(char *str, int *ints))
+{
+}
diff --git a/drivers/char/apm_bios.c b/drivers/char/apm_bios.c
index c461cf709..e9e964c43 100644
--- a/drivers/char/apm_bios.c
+++ b/drivers/char/apm_bios.c
@@ -38,7 +38,7 @@
* Linux 1.3.85
* 1.1: support user-space standby and suspend, power off after system
* halted, Linux 1.3.98
- * 1.2: When resetting RTC after resume, take care so that the the time
+ * 1.2: When resetting RTC after resume, take care so that the time
* is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
* <jtoth@princeton.edu>); improve interaction between
* screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
@@ -515,6 +515,8 @@ static int apm_get_power_status(u_short *status, u_short *bat, u_short *life)
return APM_SUCCESS;
}
+#if 0
+/* not used anywhere */
static int apm_get_battery_status(u_short which,
u_short *bat, u_short *life, u_short *nbat)
{
@@ -532,6 +534,7 @@ static int apm_get_battery_status(u_short which,
return (error >> 8);
return APM_SUCCESS;
}
+#endif
static inline int apm_engage_power_management(u_short device)
{
diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c
index 707e9d9e2..113395dba 100644
--- a/drivers/char/atarimouse.c
+++ b/drivers/char/atarimouse.c
@@ -21,10 +21,10 @@
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/init.h>
+#include <linux/busmouse.h>
#include <asm/setup.h>
#include <asm/atarikb.h>
-#include <asm/atari_mouse.h>
#include <asm/uaccess.h>
static struct mouse_status mouse;
@@ -160,15 +160,21 @@ static struct miscdevice atari_mouse = {
__initfunc(int atari_mouse_init(void))
{
- mouse.active = 0;
- mouse.ready = 0;
- mouse.wait = NULL;
+ int r;
- if (!MACH_IS_ATARI)
- return -ENODEV;
- printk(KERN_INFO "Atari mouse installed.\n");
- misc_register(&atari_mouse);
- return 0;
+ if (!MACH_IS_ATARI)
+ return -ENODEV;
+
+ mouse.active = 0;
+ mouse.ready = 0;
+ mouse.wait = NULL;
+
+ r = misc_register(&atari_mouse);
+ if (r)
+ return r;
+
+ printk(KERN_INFO "Atari mouse installed.\n");
+ return 0;
}
@@ -201,8 +207,6 @@ __initfunc(void atari_mouse_setup( char *str, int *ints ))
}
#ifdef MODULE
-#include <asm/setup.h>
-
int init_module(void)
{
return atari_mouse_init();
diff --git a/drivers/char/bt848.h b/drivers/char/bt848.h
index 5a76ea02a..a50e31a5c 100644
--- a/drivers/char/bt848.h
+++ b/drivers/char/bt848.h
@@ -40,6 +40,7 @@
#define BT848_DSTATUS_FIELD (1<<5)
#define BT848_DSTATUS_NUML (1<<4)
#define BT848_DSTATUS_CSEL (1<<3)
+#define BT848_DSTATUS_PLOCK (1<<2)
#define BT848_DSTATUS_LOF (1<<1)
#define BT848_DSTATUS_COF (1<<0)
@@ -55,10 +56,12 @@
#define BT848_IFORM_XTAUTO (3<<3)
#define BT848_IFORM_XTBOTH (3<<3)
#define BT848_IFORM_NTSC 1
+#define BT848_IFORM_NTSC_J 2
#define BT848_IFORM_PAL_BDGHI 3
#define BT848_IFORM_PAL_M 4
#define BT848_IFORM_PAL_N 5
#define BT848_IFORM_SECAM 6
+#define BT848_IFORM_PAL_NC 7
#define BT848_IFORM_AUTO 0
#define BT848_IFORM_NORM 7
@@ -114,6 +117,12 @@
#define BT848_SCLOOP_HFILT_QCIF (2<<3)
#define BT848_SCLOOP_HFILT_ICON (3<<3)
+#define BT848_SCLOOP_PEAK (1<<7)
+#define BT848_SCLOOP_HFILT_MINP (1<<3)
+#define BT848_SCLOOP_HFILT_MEDP (2<<3)
+#define BT848_SCLOOP_HFILT_MAXP (3<<3)
+
+
#define BT848_OFORM 0x048
#define BT848_OFORM_RANGE (1<<7)
#define BT848_OFORM_CORE0 (0<<5)
@@ -213,6 +222,7 @@
#define BT848_VBI_PACK_DEL_EXT_FRAME 2
#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1
+
#define BT848_INT_STAT 0x100
#define BT848_INT_MASK 0x104
@@ -318,4 +328,15 @@
#define BT848_RISC_SKIP123 (0x0a<<28)
#define BT848_RISC_WRITE1S23 (0x0b<<28)
+
+
+/* Bt848A and Bt849 only !! */
+#define BT848_TGLB 0x080
+#define BT848_TGCTRL 0x084
+#define BT848_FCAP 0x0E8
+#define BT848_PLL_F_LO 0x0F0
+#define BT848_PLL_F_HI 0x0F4
+#define BT848_PLL_XCI 0x0F8
+
+
#endif
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index 97d5794f1..8bb3f203e 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -24,22 +24,25 @@
TODO:
- * think of some good ioctls for Video4Linux to handle
- YUV, planar YUV, ... grabs and sell them to AC :-)
* move norm from tuner to channel struct!?
composite source from a satellite tuner can deliver different norms
depending on tuned channel
* mmap VBI data?
+ * use new PCI routines
+ * fix RAW Composite grabbing for NTSC
+ * allow for different VDELAY in RAW grabbing?
+ * extra modules for tda9850, tda8425, any volunteers???
+ * support 15bpp
*/
#include <linux/module.h>
-#include <linux/bios32.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>
#include <linux/pci.h>
#include <linux/signal.h>
@@ -55,7 +58,7 @@
#include <linux/version.h>
#include <asm/uaccess.h>
-#include "i2c.h"
+#include <linux/i2c.h>
#include "bttv.h"
#include "tuner.h"
@@ -153,6 +156,7 @@ static void * rvmalloc(unsigned long size)
mem=vmalloc(size);
if (mem)
{
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
adr=(unsigned long) mem;
while (size > 0)
{
@@ -193,7 +197,7 @@ static void rvfree(void * mem, unsigned long size)
static int fbuffer_alloc(struct bttv *btv)
{
if(!btv->fbuffer)
- btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000);
+ btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
else
printk(KERN_ERR "bttv: Double alloc of fbuffer!\n");
if(!btv->fbuffer)
@@ -242,7 +246,7 @@ static int I2CRead(struct i2c_bus *bus, unsigned char addr)
stat=btread(BT848_INT_STAT);
if (stat & BT848_INT_I2CDONE)
break;
- udelay(1000);
+ mdelay(1);
}
if (!i)
@@ -284,7 +288,7 @@ static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,
stat=btread(BT848_INT_STAT);
if (stat & BT848_INT_I2CDONE)
break;
- udelay(1000);
+ mdelay(1);
}
if (!i)
@@ -349,9 +353,9 @@ void attach_inform(struct i2c_bus *bus, int id)
break;
case I2C_DRIVERID_TUNER:
btv->have_tuner = 1;
- if (btv->type == BTTV_MIRO)
+ if (btv->tuner_type != -1)
{
- tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
+ tunertype=btv->tuner_type;
i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER,
TUNER_SET_TYPE,&tunertype);
}
@@ -393,28 +397,50 @@ static struct i2c_bus bttv_i2c_bus_template =
/* ----------------------------------------------------------------------- */
+
+struct tvcard
+{
+ int inputs;
+ int tuner;
+ int svhs;
+ u32 gpiomask;
+ u32 muxsel[8];
+ u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */
+};
+
+static struct tvcard tvcards[] =
+{
+ /* default */
+ { 3, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
+ /* MIRO */
+ { 4, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10}},
+ /* Hauppauge */
+ { 3, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
+ /* STB */
+ { 3, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1}},
+ /* Intel??? */
+ { 3, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}},
+ /* Diamond DTV2000 */
+ { 3, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}},
+ /* AVerMedia TVPhone */
+ { 3, 0, 2,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}},
+ /* Matrix Vision MV-Delta */
+ { 5,-1, 4, 0, { 2, 3, 1, 0, 0}},
+ /* Fly Video II */
+ { 3, 0, 2, 0xc00, { 2, 3, 1, 1},
+ {0, 0xc00, 0x800, 0x400, 0xc00, 0}},
+};
+#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
+
+
/*
* Tuner, Radio, internal, external and mute
*/
-static unsigned char audiomuxs[][5] =
-{
- { 0x00, 0x00, 0x00, 0x00, 0x00}, /* unknown */
- { 0x02, 0x00, 0x00, 0x00, 0x0a}, /* MIRO */
- { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Hauppauge */
- { 0x04, 0x00, 0x02, 0x03, 0x01}, /* STB */
- { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Intel??? */
- { 0x00, 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000 */
- { 0x0c, 0x00, 0x0b, 0x0b, 0x00}, /* AVerMedia TVPhone */
-};
-
static void audio(struct bttv *btv, int mode)
{
- /* enable least significant GPIO output nibble */
- btwrite(0x0f, BT848_GPIO_OUT_EN);
-
- /* select direct input */
- btwrite(0x00, BT848_GPIO_REG_INP);
+ btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask,
+ BT848_GPIO_OUT_EN);
switch (mode)
{
@@ -437,12 +463,17 @@ static void audio(struct bttv *btv, int mode)
break;
}
/* if audio mute or not in H-lock, turn audio off */
- if ((btv->audio&AUDIO_MUTE) ||
- (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)))
+ if ((btv->audio&AUDIO_MUTE)
+#if 0
+ ||
+ (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
+#endif
+ )
mode=AUDIO_OFF;
if ((mode == 0) && (btv->radio))
mode = 1;
- btaor(audiomuxs[btv->type][mode] , ~0x0f, BT848_GPIO_DATA);
+ btaor(tvcards[btv->type].audiomux[mode],
+ ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
}
@@ -469,14 +500,77 @@ static void bt848_cap(struct bttv *btv, uint state)
}
}
-static void bt848_muxsel(struct bttv *btv, uint input)
+
+/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*/
+
+static int set_pll(struct bttv *btv)
+{
+ int i;
+
+ if (!btv->pll)
+ return 0;
+ if ((btread(BT848_IFORM)&BT848_IFORM_XT0))
+ {
+ /* printk ("switching PLL off\n");*/
+ btwrite(0x00,BT848_TGCTRL);
+ btwrite(0x00,BT848_PLL_XCI);
+ btv->pll&=~2;
+ return 0;
+ }
+
+ /* do not set pll again if already active */
+ if (btv->pll&2)
+ return 1;
+
+ /* printk ("setting PLL for PAL/SECAM\n");*/
+
+ btwrite(0x00,BT848_TGCTRL);
+ btwrite(0xf9,BT848_PLL_F_LO);
+ btwrite(0xdc,BT848_PLL_F_HI);
+ btwrite(0x8e,BT848_PLL_XCI);
+
+ /* Ugh ugh ugh .. schedule ? */
+ udelay(100000);
+ for (i=0; i<100; i++)
+ {
+ if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))
+ btwrite(0,BT848_DSTATUS);
+ else
+ {
+ btwrite(0x08,BT848_TGCTRL);
+ btv->pll|=2;
+ return 1;
+ }
+ udelay(10000);
+ }
+ return -1;
+}
+
+static void bt848_muxsel(struct bttv *btv, unsigned int input)
{
- input&=3;
+ btwrite(tvcards[btv->type].gpiomask, BT848_GPIO_OUT_EN);
/* This seems to get rid of some synchronization problems */
btand(~(3<<5), BT848_IFORM);
- udelay(10000);
+ mdelay(10);
+ input %= tvcards[btv->type].inputs;
+ if (input==tvcards[btv->type].svhs)
+ {
+ btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
+ btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
+ }
+ else
+ {
+ btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+ btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+ }
+ btaor((tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);
+ audio(btv, (input!=tvcards[btv->type].tuner) ?
+ AUDIO_EXTERN : AUDIO_TUNER);
+ btaor(tvcards[btv->type].muxsel[input]>>4,
+ ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA);
+#if 0
if (input==3)
{
btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
@@ -491,6 +585,7 @@ static void bt848_muxsel(struct bttv *btv, uint input)
input=3;
btaor(((input+2)&3)<<5, ~(3<<5), BT848_IFORM);
audio(btv, input ? AUDIO_EXTERN : AUDIO_TUNER);
+#endif
}
@@ -540,8 +635,60 @@ int fmtbppx2[16] = {
8, 6, 4, 4, 4, 3, 2, 2, 4, 3, 0, 0, 0, 0, 2, 0
};
-static int make_vrisctab(struct bttv *btv, unsigned int *ro, unsigned int *re,
- unsigned int *vbuf, unsigned short width, unsigned short height, unsigned short fmt)
+int palette2fmt[] = {
+ 0,
+ BT848_COLOR_FMT_Y8,
+ BT848_COLOR_FMT_RGB8,
+ BT848_COLOR_FMT_RGB16,
+ BT848_COLOR_FMT_RGB24,
+ BT848_COLOR_FMT_RGB32,
+ BT848_COLOR_FMT_RGB15,
+ BT848_COLOR_FMT_YUY2,
+ BT848_COLOR_FMT_BtYUV,
+ -1,
+ -1,
+ -1,
+ BT848_COLOR_FMT_RAW,
+ BT848_COLOR_FMT_YCrCb422,
+ BT848_COLOR_FMT_YCrCb411,
+};
+#define PALETTEFMT_MAX 11
+
+static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
+ unsigned int *re, unsigned int *vbuf)
+{
+ unsigned long line;
+ unsigned long bpl=1024;
+ unsigned long vadr=(unsigned long) vbuf;
+
+ *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0;
+ *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0;
+
+ /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY
+ is 2. We'll have to handle this inside the IRQ handler ... */
+
+ for (line=0; line < 640; line++)
+ {
+ *(ro++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
+ *(ro++)=kvirt_to_bus(vadr);
+ *(re++)=BT848_RISC_WRITE|bpl|BT848_RISC_SOL|BT848_RISC_EOL;
+ *(re++)=kvirt_to_bus(vadr+BTTV_MAX_FBUF/2);
+ vadr+=bpl;
+ }
+
+ *(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 fmt)
{
unsigned long line;
unsigned long bpl; /* bytes per line */
@@ -551,6 +698,9 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, unsigned int *re,
int inter;
unsigned long vadr=(unsigned long) vbuf;
+ if (btv->gfmt==BT848_COLOR_FMT_RAW)
+ return make_rawrisctab(btv, ro, re, vbuf);
+
inter = (height>btv->win.cropheight/2) ? 1 : 0;
bpl=width*fmtbppx2[fmt&0xf]/2;
@@ -652,6 +802,7 @@ static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr,
*x+=dx;
}
+
/*
* Set the registers for the size we have specified. Don't bother
* trying to understand this without the BT848 manual in front of
@@ -683,10 +834,16 @@ static struct tvnorm tvnorms[] = {
944, 186, 922, 0x20},
/* PAL-M */
{ 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0),
- 780, 186, 922, 0x16},
+ 780, 135, 754, 0x16},
/* PAL-N */
{ 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1),
944, 186, 922, 0x20},
+ /* PAL-NC */
+ { 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0),
+ 944, 186, 922, 0x20},
+ /* NTSC-Japan */
+ { 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0),
+ 780, 135, 754, 0x16},
};
#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm))
@@ -709,7 +866,7 @@ static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc,
btwrite(vtc, BT848_E_VTC+off);
btwrite(hscale>>8, BT848_E_HSCALE_HI+off);
btwrite(hscale&0xff, BT848_E_HSCALE_LO+off);
- btaor((vscale>>8), 0xc0, BT848_E_VSCALE_HI+off);
+ btaor((vscale>>8), 0xe0, BT848_E_VSCALE_HI+off);
btwrite(vscale&0xff, BT848_E_VSCALE_LO+off);
btwrite(hactive&0xff, BT848_E_HACTIVE_LO+off);
btwrite(hdelay&0xff, BT848_E_HDELAY_LO+off);
@@ -747,6 +904,8 @@ 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);
+
+ set_pll(btv);
btwrite(fmt, BT848_COLOR_FMT);
hactive=width;
@@ -788,30 +947,22 @@ int bpp2fmt[4] = {
static void bt848_set_winsize(struct bttv *btv)
{
unsigned short format;
- int bpp;
- bpp=fmtbppx2[btv->win.color_fmt&0x0f]/2;
- if (btv->win.bpp == 0)
- {
- btv->win.bpp=bpp;
- format=btv->win.color_fmt;
- }
- else if (btv->win.bpp!=bpp)
- btv->win.color_fmt=format=bpp2fmt[(btv->win.bpp-1)&3];
- else
- format=btv->win.color_fmt;
+ btv->win.color_fmt=format= (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 :
+ bpp2fmt[(btv->win.bpp-1)&3];
/* RGB8 seems to be a 9x5x5 GRB color cube starting at
* color 16. Why the h... can't they even mention this in the
- * datasheet??? [AC - because its a standard format so I guess
- * it never occured them]
- * Enable dithering in this mode
+ * data sheet? [AC - because it's a standard format so I guess
+ * it never occurred to them]
+ * Enable dithering in this mode.
*/
+#if 0
if (format==BT848_COLOR_FMT_RGB8)
btand(~0x10, BT848_CAP_CTL);
else
btor(0x10, BT848_CAP_CTL);
-
+#endif
bt848_set_geo(btv,btv->win.width, btv->win.height, format);
}
@@ -876,6 +1027,8 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
if(fbuffer_alloc(btv))
return -ENOBUFS;
}
+ if(btv->grabbing>1)
+ return -ENOBUFS;
/*
* No grabbing past the end of the buffer!
@@ -887,7 +1040,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
if(mp->height <0 || mp->width <0)
return -EINVAL;
- if(mp->height>480 || mp->width>640)
+ if(mp->height>576 || mp->width>768)
return -EINVAL;
/*
@@ -900,20 +1053,30 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
* Ok load up the BT848
*/
- vbuf=(unsigned int *)(btv->fbuffer+0x144000*mp->frame);
- if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
- return -EAGAIN;
- ro=btv->grisc+(((btv->grabcount++)&1) ? 2048 :0);
- re=ro+1024;
+ vbuf=(unsigned int *)(btv->fbuffer+BTTV_MAX_FBUF*mp->frame);
+/* if (!(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC))
+ return -EAGAIN; */
+ ro=btv->grisc+(((btv->grabcount++)&1) ? 4096 :0);
+ re=ro+2048;
btv->gwidth=mp->width;
btv->gheight=mp->height;
- btv->gfmt=mp->format;
+ if (mp->format > PALETTEFMT_MAX)
+ return -EINVAL;
+ btv->gfmt=palette2fmt[mp->format];
+ if(btv->gfmt==-1)
+ return -EINVAL;
+
make_vrisctab(btv, ro, re, vbuf, btv->gwidth, btv->gheight, btv->gfmt);
/* bt848_set_risc_jmps(btv); */
btor(3, BT848_CAP_CTL);
btor(3, BT848_GPIO_DMA_CTL);
- btv->gro=virt_to_bus(ro);
- btv->gre=virt_to_bus(re);
+ if (btv->grabbing) {
+ btv->gro_next=virt_to_bus(ro);
+ btv->gre_next=virt_to_bus(re);
+ } else {
+ btv->gro=virt_to_bus(ro);
+ btv->gre=virt_to_bus(re);
+ }
if (!(btv->grabbing++))
btv->risc_jmp[12]=BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ;
/* interruptible_sleep_on(&btv->capq); */
@@ -990,7 +1153,7 @@ static int bttv_open(struct video_device *dev, int flags)
find_vga();
btv->fbuffer=NULL;
if (!btv->fbuffer)
- btv->fbuffer=(unsigned char *) rvmalloc(2*0x144000);
+ btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF);
if (!btv->fbuffer)
{
btv->user--;
@@ -1014,7 +1177,7 @@ static void bttv_close(struct video_device *dev)
bt848_set_risc_jmps(btv);
if(btv->fbuffer)
- rvfree((void *) btv->fbuffer, 2*0x144000);
+ rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF);
btv->fbuffer=0;
MOD_DEC_USE_COUNT;
}
@@ -1411,8 +1574,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
strcpy(v.name, "Television");
v.rangelow=0;
v.rangehigh=0xFFFFFFFF;
- v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC;
+ v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM;
v.mode = btv->win.norm;
+ v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0;
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
return 0;
@@ -1439,13 +1603,15 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCGPICT:
{
struct video_picture p=btv->picture;
- if(btv->win.bpp==1)
+ if(btv->win.depth==8)
p.palette=VIDEO_PALETTE_HI240;
- if(btv->win.bpp==2)
+ if(btv->win.depth==15)
+ p.palette=VIDEO_PALETTE_RGB555;
+ if(btv->win.depth==16)
p.palette=VIDEO_PALETTE_RGB565;
- if(btv->win.bpp==3)
+ if(btv->win.depth==24)
p.palette=VIDEO_PALETTE_RGB24;
- if(btv->win.bpp==4)
+ if(btv->win.depth==32)
p.palette=VIDEO_PALETTE_RGB32;
if(copy_to_user(arg, &p, sizeof(p)))
@@ -1455,6 +1621,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
case VIDIOCSPICT:
{
struct video_picture p;
+ int format;
if(copy_from_user(&p, arg,sizeof(p)))
return -EFAULT;
/* We want -128 to 127 we get 0-65535 */
@@ -1466,8 +1633,15 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
bt848_hue(btv, (p.hue>>8)-128);
/* 0-511 */
bt848_contrast(btv, p.contrast>>7);
- btv->picture=p;
- return 0;
+ btv->picture = p;
+
+ /* set palette if bpp matches */
+ if (p.palette < sizeof(palette2fmt)/sizeof(int)) {
+ format = palette2fmt[p.palette];
+ if (fmtbppx2[format&0x0f]/2 == btv->win.bpp)
+ btv->win.color_fmt = format;
+ }
+ return 0;
}
case VIDIOCSWIN:
{
@@ -1571,7 +1745,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
v.base=(void *)btv->win.vidadr;
v.height=btv->win.sheight;
v.width=btv->win.swidth;
- v.depth=btv->win.bpp*8;
+ v.depth=btv->win.depth;
v.bytesperline=btv->win.bpl;
if(copy_to_user(arg, &v,sizeof(v)))
return -EFAULT;
@@ -1585,18 +1759,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EPERM;
if(copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
- if(v.depth!=8 && v.depth!=16 && v.depth!=24 && v.depth!=32)
+ if(v.depth!=8 && v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32)
return -EINVAL;
- if (v.base)
- /* also handle virtual base addresses */
- if ((unsigned int)v.base>=0xe0000000UL)
- btv->win.vidadr=(uint)v.base;
- else
- btv->win.vidadr=PAGE_OFFSET|
- uvirt_to_bus((uint)v.base);
+ btv->win.vidadr=(unsigned long)v.base;
btv->win.sheight=v.height;
btv->win.swidth=v.width;
- btv->win.bpp=v.depth/8;
+ btv->win.bpp=((v.depth+1)&0x38)/8;
+ btv->win.depth=v.depth;
btv->win.bpl=v.bytesperline;
DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n",
@@ -1635,13 +1804,21 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
strcpy(v.name,"TV");
if (btv->have_msp3400)
{
- v.flags|=VIDEO_AUDIO_VOLUME;
- i2c_control_device(&(btv->i2c),
- I2C_DRIVERID_MSP3400,
- MSP_GET_VOLUME,&(v.volume));
- i2c_control_device(&(btv->i2c),
- I2C_DRIVERID_MSP3400,
- MSP_GET_STEREO,&(v.mode));
+ v.flags|=VIDEO_AUDIO_VOLUME |
+ VIDEO_AUDIO_BASS |
+ VIDEO_AUDIO_TREBLE;
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_VOLUME,&(v.volume));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_BASS,&(v.bass));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_TREBLE,&(v.treble));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_GET_STEREO,&(v.mode));
}
else v.mode = VIDEO_SOUND_MONO;
if(copy_to_user(arg,&v,sizeof(v)))
@@ -1655,28 +1832,37 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
if(v.flags&VIDEO_AUDIO_MUTE)
audio(btv, AUDIO_MUTE);
- if(v.audio<0||v.audio>2)
+ /* One audio source per tuner */
+ if(v.audio!=0)
return -EINVAL;
bt848_muxsel(btv,v.audio);
if(!(v.flags&VIDEO_AUDIO_MUTE))
audio(btv, AUDIO_UNMUTE);
if (btv->have_msp3400)
{
- i2c_control_device(&(btv->i2c),
- I2C_DRIVERID_MSP3400,
- MSP_SET_VOLUME,&(v.volume));
- i2c_control_device(&(btv->i2c),
- I2C_DRIVERID_MSP3400,
- MSP_SET_STEREO,&(v.mode));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_VOLUME,&(v.volume));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_BASS,&(v.bass));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_TREBLE,&(v.treble));
+ i2c_control_device(&(btv->i2c),
+ I2C_DRIVERID_MSP3400,
+ MSP_SET_STEREO,&(v.mode));
}
btv->audio_dev=v;
return 0;
}
case VIDIOCSYNC:
- if (btv->grabbing && btv->grab==btv->lastgrab)
+ if (!btv->grabbing)
+ return -EAGAIN;
+ if (btv->grab==btv->lastgrab)
interruptible_sleep_on(&btv->capq);
- btv->lastgrab=btv->grab;
+ btv->lastgrab++;
return 0;
case BTTV_WRITEE:
@@ -1728,7 +1914,7 @@ static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long si
unsigned long start=(unsigned long) adr;
unsigned long page,pos;
- if (size>2*0x144000)
+ if (size>2*BTTV_MAX_FBUF)
return -EINVAL;
if (!btv->fbuffer)
{
@@ -1757,6 +1943,7 @@ static struct video_device bttv_template=
bttv_close,
bttv_read,
bttv_write,
+ NULL, /* poll */
bttv_ioctl,
bttv_mmap,
bttv_init_done,
@@ -1810,6 +1997,20 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count,
return count;
}
+static unsigned int vbi_poll(struct video_device *dev, struct file *file,
+ poll_table *wait)
+{
+ struct bttv *btv=(struct bttv *)(dev-2);
+ unsigned int mask = 0;
+
+ poll_wait(file, &btv->vbiq, wait);
+
+ if (btv->vbip < VBIBUF_SIZE)
+ mask |= (POLLIN | POLLRDNORM);
+
+ return mask;
+}
+
static int vbi_open(struct video_device *dev, int flags)
{
struct bttv *btv=(struct bttv *)(dev-2);
@@ -1847,6 +2048,7 @@ static struct video_device vbi_template=
vbi_close,
vbi_read,
bttv_write,
+ vbi_poll,
vbi_ioctl,
NULL, /* no mmap yet */
bttv_init_done,
@@ -1943,6 +2145,7 @@ static struct video_device radio_template=
radio_close,
radio_read, /* just returns -EINVAL */
bttv_write, /* just returns -EINVAL */
+ NULL, /* no poll */
radio_ioctl,
NULL, /* no mmap */
bttv_init_done, /* just returns 0 */
@@ -1960,18 +2163,24 @@ struct vidbases
};
static struct vidbases vbs[] = {
- { PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL,
- "Matrox Millennium", PCI_BASE_ADDRESS_1},
- { PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1},
- { PCI_VENDOR_ID_S3, 0, "S3", 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},
{ PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0},
- { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128,
- "Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
"DEC DC21030", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL,
+ "Matrox Millennium", PCI_BASE_ADDRESS_1},
+ { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2,
+ "Matrox Millennium II", PCI_BASE_ADDRESS_0},
+ { 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_N9, PCI_DEVICE_ID_N9_I128,
+ "Number Nine Imagine 128", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0},
+ { PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0},
};
@@ -1991,77 +2200,69 @@ static uint dec_offsets[4] = {
static int find_vga(void)
{
- unsigned int devfn, class, vendev;
- unsigned short vendor, device, badr;
- int found=0, bus=0, i, tga_type;
+ unsigned short badr;
+ int found = 0, i, tga_type;
unsigned int vidadr=0;
+ struct pci_dev *dev;
- for (devfn = 0; devfn < 0xff; devfn++)
+ for (dev = pci_devices; dev != NULL; dev = dev->next)
{
- if (PCI_FUNC(devfn) != 0)
+ if (dev->class != PCI_CLASS_NOT_DEFINED_VGA &&
+ ((dev->class) >> 16 != PCI_BASE_CLASS_DISPLAY))
+ {
continue;
- pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendev);
- if (vendev == 0xffffffff || vendev == 0x00000000)
+ }
+ if (PCI_FUNC(dev->devfn) != 0)
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++)
{
- 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 (!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)
+ if (dev->vendor == vbs[i].vendor)
{
- printk(KERN_ERR "bttv: Memory @ 0, must be something wrong!");
- continue;
+ if (vbs[i].device)
+ if (vbs[i].device!=dev->device)
+ continue;
+ printk("%s.\n", vbs[i].name);
+ badr=vbs[i].badr;
+ break;
}
-
- if (vendor==PCI_VENDOR_ID_DEC)
- if (device==PCI_DEVICE_ID_DEC_TGA)
+ }
+ if (!badr)
+ {
+ printk(KERN_ERR "bttv: Unknown video memory base address.\n");
+ continue;
+ }
+ pci_read_config_dword(dev, 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!");
+ continue;
+ }
+
+ if (dev->vendor == PCI_VENDOR_ID_DEC &&
+ dev->device == PCI_DEVICE_ID_DEC_TGA)
+ {
+ tga_type = (readl((unsigned long)vidadr) >> 12) & 0x0f;
+ if (tga_type != 0 && tga_type != 1 && tga_type != 3)
{
- 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];
+ printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type);
+ found--;
}
-
- DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr));
- DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", devfn));
- found++;
+ vidadr+=dec_offsets[tga_type];
}
+ DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr));
+ DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", dev->devfn));
+ found++;
}
if (vidmem)
@@ -2086,79 +2287,77 @@ static int find_vga(void)
static void handle_chipset(void)
{
- int index;
+ struct pci_dev *dev = NULL;
/* Just in case some nut set this to something dangerous */
if (triton1)
triton1=BT848_INT_ETBF;
- for (index = 0; index < 8; index++)
+ while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev)))
{
- 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");
- }
+ 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));
- }
+ /* dev == NULL */
- 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;
+ while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev)))
+ {
+ unsigned char b;
+ pci_read_config_byte(dev, 0x53, &b);
+ DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, "));
+ DEBUG(printk("bufcon=0x%02x\n",b));
+ }
- pcibios_read_config_byte(bus, devfn, TRITON_PCON, &b);
- bo=b;
- DEBUG(printk(KERN_DEBUG "bttv: 82437FX: PCON: 0x%x\n",b));
+ while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev)))
+ {
+/* unsigned char b;
+ unsigned char bo;*/
- if(!(b & TRITON_BUS_CONCURRENCY))
- {
- printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n");
- b |= TRITON_BUS_CONCURRENCY;
- }
+ 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 */
- 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;
- }
+ pci_read_config_byte(dev, 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
+ if (b!=bo)
+ {
+ pci_write_config_byte(dev, TRITON_PCON, b);
+ printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b);
}
+#endif
}
}
+static void init_tda8425(struct i2c_bus *bus)
+{
+ I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */
+ 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 */
+}
+
static void init_tda9850(struct i2c_bus *bus)
{
@@ -2177,13 +2376,13 @@ static void init_tda9850(struct i2c_bus *bus)
static void idcard(struct bttv *btv)
{
- int tunertype;
btwrite(0, BT848_GPIO_OUT_EN);
DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA)));
/* Default the card to the user-selected one. */
btv->type=card;
-
+ btv->tuner_type=-1; /* use default tuner type */
+
/* If we were asked to auto-detect, then do so!
Right now this will only recognize Miro, Hauppauge or STB
*/
@@ -2196,12 +2395,34 @@ static void idcard(struct bttv *btv)
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;
+ }
}
- btv->dbx = I2CRead(&(btv->i2c), I2C_TDA9850) ? 0 : 1;
+ if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0)
+ {
+ btv->audio_chip = TDA9850;
+ printk(KERN_INFO "bttv: audio chip: TDA9850\n");
+ }
- if (btv->dbx)
- init_tda9850(&(btv->i2c));
+ if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0)
+ {
+ btv->audio_chip = TDA8425;
+ printk("bttv: audio chip: TDA8425\n");
+ }
+
+ switch(btv->audio_chip)
+ {
+ case TDA9850:
+ init_tda9850(&(btv->i2c));
+ break;
+ case TDA8425:
+ init_tda8425(&(btv->i2c));
+ break;
+ }
/* How do I detect the tuner type for other cards but Miro ??? */
printk(KERN_INFO "bttv: model: ");
@@ -2209,13 +2430,6 @@ static void idcard(struct bttv *btv)
{
case BTTV_MIRO:
printk("MIRO\n");
- if (btv->have_tuner)
- {
- tunertype=((btread(BT848_GPIO_DATA)>>10)-1)&7;
- i2c_control_device(&(btv->i2c),
- I2C_DRIVERID_TUNER,
- TUNER_SET_TYPE,&tunertype);
- }
strcpy(btv->video_dev.name,"BT848(Miro)");
break;
case BTTV_HAUPPAUGE:
@@ -2238,6 +2452,10 @@ static void idcard(struct bttv *btv)
printk("AVerMedia\n");
strcpy(btv->video_dev.name,"BT848(AVerMedia)");
break;
+ case BTTV_MATRIX_VISION:
+ printk("MATRIX-Vision\n");
+ strcpy(btv->video_dev.name,"BT848(MATRIX-Vision)");
+ break;
}
audio(btv, AUDIO_MUTE);
}
@@ -2288,7 +2506,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 cpaturing and DMA */
+ /* enable capturing and DMA */
btaor(flags, ~0x0f, BT848_CAP_CTL);
if (flags&0x0f)
bt848_dma(btv, 3);
@@ -2321,6 +2539,7 @@ static int init_bt848(int i)
btv->win.cropx=0;
btv->win.cropy=0;
btv->win.bpp=2;
+ btv->win.depth=16;
btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
btv->win.bpl=1024*btv->win.bpp;
btv->win.swidth=1024;
@@ -2359,9 +2578,11 @@ static int init_bt848(int i)
btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE);
if (!btv->vbibuf)
return -1;
- if (!(btv->grisc=(unsigned int *) kmalloc(16384, GFP_KERNEL)))
+ if (!(btv->grisc=(unsigned int *) kmalloc(32768, GFP_KERNEL)))
return -1;
+ memset(btv->vbibuf, 0, VBIBUF_SIZE); /* We don't want to return random
+ memory to the user */
btv->fbuffer=NULL;
bt848_muxsel(btv, 1);
@@ -2372,7 +2593,11 @@ static int init_bt848(int i)
btwrite(0x00, BT848_CAP_CTL);
btwrite(0xfc, BT848_GPIO_DMA_CTL);
- btwrite(0x0ff, BT848_VBI_PACK_SIZE);
+ /* select direct input */
+ btwrite(0x00, BT848_GPIO_REG_INP);
+
+
+ btwrite(0xff, BT848_VBI_PACK_SIZE);
btwrite(1, BT848_VBI_PACK_DEL);
@@ -2502,10 +2727,11 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
/* captured full frame */
if (stat&(2<<28))
{
- btv->grab++;
wake_up_interruptible(&btv->capq);
if ((--btv->grabbing))
{
+ btv->gro = btv->gro_next;
+ btv->gre = btv->gre_next;
btv->risc_jmp[5]=btv->gro;
btv->risc_jmp[11]=btv->gre;
bt848_set_geo(btv, btv->gwidth,
@@ -2517,6 +2743,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->win.height,
btv->win.color_fmt);
}
+ wake_up_interruptible(&btv->capq);
break;
}
if (stat&(8<<28))
@@ -2588,30 +2815,29 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
static int find_bt848(void)
{
- short pci_index;
unsigned char command, latency;
int result;
- unsigned char bus, devfn;
struct bttv *btv;
+ struct pci_dev *dev;
bttv_num=0;
if (!pcibios_present())
{
- DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessable!\n"));
+ DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessible!\n"));
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);
- ++pci_index)
+ for (dev = pci_devices; dev != NULL; dev = dev->next)
{
+ if (dev->vendor != PCI_VENDOR_ID_BROOKTREE)
+ continue;
+ if (dev->device != PCI_DEVICE_ID_BT849 &&
+ dev->device != PCI_DEVICE_ID_BT848)
+ continue;
+
+ /* Ok, Bt848 or Bt849 found! */
btv=&bttvs[bttv_num];
- btv->bus=bus;
- btv->devfn=devfn;
+ btv->dev=dev;
btv->bt848_mem=NULL;
btv->vbibuf=NULL;
btv->risc_jmp=NULL;
@@ -2624,12 +2850,10 @@ static int find_bt848(void)
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);
+ pci_read_config_word (btv->dev, PCI_DEVICE_ID, &btv->id);
+
+ /* pci_read_config_dword(btv->dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr); */
+ btv->bt848_adr = btv->dev->base_address[0];
if (remap&&(!bttv_num))
{
@@ -2637,25 +2861,33 @@ static int find_bt848(void)
remap&=PCI_BASE_ADDRESS_MEM_MASK;
printk(KERN_INFO "Remapping to : 0x%08x.\n", remap);
remap|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK);
- pcibios_write_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
- remap);
- pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0,
- &btv->bt848_adr);
+ pci_write_config_dword(btv->dev, PCI_BASE_ADDRESS_0, remap);
+ pci_read_config_dword(btv->dev, PCI_BASE_ADDRESS_0, &btv->bt848_adr);
+ btv->dev->base_address[0] = btv->bt848_adr;
}
btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK;
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION,
+ pci_read_config_byte(btv->dev, PCI_CLASS_REVISION,
&btv->revision);
printk(KERN_INFO "bttv: Brooktree Bt%d (rev %d) ",
- btv->id, btv->revision);
+ btv->id, btv->revision);
printk("bus: %d, devfn: %d, ",
- btv->bus, btv->devfn);
- printk("irq: %d, ",btv->irq);
+ btv->dev->bus->number, btv->dev->devfn);
+ printk("irq: %d, ",btv->dev->irq);
printk("memory: 0x%08x.\n", btv->bt848_adr);
+ btv->pll = 0;
+#ifdef USE_PLL
+ if (btv->id==849 || (btv->id==848 && btv->revision==0x12))
+ {
+ printk(KERN_INFO "bttv: internal PLL, single crystal operation enabled.\n");
+ btv->pll=1;
+ }
+#endif
+
btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000);
- result = request_irq(btv->irq, bttv_irq,
+ result = request_irq(btv->dev->irq, bttv_irq,
SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv);
if (result==-EINVAL)
{
@@ -2664,29 +2896,27 @@ static int find_bt848(void)
}
if (result==-EBUSY)
{
- printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->irq);
+ printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->dev->irq);
return result;
}
if (result < 0)
return result;
/* Enable bus-mastering */
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
+ pci_read_config_byte(btv->dev, 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);
+ pci_write_config_byte(btv->dev, PCI_COMMAND, command);
+ pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
if (!(command&PCI_COMMAND_MASTER))
{
printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n");
return -1;
}
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER,
- &latency);
+ pci_read_config_byte(btv->dev, PCI_LATENCY_TIMER, &latency);
if (!latency)
{
latency=32;
- pcibios_write_config_byte(btv->bus, btv->devfn,
- PCI_LATENCY_TIMER, latency);
+ pci_write_config_byte(btv->dev, PCI_LATENCY_TIMER, latency);
}
DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency));
bttv_num++;
@@ -2720,9 +2950,10 @@ static void release_bttv(void)
i2c_unregister_bus((&btv->i2c));
/* disable PCI bus-mastering */
- pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command);
- command|=PCI_COMMAND_MASTER;
- pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command);
+ pci_read_config_byte(btv->dev, PCI_COMMAND, &command);
+ /* Should this be &=~ ?? */
+ command|=PCI_COMMAND_MASTER;
+ pci_write_config_byte(btv->dev, PCI_COMMAND, command);
/* unmap and free memory */
if (btv->grisc)
@@ -2743,7 +2974,7 @@ static void release_bttv(void)
vfree((void *) btv->vbibuf);
- free_irq(btv->irq,btv);
+ free_irq(btv->dev->irq,btv);
DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem));
if (btv->bt848_mem)
iounmap(btv->bt848_mem);
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index ca0fb057c..e1e21f595 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -26,21 +26,14 @@
#include <linux/types.h>
#include <linux/wait.h>
-#include "i2c.h"
+#include <linux/i2c.h>
#include "msp3400.h"
#include "bt848.h"
#include <linux/videodev.h>
#define MAX_CLIPRECS 100
#define RISCMEM_LEN (32744*2)
-#define MAX_FBUF 0x144000
-
-struct riscprog
-{
- unsigned int length;
- u32 *busadr;
- u32 *prog;
-};
+#define BTTV_MAX_FBUF 0x144000
/* clipping rectangle */
@@ -51,29 +44,6 @@ struct cliprec
};
-/* grab buffer */
-struct gbuffer
-{
- struct gbuffer *next;
- struct gbuffer *next_active;
- void *adr;
- int x, y;
- int width, height;
- unsigned int bpl;
- unsigned int fmt;
- int flags;
-#define GBUF_ODD 1
-#define GBUF_EVEN 2
-#define GBUF_LFB 4
-#define GBUF_INT 8
- unsigned int length;
- void *ro;
- void *re;
- u32 bro;
- u32 bre;
-};
-
-
#ifdef __KERNEL__
struct bttv_window
@@ -84,11 +54,12 @@ struct bttv_window
ushort swidth, sheight;
short cropx, cropy;
ushort cropwidth, cropheight;
- unsigned int vidadr;
+ unsigned long vidadr;
ushort freq;
int norm;
int interlace;
int color_fmt;
+ ushort depth;
};
@@ -103,12 +74,11 @@ struct bttv
struct i2c_bus i2c;
int have_msp3400;
int have_tuner;
+ int tuner_type;
unsigned short id;
- unsigned char bus; /* PCI bus the Bt848 is on */
- unsigned char devfn;
+ struct pci_dev *dev;
unsigned char revision;
- unsigned char irq; /* IRQ used by Bt848 card */
unsigned int bt848_adr; /* bus address of IO mem returned by PCI BIOS */
unsigned char *bt848_mem; /* pointer to mapped IO memory */
unsigned long busriscmem;
@@ -119,7 +89,7 @@ struct bttv
int type; /* card type */
int audio; /* audio mode */
int user;
- int dbx;
+ int audio_chip;
int radio;
u32 *risc_jmp;
@@ -145,12 +115,15 @@ struct bttv
u32 *grisc;
unsigned long gro;
unsigned long gre;
+ unsigned long gro_next;
+ unsigned long gre_next;
char *fbuffer;
int gmode;
int grabbing;
int lastgrab;
int grab;
int grabcount;
+ int pll;
};
#endif
@@ -184,6 +157,8 @@ struct bttv
#define BTTV_INTEL 0x04
#define BTTV_DIAMOND 0x05
#define BTTV_AVERMEDIA 0x06
+#define BTTV_MATRIX_VISION 0x07
+#define BTTV_FLYVIDEO 0x08
#define AUDIO_TUNER 0x00
#define AUDIO_RADIO 0x01
@@ -194,8 +169,12 @@ struct bttv
#define AUDIO_MUTE 0x80
#define AUDIO_UNMUTE 0x81
+#define TDA9850 0x01
+#define TDA8425 0x02
+
#define I2C_TSA5522 0xc2
#define I2C_TDA9850 0xb6
+#define I2C_TDA8425 0x82
#define I2C_HAUPEE 0xa0
#define I2C_STBEE 0xae
@@ -207,4 +186,12 @@ struct bttv
#define TDA9850_ALI2 0x09
#define TDA9850_ALI3 0x0a
+
+#define TDA8425_VL 0x00
+#define TDA8425_VR 0x01
+#define TDA8425_BA 0x02
+#define TDA8425_TR 0x03
+#define TDA8425_S1 0x08
+
+
#endif
diff --git a/drivers/char/bw-qcam.c b/drivers/char/bw-qcam.c
index 2142cf6a1..48de68db3 100644
--- a/drivers/char/bw-qcam.c
+++ b/drivers/char/bw-qcam.c
@@ -112,7 +112,7 @@ static int qc_calibrate(struct qcam_device *q)
do {
qc_command(q, 33);
value = qc_readparam(q);
- udelay(1000);
+ mdelay(1);
schedule();
count++;
} while (value == 0xff && count<2048);
@@ -296,7 +296,7 @@ static int qc_detect(struct qcam_device *q)
if (reg != lastreg)
count++;
lastreg = reg;
- udelay(1000);
+ mdelay(1);
}
/* Be liberal in what you accept... */
@@ -842,6 +842,7 @@ static struct video_device qcam_template=
qcam_close,
qcam_read,
qcam_write,
+ NULL,
qcam_ioctl,
NULL,
qcam_init_done,
diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c
index e424266c8..e6d4c16b5 100644
--- a/drivers/char/c-qcam.c
+++ b/drivers/char/c-qcam.c
@@ -149,7 +149,7 @@ static int qc_detect(struct qcam_device *qcam)
ostat = stat = parport_read_status(qcam->pport);
for (i=0; i<250; i++)
{
- udelay(1000);
+ mdelay(1);
stat = parport_read_status(qcam->pport);
if (ostat != stat)
{
@@ -166,9 +166,9 @@ static void qc_reset(struct qcam_device *qcam)
{
parport_write_control(qcam->pport, 0xc);
parport_write_control(qcam->pport, 0x8);
- udelay(1000);
+ mdelay(1);
parport_write_control(qcam->pport, 0xc);
- udelay(1000);
+ mdelay(1);
}
/* Reset the QuickCam and program for brightness, contrast,
@@ -325,7 +325,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
{
/* Turn the port around */
parport_frob_control(q->pport, 0x20, 0x20);
- udelay(3000);
+ mdelay(3);
qcam_set_ack(q, 0);
if (qcam_await_ready1(q, 1)) {
kfree(tmpbuf);
@@ -356,7 +356,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
wantlen -= t;
if (t < s)
break;
- if (need_resched)
+ if (current->need_resched)
schedule();
}
@@ -377,7 +377,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
int l;
do {
l = qcam_read_bytes(q, tmpbuf, 3);
- if (need_resched)
+ if (current->need_resched)
schedule();
} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
@@ -392,7 +392,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
return len;
}
parport_frob_control(q->pport, 0x20, 0);
- udelay(3000);
+ mdelay(3);
qcam_set_ack(q, 1);
if (qcam_await_ready1(q, 0))
{
@@ -407,7 +407,7 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
int l;
do {
l = qcam_read_bytes(q, tmpbuf, 1);
- if (need_resched)
+ if (current->need_resched)
schedule();
} while (l && tmpbuf[0] == 0x7e);
l = qcam_read_bytes(q, tmpbuf+1, 2);
@@ -646,6 +646,7 @@ static struct video_device qcam_template=
qcam_close,
qcam_read,
qcam_write,
+ NULL,
qcam_ioctl,
NULL,
qcam_init_done,
diff --git a/drivers/char/conmakehash.c b/drivers/char/conmakehash.c
index 4d3958fd9..e0c6891a9 100644
--- a/drivers/char/conmakehash.c
+++ b/drivers/char/conmakehash.c
@@ -52,7 +52,6 @@ int unicount[MAX_FONTLEN];
void addpair(int fp, int un)
{
int i;
- unicode hu;
if ( un <= 0xfffe )
{
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 9c9e61e8c..d5b315328 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -3,38 +3,8 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+
/*
- * console.c
- *
- * This module exports the console io functions:
- *
- * 'void do_keyboard_interrupt(void)'
- *
- * 'int vc_allocate(unsigned int console)'
- * 'int vc_cons_allocated(unsigned int console)'
- * 'int vc_resize(unsigned long lines, unsigned long cols)'
- * 'void vc_disallocate(unsigned int currcons)'
- *
- * 'unsigned long con_init(unsigned long)'
- * 'int con_open(struct tty_struct *tty, struct file * filp)'
- * 'void con_write(struct tty_struct * tty)'
- * 'void vt_console_print(const char * b)'
- * 'void update_screen(int new_console)'
- *
- * 'void do_blank_screen(int)'
- * 'void do_unblank_screen(void)'
- * 'void poke_blanked_console(void)'
- *
- * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)'
- * 'void complement_pos(int currcons, int offset)'
- * 'void invert_screen(int currcons, int offset, int count, int shift)'
- *
- * 'void scrollback(int lines)'
- * 'void scrollfront(int lines)'
- *
- * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)'
- * 'int mouse_reporting(void)'
- *
* Hopefully this will be a rather complete VT102 implementation.
*
* Beeping thanks to John T Kohl.
@@ -63,38 +33,48 @@
* redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
*
* APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
+ *
+ * Merge with the abstract console driver by Geert Uytterhoeven
+ * <Geert.Uytterhoeven@cs.kuleuven.ac.be>, Jan 1997.
+ *
+ * Original m68k console driver modifications by
+ *
+ * - Arno Griffioen <arno@usn.nl>
+ * - David Carter <carter@cs.bris.ac.uk>
+ *
+ * Note that the abstract console driver allows all consoles to be of
+ * potentially different sizes, so the following variables depend on the
+ * current console (currcons):
+ *
+ * - video_num_columns
+ * - video_num_lines
+ * - video_size_row
+ * - video_screen_size
+ * - can_do_color
+ *
+ * The abstract console driver provides a generic interface for a text
+ * console. It supports VGA text mode, frame buffer based graphical consoles
+ * and special graphics processors that are only accessible through some
+ * registers (e.g. a TMS340x0 GSP).
+ *
+ * The interface to the hardware is specified using a special structure
+ * (struct consw) which contains function pointers to console operations
+ * (see <linux/console.h> for more information).
+ *
+ * Support for changeable cursor shape
+ * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
+ *
+ * Ported to i386 and con_scrolldelta fixed
+ * by Emmanuel Marty <core@ggi-project.org>, April 1998
+ *
+ * Resurrected character buffers in videoram plus lots of other trickery
+ * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
*/
-#define BLANK 0x0020
-
-/* A bitmap for codes <32. A bit of 1 indicates that the code
- * corresponding to that bit number invokes some special action
- * (such as cursor movement) and should not be displayed as a
- * glyph unless the disp_ctrl mode is explicitly enabled.
- */
-#define CTRL_ACTION 0x0d00ff81
-#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
-
-/*
- * Here is the default bell parameters: 750HZ, 1/8th of a second
- */
-#define DEFAULT_BELL_PITCH 750
-#define DEFAULT_BELL_DURATION (HZ/8)
-
-/*
- * NOTE!!! We sometimes disable and enable interrupts for a short while
- * (to put a word in video IO), but this will work even for keyboard
- * interrupts. We know interrupts aren't enabled when getting a keyboard
- * interrupt, as we use trap-gates. Hopefully all is well.
- */
-
+#include <linux/module.h>
#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/console.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
@@ -102,112 +82,76 @@
#include <linux/malloc.h>
#include <linux/major.h>
#include <linux/mm.h>
-#include <linux/ioport.h>
+#include <linux/console.h>
#include <linux/init.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/tqueue.h>
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
#endif
-#ifdef CONFIG_SGI
-#include <asm/sgialib.h>
-#elif defined(CONFIG_ACER_PICA_61)
-#include <asm/bootinfo.h>
-/*
- * The video control ports are mapped at virtual address
- * 0xe0200000 for the onboard S3 card of the Acer; M700 and Magnum 4000
- * don't have ports at all.
- */
-#define PORT_BASE video_port_base
-unsigned long video_port_base;
-#endif
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/console_struct.h>
+#include <asm/linux_logo.h>
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
+#include "console_macros.h"
+
+
+struct consw *conswitchp = NULL;
+
+static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+
+/* A bitmap for codes <32. A bit of 1 indicates that the code
+ * corresponding to that bit number invokes some special action
+ * (such as cursor movement) and should not be displayed as a
+ * glyph unless the disp_ctrl mode is explicitly enabled.
+ */
+#define CTRL_ACTION 0x0d00ff81
+#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
-int serial_console;
+/*
+ * Here is the default bell parameters: 750HZ, 1/8th of a second
+ */
+#define DEFAULT_BELL_PITCH 750
+#define DEFAULT_BELL_DURATION (HZ/8)
-#ifdef __sparc__
-int serial_console;
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
-struct tty_driver console_driver;
-static int console_refcount;
static struct tty_struct *console_table[MAX_NR_CONSOLES];
static struct termios *console_termios[MAX_NR_CONSOLES];
static struct termios *console_termios_locked[MAX_NR_CONSOLES];
-unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
struct vc vc_cons [MAX_NR_CONSOLES];
static int con_open(struct tty_struct *, struct file *);
-static void con_setsize(unsigned long rows, unsigned long cols);
-static void vc_init(unsigned int console, unsigned long rows,
- unsigned long cols, int do_clear);
-extern void get_scrmem(int currcons);
-extern void set_scrmem(int currcons, long offset);
-static void set_origin(int currcons);
+static void vc_init(unsigned int console, unsigned int rows,
+ unsigned int cols, int do_clear);
static void blank_screen(void);
static void unblank_screen(void);
-extern void change_console(unsigned int);
-extern void poke_blanked_console(void);
static void gotoxy(int currcons, int new_x, int new_y);
static void save_cur(int currcons);
-extern void set_cursor(int currcons);
-extern void hide_cursor(void);
static void reset_terminal(int currcons, int do_clear);
-extern void reset_vc(unsigned int new_console);
-extern void vt_init(void);
-extern void set_vesa_blanking(unsigned long arg);
-extern void vesa_blank(void);
-extern void vesa_unblank(void);
-extern void vesa_powerdown(void);
-extern void compute_shiftstate(void);
-extern void reset_palette(int currcons);
-extern void set_palette(void);
-extern int con_is_present(void);
-extern unsigned long con_type_init(unsigned long, const char **);
-extern void con_type_init_finish(void);
-extern int set_get_cmap(unsigned char *, int);
-extern int set_get_font(unsigned char *, int, int);
-extern void rs_cons_hook(int chip, int out, int channel);
-
-/* Description of the hardware situation */
-unsigned char video_type; /* Type of display being used */
-unsigned long video_mem_base; /* Base of video memory */
-unsigned long video_mem_term; /* End of video memory */
-unsigned short video_port_reg; /* Video register select port */
-unsigned short video_port_val; /* Video register value port */
-unsigned long video_num_columns; /* Number of text columns */
-unsigned long video_num_lines; /* Number of text lines */
-unsigned long video_size_row;
-unsigned long video_screen_size;
-
-int can_do_color = 0;
+static void con_flush_chars(struct tty_struct *tty);
+
static int printable = 0; /* Is console ready for printing? */
-int video_mode_512ch = 0; /* 512-character mode */
-unsigned long video_font_height; /* Height of current screen font */
-unsigned long video_scan_lines; /* Number of scan lines on screen */
-static unsigned long default_font_height; /* Height of default screen font */
-int video_font_is_default = 1;
-static unsigned short console_charmask = 0x0ff;
+int do_poke_blanked_console = 0;
+int console_blanked = 0;
-/* used by kbd_bh - set by keyboard_interrupt */
- int do_poke_blanked_console = 0;
- int console_blanked = 0;
static int blankinterval = 10*60*HZ;
static int vesa_off_interval = 0;
-static long blank_origin, blank__origin, unblank_origin;
/*
* fg_console is the current virtual console,
@@ -220,270 +164,587 @@ int last_console = 0;
int want_console = -1;
int kmsg_redirect = 0;
-#ifdef CONFIG_SERIAL_ECHO
-
-#include <linux/serial_reg.h>
+/*
+ * For each existing display, we have a pointer to console currently visible
+ * on that display, allowing consoles other than fg_console to be refreshed
+ * appropriately. Unless the low-level driver supplies its own display_fg
+ * variable, we use this one for the "master display".
+ */
+static struct vc_data *master_display_fg = NULL;
-extern int serial_echo_init (int base);
-extern int serial_echo_print (const char *s);
+/*
+ * Unfortunately, we need to delay tty echo when we're currently writing to the
+ * console since the code is (and always was) not re-entrant, so we insert
+ * all filp requests to con_task_queue instead of tq_timer and run it from
+ * the console_bh.
+ */
+DECLARE_TASK_QUEUE(con_task_queue);
/*
- * this defines the address for the port to which printk echoing is done
- * when CONFIG_SERIAL_ECHO is defined
+ * Low-Level Functions
*/
-#define SERIAL_ECHO_PORT 0x3f8 /* COM1 */
-static int serial_echo_port = 0;
+#define IS_FG (currcons == fg_console)
+#define IS_VISIBLE (*display_fg == vc_cons[currcons].d)
-#define serial_echo_outb(v,a) outb((v),(a)+serial_echo_port)
-#define serial_echo_inb(a) inb((a)+serial_echo_port)
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE 0
+#else
+#define DO_UPDATE IS_VISIBLE
+#endif
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+static inline unsigned short *screenpos(int currcons, int offset, int viewed)
+{
+ unsigned short *p = (unsigned short *)(visible_origin + offset);
+ return p;
+}
-/* Wait for transmitter & holding register to empty */
-#define WAIT_FOR_XMITR \
- do { \
- lsr = serial_echo_inb(UART_LSR); \
- } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
+static void scrolldelta(int lines)
+{
+ int currcons = fg_console;
-/* These two functions abstract the actual communications with the
- * debug port. This is so we can change the underlying communications
- * mechanism without modifying the rest of the code.
+ clear_selection();
+ if (vcmode == KD_TEXT)
+ sw->con_scrolldelta(vc_cons[currcons].d, lines);
+}
+
+static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
+{
+ unsigned short *d, *s;
+
+ if (t+nr >= b)
+ nr = b - t - 1;
+ if (b > video_num_lines || t >= b || nr < 1)
+ return;
+ if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
+ return;
+ d = (unsigned short *) (origin+video_size_row*t);
+ s = (unsigned short *) (origin+video_size_row*(t+nr));
+ scr_memcpyw(d, s, (b-t-nr) * video_size_row);
+ scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
+}
+
+static void
+scrdown(int currcons, unsigned int t, unsigned int b, int nr)
+{
+ unsigned short *s;
+ unsigned int step;
+
+ if (t+nr >= b)
+ nr = b - t - 1;
+ if (b > video_num_lines || t >= b || nr < 1)
+ return;
+ if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
+ return;
+ s = (unsigned short *) (origin+video_size_row*t);
+ step = video_num_columns * nr;
+ scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
+ scr_memsetw(s, video_erase_char, 2*step);
+}
+
+static void do_update_region(int currcons, unsigned long start, int count)
+{
+#ifndef VT_BUF_VRAM_ONLY
+ unsigned int xx, yy, offset;
+ u16 *p;
+
+ if (start < origin) {
+ count -= origin - start;
+ start = origin;
+ }
+ if (count <= 0)
+ return;
+ offset = (start - origin) / 2;
+ xx = offset % video_num_columns;
+ yy = offset / video_num_columns;
+ p = (u16 *) start;
+ for(;;) {
+ u16 attrib = scr_readw(p) & 0xff00;
+ int startx = xx;
+ u16 *q = p;
+ while (xx < video_num_columns && count) {
+ if (attrib != (scr_readw(p) & 0xff00)) {
+ if (p > q)
+ sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+ startx = xx;
+ q = p;
+ attrib = scr_readw(p) & 0xff00;
+ }
+ p++;
+ xx++;
+ count--;
+ }
+ if (p > q)
+ sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
+ if (!count)
+ break;
+ xx = 0;
+ yy++;
+ }
+#endif
+}
+
+void update_region(int currcons, unsigned long start, int count)
+{
+ if (DO_UPDATE)
+ do_update_region(currcons, start, count);
+}
+
+/* Structure of attributes is hardware-dependent */
+
+static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+{
+ if (sw->con_build_attr)
+ return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
+
+#ifndef VT_BUF_VRAM_ONLY
+/*
+ * ++roman: I completely changed the attribute format for monochrome
+ * mode (!can_do_color). The formerly used MDA (monochrome display
+ * adapter) format didn't allow the combination of certain effects.
+ * Now the attribute is just a bit vector:
+ * Bit 0..1: intensity (0..2)
+ * Bit 2 : underline
+ * Bit 3 : reverse
+ * Bit 7 : blink
*/
-int
-serial_echo_print(const char *s)
+ {
+ u8 a = color;
+ if (!can_do_color)
+ return _intensity |
+ (_underline ? 4 : 0) |
+ (_reverse ? 8 : 0) |
+ (_blink ? 0x80 : 0);
+ if (_underline)
+ a = (a & 0xf0) | ulcolor;
+ else if (_intensity == 0)
+ a = (a & 0xf0) | halfcolor;
+ if (_reverse)
+ a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+ if (_blink)
+ a ^= 0x80;
+ if (_intensity == 2)
+ a ^= 0x08;
+ if (hi_font_mask == 0x100)
+ a <<= 1;
+ return a;
+ }
+#else
+ return 0;
+#endif
+}
+
+static void update_attr(int currcons)
{
- int lsr, ier;
- int i;
+ attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
+ video_erase_char = (build_attr(currcons, color, 1, 0, 0, decscnm) << 8) | ' ';
+}
- if (!serial_echo_port) return (0);
+/* Note: inverting the screen twice should revert to the original state */
- /*
- * First save the IER then disable the interrupts
- */
- ier = serial_echo_inb(UART_IER);
- serial_echo_outb(0x00, UART_IER);
+void invert_screen(int currcons, int offset, int count, int viewed)
+{
+ unsigned short *p;
- /*
- * Now, do each character
- */
- for (i = 0; *s; i++, s++) {
- WAIT_FOR_XMITR;
+ count /= 2;
+ p = screenpos(currcons, offset, viewed);
+ if (sw->con_invert_region)
+ sw->con_invert_region(vc_cons[currcons].d, p, count);
+#ifndef VT_BUF_VRAM_ONLY
+ else {
+ u16 *q = p;
+ int cnt = count;
+
+ if (!can_do_color) {
+ while (cnt--) *q++ ^= 0x0800;
+ } else if (hi_font_mask == 0x100) {
+ while (cnt--) {
+ u16 a = *q;
+ a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+ *q++ = a;
+ }
+ } else {
+ while (cnt--) {
+ u16 a = *q;
+ a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+ *q++ = a;
+ }
+ }
+ }
+#endif
+ update_region(currcons, (unsigned long) p, count);
+}
- /* Send the character out. */
- serial_echo_outb(*s, UART_TX);
+/* used by selection: complement pointer position */
+void complement_pos(int currcons, int offset)
+{
+ static unsigned short *p = NULL;
+ static unsigned short old = 0;
+ static unsigned short oldx = 0, oldy = 0;
- /* if a LF, also do CR... */
- if (*s == 10) {
- WAIT_FOR_XMITR;
- serial_echo_outb(13, UART_TX);
+ if (p) {
+ scr_writew(old, p);
+ if (DO_UPDATE)
+ sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
+ }
+ if (offset == -1)
+ p = NULL;
+ else {
+ unsigned short new;
+ p = screenpos(currcons, offset, 1);
+ old = scr_readw(p);
+ new = old ^ complement_mask;
+ scr_writew(new, p);
+ if (DO_UPDATE) {
+ oldx = (offset >> 1) % video_num_columns;
+ oldy = (offset >> 1) / video_num_columns;
+ sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
}
}
+}
- /*
- * Finally, Wait for transmitter & holding register to empty
- * and restore the IER
- */
- do {
- lsr = serial_echo_inb(UART_LSR);
- } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
- serial_echo_outb(ier, UART_IER);
+static void insert_char(int currcons, unsigned int nr)
+{
+ unsigned short *p, *q = (unsigned short *) pos;
- return (0);
+ p = q + video_num_columns - nr - x;
+ while (--p >= q)
+ scr_writew(scr_readw(p), p + nr);
+ scr_memsetw(q, video_erase_char, nr*2);
+ need_wrap = 0;
+ if (DO_UPDATE) {
+ unsigned short oldattr = attr;
+ sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
+ video_num_columns-x-nr);
+ attr = video_erase_char >> 8;
+ while (nr--)
+ sw->con_putc(vc_cons[currcons].d,
+ video_erase_char,y,x+nr);
+ attr = oldattr;
+ }
+}
+
+static void delete_char(int currcons, unsigned int nr)
+{
+ unsigned int i = x;
+ unsigned short *p = (unsigned short *) pos;
+
+ while (++i <= video_num_columns - nr) {
+ scr_writew(scr_readw(p+nr), p);
+ p++;
+ }
+ scr_memsetw(p, video_erase_char, nr*2);
+ need_wrap = 0;
+ if (DO_UPDATE) {
+ unsigned short oldattr = attr;
+ sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
+ video_num_columns-x-nr);
+ attr = video_erase_char >> 8;
+ while (nr--)
+ sw->con_putc(vc_cons[currcons].d,
+ video_erase_char, y,
+ video_num_columns-1-nr);
+ attr = oldattr;
+ }
}
+static int softcursor_original;
-int
-serial_echo_init(int base)
+static void add_softcursor(int currcons)
{
- int comstat, hi, lo;
-
- if (base != 0x2f8 && base != 0x3f8) {
- serial_echo_port = 0;
- return (0);
- } else
- serial_echo_port = base;
+ int i = scr_readw((u16 *) pos);
+ u32 type = cursor_type;
- /*
- * read the Divisor Latch
- */
- comstat = serial_echo_inb(UART_LCR);
- serial_echo_outb(comstat | UART_LCR_DLAB, UART_LCR);
- hi = serial_echo_inb(UART_DLM);
- lo = serial_echo_inb(UART_DLL);
- serial_echo_outb(comstat, UART_LCR);
+ if (! (type & 0x10)) return;
+ if (softcursor_original != -1) return;
+ softcursor_original = i;
+ i |= ((type >> 8) & 0xff00 );
+ i ^= ((type) & 0xff00 );
+ if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
+ if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
+ scr_writew(i, (u16 *) pos);
+ if (DO_UPDATE)
+ sw->con_putc(vc_cons[currcons].d, i, y, x);
+}
- /*
- * now do hardwired init
- */
- serial_echo_outb(0x03, UART_LCR); /* No parity, 8 data bits, 1 stop */
- serial_echo_outb(0x83, UART_LCR); /* Access divisor latch */
- serial_echo_outb(0x00, UART_DLM); /* 9600 baud */
- serial_echo_outb(0x0c, UART_DLL);
- serial_echo_outb(0x03, UART_LCR); /* Done with divisor */
-
- /* Prior to disabling interrupts, read the LSR and RBR
- * registers
- */
- comstat = serial_echo_inb(UART_LSR); /* COM? LSR */
- comstat = serial_echo_inb(UART_RX); /* COM? RBR */
- serial_echo_outb(0x00, UART_IER); /* Disable all interrupts */
+static void hide_cursor(int currcons)
+{
+ if (currcons == sel_cons)
+ clear_selection();
+ if (softcursor_original != -1) {
+ scr_writew(softcursor_original,(u16 *) pos);
+ if (DO_UPDATE)
+ sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
+ softcursor_original = -1;
+ }
+ sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
+}
- return(0);
+void set_cursor(int currcons)
+{
+ if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
+ return;
+ if (deccm) {
+ if (currcons == sel_cons)
+ clear_selection();
+ add_softcursor(currcons);
+ if ((cursor_type & 0x0f) != 1)
+ sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
+ } else
+ hide_cursor(currcons);
+}
+
+static void set_origin(int currcons)
+{
+ if (!IS_VISIBLE ||
+ !sw->con_set_origin ||
+ !sw->con_set_origin(vc_cons[currcons].d))
+ origin = (unsigned long) screenbuf;
+ visible_origin = origin;
+ scr_end = origin + screenbuf_size;
+ pos = origin + video_size_row*y + 2*x;
+}
+
+static inline void save_screen(void)
+{
+ int currcons = fg_console;
+ if (sw->con_save_screen)
+ sw->con_save_screen(vc_cons[currcons].d);
+}
+
+/*
+ * Redrawing of screen
+ */
+
+void update_screen(int new_console)
+{
+ int currcons = fg_console;
+ int redraw = 1;
+ int old_console;
+ static int lock = 0;
+ struct vc_data **display;
+
+ if (lock)
+ return;
+ if (!vc_cons_allocated(new_console)) {
+ /* strange ... */
+ printk("update_screen: tty %d not allocated ??\n", new_console+1);
+ return;
+ }
+ lock = 1;
+
+ hide_cursor(currcons);
+ if (fg_console != new_console) {
+ display = vc_cons[new_console].d->vc_display_fg;
+ old_console = (*display) ? (*display)->vc_num : fg_console;
+ *display = vc_cons[new_console].d;
+ fg_console = new_console;
+ currcons = old_console;
+ if (!IS_VISIBLE)
+ set_origin(currcons);
+ currcons = new_console;
+ if (old_console == new_console)
+ redraw = 0;
+ }
+ if (redraw) {
+ set_origin(currcons);
+ if (sw->con_switch(vc_cons[currcons].d))
+ /* Update the screen contents */
+ do_update_region(currcons, origin, screenbuf_size/2);
+ }
+ set_cursor(currcons);
+ set_leds();
+ compute_shiftstate();
+ lock = 0;
}
-#endif /* CONFIG_SERIAL_ECHO */
+/*
+ * Allocation, freeing and resizing of VTs.
+ */
int vc_cons_allocated(unsigned int i)
{
return (i < MAX_NR_CONSOLES && vc_cons[i].d);
}
-int vc_allocate(unsigned int i) /* return 0 on success */
+void visual_init(int currcons)
+{
+ /* ++Geert: sw->con_init determines console size */
+ sw = conswitchp;
+ cons_num = currcons;
+ display_fg = &master_display_fg;
+ vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
+ vc_cons[currcons].d->vc_uni_pagedir = 0;
+ hi_font_mask = 0;
+ complement_mask = 0;
+ sw->con_init(vc_cons[currcons].d, 1);
+ if (!complement_mask)
+ complement_mask = can_do_color ? 0x7700 : 0x0800;
+ video_size_row = video_num_columns<<1;
+ video_screen_size = video_num_lines*video_size_row;
+}
+
+int vc_allocate(unsigned int currcons, int init) /* return 0 on success */
{
- if (i >= MAX_NR_CONSOLES)
+ if (currcons >= MAX_NR_CONSOLES)
return -ENXIO;
- if (!vc_cons[i].d) {
+ if (!vc_cons[currcons].d) {
long p, q;
/* prevent users from taking too much memory */
- if (i >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
+ if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
return -EPERM;
/* due to the granularity of kmalloc, we waste some memory here */
/* the alloc is done in two steps, to optimize the common situation
of a 25x80 console (structsize=216, video_screen_size=4000) */
- q = (long) kmalloc(video_screen_size, GFP_KERNEL);
- if (!q)
- return -ENOMEM;
+ /* although the numbers above are not valid since long ago, the
+ point is still up-to-date and the comment still has its value
+ even if only as a historical artifact. --mj, July 1998 */
p = (long) kmalloc(structsize, GFP_KERNEL);
- if (!p) {
- kfree_s((char *) q, video_screen_size);
+ if (!p)
+ return -ENOMEM;
+ vc_cons[currcons].d = (struct vc_data *)p;
+ vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
+ visual_init(currcons);
+ q = (long)kmalloc(video_screen_size, GFP_KERNEL);
+ if (!q) {
+ kfree_s((char *) p, structsize);
+ vc_cons[currcons].d = NULL;
+ vt_cons[currcons] = NULL;
return -ENOMEM;
}
-
- vc_cons[i].d = (struct vc_data *) p;
- p += sizeof(struct vc_data);
- vt_cons[i] = (struct vt_struct *) p;
- vc_scrbuf[i] = (unsigned short *) q;
- vc_cons[i].d->vc_kmalloced = 1;
- vc_cons[i].d->vc_screenbuf_size = video_screen_size;
- vc_init (i, video_num_lines, video_num_columns, 1);
+ con_set_default_unimap(currcons);
+ screenbuf = (unsigned short *) q;
+ kmalloced = 1;
+ screenbuf_size = video_screen_size;
+ if (!sw->con_save_screen)
+ init = 0; /* If console does not have save_screen routine,
+ we should clear the screen */
+ vc_init(currcons, video_num_lines, video_num_columns, !init);
}
return 0;
}
/*
- * Change # of rows and columns (0 means unchanged)
+ * Change # of rows and columns (0 means unchanged/the size of fg_console)
* [this is to be used together with some user program
* like resize that changes the hardware videomode]
*/
-int vc_resize(unsigned long lines, unsigned long cols)
+int vc_resize(unsigned int lines, unsigned int cols,
+ unsigned int first, unsigned int last)
{
- unsigned long cc, ll, ss, sr;
- unsigned long occ, oll, oss, osr;
- unsigned short *p;
- unsigned int currcons, i;
+ unsigned int cc, ll, ss, sr, todo = 0;
+ unsigned int currcons = fg_console, i;
unsigned short *newscreens[MAX_NR_CONSOLES];
- long ol, nl, rlth, rrem;
cc = (cols ? cols : video_num_columns);
ll = (lines ? lines : video_num_lines);
sr = cc << 1;
ss = sr * ll;
- if (ss > video_mem_term - video_mem_base)
- return -ENOMEM;
-
- /*
- * Some earlier version had all consoles of potentially
- * different sizes, but that was really messy.
- * So now we only change if there is room for all consoles
- * of the same size.
- */
- for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
- if (!vc_cons_allocated(currcons))
- newscreens[currcons] = 0;
- else {
- p = (unsigned short *) kmalloc(ss, GFP_USER);
- if (!p) {
- for (i = 0; i< currcons; i++)
- if (newscreens[i])
- kfree_s(newscreens[i], ss);
- return -ENOMEM;
+ for (currcons = first; currcons <= last; currcons++) {
+ if (!vc_cons_allocated(currcons) ||
+ (cc == video_num_columns && ll == video_num_lines))
+ newscreens[currcons] = NULL;
+ else {
+ unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
+ if (!p) {
+ for (i = 0; i< currcons; i++)
+ if (newscreens[i])
+ kfree_s(newscreens[i], ss);
+ return -ENOMEM;
+ }
+ newscreens[currcons] = p;
+ todo++;
}
- newscreens[currcons] = p;
- }
}
+ if (!todo)
+ return 0;
- get_scrmem(fg_console);
-
- oll = video_num_lines;
- occ = video_num_columns;
- osr = video_size_row;
- oss = video_screen_size;
-
- video_num_lines = ll;
- video_num_columns = cc;
- video_size_row = sr;
- video_screen_size = ss;
-
- for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
- if (!vc_cons_allocated(currcons))
- continue;
-
- rlth = MIN(osr, sr);
- rrem = sr - rlth;
- ol = origin;
- nl = (long) newscreens[currcons];
- if (ll < oll)
- ol += (oll - ll) * osr;
-
- while (ol < scr_end) {
- memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
- if (rrem)
- memsetw((void *)(nl + rlth), video_erase_char, rrem);
- ol += osr;
- nl += sr;
- }
-
- if (kmalloced)
- kfree_s(vc_scrbuf[currcons], screenbuf_size);
- vc_scrbuf[currcons] = newscreens[currcons];
- kmalloced = 1;
- screenbuf_size = ss;
+ for (currcons = first; currcons <= last; currcons++) {
+ unsigned int occ, oll, oss, osr;
+ unsigned long ol, nl, nlend, rlth, rrem;
+ if (!newscreens[currcons] || !vc_cons_allocated(currcons))
+ continue;
- origin = video_mem_start = (long) vc_scrbuf[currcons];
- scr_end = video_mem_end = video_mem_start + ss;
+ oll = video_num_lines;
+ occ = video_num_columns;
+ osr = video_size_row;
+ oss = video_screen_size;
+
+ video_num_lines = ll;
+ video_num_columns = cc;
+ video_size_row = sr;
+ video_screen_size = ss;
+
+ rlth = MIN(osr, sr);
+ rrem = sr - rlth;
+ ol = origin;
+ nl = (long) newscreens[currcons];
+ nlend = nl + ss;
+ if (ll < oll)
+ ol += (oll - ll) * osr;
+
+ update_attr(currcons);
+
+ while (ol < scr_end) {
+ scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
+ if (rrem)
+ scr_memsetw((void *)(nl + rlth), video_erase_char, rrem);
+ ol += osr;
+ nl += sr;
+ }
+ if (nlend > nl)
+ scr_memsetw((void *) nl, video_erase_char, nlend - nl);
+ if (kmalloced)
+ kfree_s(screenbuf, oss);
+ screenbuf = newscreens[currcons];
+ kmalloced = 1;
+ screenbuf_size = ss;
+ set_origin(currcons);
- if (scr_end > nl)
- memsetw((void *) nl, video_erase_char, scr_end - nl);
+ /* do part of a reset_terminal() */
+ top = 0;
+ bottom = video_num_lines;
+ gotoxy(currcons, x, y);
+ save_cur(currcons);
+
+ if (console_table[currcons]) {
+ struct winsize ws, *cws = &console_table[currcons]->winsize;
+ memset(&ws, 0, sizeof(ws));
+ ws.ws_row = video_num_lines;
+ ws.ws_col = video_num_columns;
+ if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
+ console_table[currcons]->pgrp > 0)
+ kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
+ *cws = ws;
+ }
- /* do part of a reset_terminal() */
- top = 0;
- bottom = video_num_lines;
- gotoxy(currcons, x, y);
- save_cur(currcons);
+ if (IS_FG && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ update_screen(fg_console);
}
- set_scrmem(fg_console, 0);
- set_origin(fg_console);
set_cursor(fg_console);
-
return 0;
}
+
void vc_disallocate(unsigned int currcons)
{
if (vc_cons_allocated(currcons)) {
+ sw->con_deinit(vc_cons[currcons].d);
if (kmalloced)
- kfree_s(vc_scrbuf[currcons], screenbuf_size);
+ kfree_s(screenbuf, screenbuf_size);
if (currcons >= MIN_NR_CONSOLES)
- kfree_s(vc_cons[currcons].d, structsize);
- vc_cons[currcons].d = 0;
+ kfree_s(vc_cons[currcons].d, structsize);
+ vc_cons[currcons].d = NULL;
}
}
+/*
+ * VT102 emulator
+ */
#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
@@ -550,61 +811,10 @@ static void gotoxay(int currcons, int new_x, int new_y)
gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
}
-/*
- * Hardware scrollback support
- */
-extern void __set_origin(unsigned short);
-unsigned short __real_origin; /* offset of non-scrolled screen */
-unsigned short __origin; /* offset of currently displayed screen */
-unsigned char has_wrapped; /* all of videomem is data of fg_console */
-static unsigned char hardscroll_enabled;
-static unsigned char hardscroll_disabled_by_init = 0;
-
-void no_scroll(char *str, int *ints)
-{
- /*
- * Disabling scrollback is required for the Braillex ib80-piezo
- * Braille reader made by F.H. Papenmeier (Germany).
- * Use the "no-scroll" bootflag.
- */
- hardscroll_disabled_by_init = 1;
- hardscroll_enabled = 0;
-}
-
-static void scrolldelta(int lines)
-{
- int new_origin;
- int last_origin_rel = (((video_mem_term - video_mem_base)
- / video_num_columns / 2) - (video_num_lines - 1)) * video_num_columns;
-
- new_origin = __origin + lines * video_num_columns;
- if (__origin > __real_origin)
- new_origin -= last_origin_rel;
- if (new_origin < 0) {
- int s_top = __real_origin + video_num_lines*video_num_columns;
- new_origin += last_origin_rel;
- if (new_origin < s_top)
- new_origin = s_top;
- if (new_origin > last_origin_rel - video_num_columns
- || has_wrapped == 0)
- new_origin = 0;
- else {
- unsigned short * d = (unsigned short *) video_mem_base;
- unsigned short * s = d + last_origin_rel;
- int count = (video_num_lines-1)*video_num_columns;
- while (count) {
- count--;
- scr_writew(scr_readw(d++),s++);
- }
- }
- } else if (new_origin > __real_origin)
- new_origin = __real_origin;
-
- __set_origin(new_origin);
-}
-
void scrollback(int lines)
{
+ int currcons = fg_console;
+
if (!lines)
lines = video_num_lines/2;
scrolldelta(-lines);
@@ -612,156 +822,20 @@ void scrollback(int lines)
void scrollfront(int lines)
{
+ int currcons = fg_console;
+
if (!lines)
lines = video_num_lines/2;
scrolldelta(lines);
}
-static void set_origin(int currcons)
-{
- if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_VGAC &&
- video_type != VIDEO_TYPE_EGAM && video_type != VIDEO_TYPE_PICA_S3 &&
- video_type != VIDEO_TYPE_SNI_RM && video_type != VIDEO_TYPE_SGI)
- return;
- if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
- return;
- __real_origin = (origin-video_mem_base) >> 1;
- __set_origin(__real_origin);
-}
-
-static void scrup(int currcons, unsigned int t, unsigned int b, unsigned int nr)
-{
- int hardscroll = hardscroll_enabled;
-
- if (t+nr >= b)
- nr = b - t - 1;
- if (b > video_num_lines || t >= b || nr < 1)
- return;
- if (t || b != video_num_lines || nr > 1)
- hardscroll = 0;
- if (hardscroll) {
- origin += video_size_row;
- pos += video_size_row;
- scr_end += video_size_row;
-#if 0
- /*
- * Aiiiieee. This check works for Alpha and Intel, but
- * not for MIPS boxes ... The #ifdef is a temporary fix
- * for MIPSes that is slooow.
- */
- if (origin >= last_origin || origin < video_mem_base) { /*}*/
- if (scr_end > video_mem_end) { /*}*/
-#endif
- /*
- * Is the end of the area to scroll outside of the video RAM?
- * If so, just do normal softscroll. The second part of the
- * condition is important for some non-Intel architectures.
- */
- if (scr_end > video_mem_end || scr_end < video_mem_base) {
- unsigned short * d = (unsigned short *) video_mem_start;
- unsigned short * s = (unsigned short *) origin;
- unsigned int count;
-
- count = (video_num_lines-1)*video_num_columns;
- while (count) {
- count--;
- scr_writew(scr_readw(s++),d++);
- }
- count = video_num_columns;
- while (count) {
- count--;
- scr_writew(video_erase_char, d++);
- }
- scr_end -= origin-video_mem_start;
- pos -= origin-video_mem_start;
- origin = video_mem_start;
- has_scrolled = 1;
- if (currcons == fg_console)
- has_wrapped = 1;
- } else {
- unsigned short * d;
- unsigned int count;
-
- d = (unsigned short *) (scr_end - video_size_row);
- count = video_num_columns;
- while (count) {
- count--;
- scr_writew(video_erase_char, d++);
- }
- }
- set_origin(currcons);
- } else {
- unsigned short * d = (unsigned short *) (origin+video_size_row*t);
- unsigned short * s = (unsigned short *) (origin+video_size_row*(t+nr));
-
- memcpyw(d, s, (b-t-nr) * video_size_row);
- memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
- }
-}
-
-static void
-scrdown(int currcons, unsigned int t, unsigned int b, unsigned int nr)
-{
- unsigned short *s;
- unsigned int count;
- unsigned int step;
-
- if (t+nr >= b)
- nr = b - t - 1;
- if (b > video_num_lines || t >= b || nr < 1)
- return;
- s = (unsigned short *) (origin+video_size_row*(b-nr-1));
- step = video_num_columns * nr;
- count = b - t - nr;
- while (count--) {
- memcpyw(s + step, s, video_size_row);
- s -= video_num_columns;
- }
- while (nr--) {
- s += video_num_columns;
- memsetw(s, video_erase_char, video_size_row);
- }
- has_scrolled = 1;
-}
-
-/*
- * Routine to reset the visible "screen" to the top of video memory.
- * This is necessary when exiting from the kernel back to a console
- * which expects only the top of video memory to be used for the visible
- * screen (with scrolling down by moving the memory contents).
- * The normal action of the LINUX console is to scroll using all of the
- * video memory and diddling the hardware top-of-video register as needed.
- */
-void
-scrreset(void)
-{
- int currcons = fg_console;
- unsigned short * d = (unsigned short *) video_mem_start;
- unsigned short * s = (unsigned short *) origin;
- unsigned int count;
-
- count = (video_num_lines-1)*video_num_columns;
- memcpyw(d, s, 2*count);
- memsetw(d + count, video_erase_char,
- 2*video_num_columns);
- scr_end -= origin-video_mem_start;
- pos -= origin-video_mem_start;
- origin = video_mem_start;
-
- has_scrolled = 1;
- has_wrapped = 1;
-
- set_origin(currcons);
- set_cursor(currcons);
-}
-
static void lf(int currcons)
{
/* don't scroll if above bottom of scrolling region, or
* if below scrolling region
*/
if (y+1 == bottom)
- scrup(currcons,top,bottom, 1);
+ scrup(currcons,top,bottom,1);
else if (y < video_num_lines-1) {
y++;
pos += video_size_row;
@@ -805,91 +879,96 @@ static inline void del(int currcons)
static void csi_J(int currcons, int vpar)
{
- unsigned long count;
+ unsigned int count;
unsigned short * start;
switch (vpar) {
case 0: /* erase from cursor to end of display */
count = (scr_end-pos)>>1;
start = (unsigned short *) pos;
+ if (DO_UPDATE) {
+ /* do in two stages */
+ sw->con_clear(vc_cons[currcons].d, y, x, 1,
+ video_num_columns-x);
+ sw->con_clear(vc_cons[currcons].d, y+1, 0,
+ video_num_lines-y-1,
+ video_num_columns);
+ }
break;
case 1: /* erase from start to cursor */
count = ((pos-origin)>>1)+1;
start = (unsigned short *) origin;
+ if (DO_UPDATE) {
+ /* do in two stages */
+ sw->con_clear(vc_cons[currcons].d, 0, 0, y,
+ video_num_columns);
+ sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+ x + 1);
+ }
break;
case 2: /* erase whole display */
count = video_num_columns * video_num_lines;
start = (unsigned short *) origin;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, 0, 0,
+ video_num_lines,
+ video_num_columns);
break;
default:
return;
}
- memsetw(start, video_erase_char, 2*count);
+ scr_memsetw(start, video_erase_char, 2*count);
need_wrap = 0;
}
static void csi_K(int currcons, int vpar)
{
- unsigned long count;
+ unsigned int count;
unsigned short * start;
switch (vpar) {
case 0: /* erase from cursor to end of line */
count = video_num_columns-x;
start = (unsigned short *) pos;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, x, 1,
+ video_num_columns-x);
break;
case 1: /* erase from start of line to cursor */
start = (unsigned short *) (pos - (x<<1));
count = x+1;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+ x + 1);
break;
case 2: /* erase whole line */
start = (unsigned short *) (pos - (x<<1));
count = video_num_columns;
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, 0, 1,
+ video_num_columns);
break;
default:
return;
}
- memsetw(start, video_erase_char, 2 * count);
+ scr_memsetw(start, video_erase_char, 2 * count);
need_wrap = 0;
}
static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
{ /* not vt100? */
+ int count;
+
if (!vpar)
vpar++;
+ count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
- memsetw((unsigned short *) pos, video_erase_char,
- (vpar > video_num_columns-x) ? 2 * (video_num_columns-x) : 2 * vpar);
+ scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
+ if (DO_UPDATE)
+ sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
need_wrap = 0;
}
-static void update_attr(int currcons)
-{
- attr = color;
- if (can_do_color) {
- if (underline)
- attr = (attr & 0xf0) | ulcolor;
- else if (intensity == 0)
- attr = (attr & 0xf0) | halfcolor;
- }
- if (reverse ^ decscnm)
- attr = reverse_video_char(attr);
- if (blink)
- attr ^= 0x80;
- if (intensity == 2)
- attr ^= 0x08;
- if (!can_do_color) {
- if (underline)
- attr = (attr & 0xf8) | 0x01;
- else if (intensity == 0)
- attr = (attr & 0xf0) | 0x08;
- }
- if (decscnm)
- video_erase_char = (reverse_video_char(color) << 8) | ' ';
- else
- video_erase_char = (color << 8) | ' ';
-}
-
static void default_attr(int currcons)
{
intensity = 1;
@@ -1000,14 +1079,14 @@ static void respond_string(const char * p, struct tty_struct * tty)
tty_insert_flip_char(tty, *p, 0);
p++;
}
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
static void cursor_report(int currcons, struct tty_struct * tty)
{
char buf[40];
- sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1);
+ sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
respond_string(buf, tty);
}
@@ -1038,135 +1117,6 @@ int mouse_reporting(void)
return report_mouse;
}
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
- char type, data;
-
- if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
- return -EINVAL;
- if (current->tty != tty && !suser())
- return -EPERM;
- if (get_user(type, (char *)arg))
- return -EFAULT;
- switch (type)
- {
- case 2:
- return set_selection(arg, tty, 1);
- case 3:
- return paste_selection(tty);
- case 4:
- do_unblank_screen();
- return 0;
- case 5:
- return sel_loadlut(arg);
- case 6:
-
- /*
- * Make it possible to react to Shift+Mousebutton.
- * Note that 'shift_state' is an undocumented
- * kernel-internal variable; programs not closely
- * related to the kernel should not use this.
- */
- data = shift_state;
- return __put_user(data, (char *) arg);
- case 7:
- data = mouse_reporting();
- return __put_user(data, (char *) arg);
- case 10:
- set_vesa_blanking(arg);
- return 0;
- case 11: /* set kmsg redirect */
- if (!suser())
- return -EPERM;
- if (get_user(data, (char *)arg+1))
- return -EFAULT;
- kmsg_redirect = data;
- return 0;
- case 12: /* get fg_console */
- return fg_console;
- }
- return -EINVAL;
-}
-
-static inline unsigned short *screenpos(int currcons, int offset, int viewed)
-{
- unsigned short *p = (unsigned short *)(origin + offset);
- if (viewed && currcons == fg_console)
- p -= (__real_origin - __origin);
- return p;
-}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(int currcons, int offset, int count, int viewed)
-{
- unsigned short *p;
-
- count /= 2;
- p = screenpos(currcons, offset, viewed);
- if (can_do_color)
- while (count--) {
- unsigned short old = scr_readw(p);
- scr_writew(reverse_video_short(old), p);
- p++;
- }
- else
- while (count--) {
- unsigned short old = scr_readw(p);
- scr_writew(old ^ (((old & 0x0700) == 0x0100)
- ? 0x7000 : 0x7700), p);
- p++;
- }
-}
-
-/* used by selection: complement pointer position */
-void complement_pos(int currcons, int offset)
-{
- static unsigned short *p = NULL;
- static unsigned short old = 0;
-
- if (p)
- scr_writew(old, p);
- if (offset == -1)
- p = NULL;
- else {
- p = screenpos(currcons, offset, 1);
- old = scr_readw(p);
- scr_writew(old ^ 0x7700, p);
- }
-}
-
-/* used by selection */
-unsigned short screen_word(int currcons, int offset, int viewed)
-{
- return scr_readw(screenpos(currcons, offset, viewed));
-}
-
-/* used by selection - convert a screen word to a glyph number */
-int scrw2glyph(unsigned short scr_word)
-{
- return ( video_mode_512ch )
- ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff)
- : scr_word & 0x00ff;
-}
-
-/* used by vcs - note the word offset */
-unsigned short *screen_pos(int currcons, int w_offset, int viewed)
-{
- return screenpos(currcons, 2 * w_offset, viewed);
-}
-
-void getconsxy(int currcons, char *p)
-{
- p[0] = x;
- p[1] = y;
-}
-
-void putconsxy(int currcons, char *p)
-{
- gotoxy(currcons, p[0], p[1]);
- set_cursor(currcons);
-}
-
static void set_mode(int currcons, int on_off)
{
int i;
@@ -1212,7 +1162,6 @@ static void set_mode(int currcons, int on_off)
break;
case 25: /* Cursor on/off */
deccm = on_off;
- set_cursor(currcons);
break;
case 1000:
report_mouse = on_off ? 2 : 0;
@@ -1274,10 +1223,10 @@ static void setterm_command(int currcons)
break;
case 12: /* bring specified console to the front */
if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
- update_screen(par[1]-1);
+ set_console(par[1] - 1);
break;
case 13: /* unblank the screen */
- unblank_screen();
+ poke_blanked_console();
break;
case 14: /* set vesa powerdown interval */
vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
@@ -1285,39 +1234,12 @@ static void setterm_command(int currcons)
}
}
-static void insert_char(int currcons)
-{
- unsigned int i = x;
- unsigned short tmp, old = video_erase_char;
- unsigned short * p = (unsigned short *) pos;
-
- while (i++ < video_num_columns) {
- tmp = scr_readw(p);
- scr_writew(old, p);
- old = tmp;
- p++;
- }
- need_wrap = 0;
-}
-
static void insert_line(int currcons, unsigned int nr)
{
scrdown(currcons,y,bottom,nr);
need_wrap = 0;
}
-static void delete_char(int currcons)
-{
- unsigned int i = x;
- unsigned short * p = (unsigned short *) pos;
-
- while (++i < video_num_columns) {
- scr_writew(scr_readw(p+1), p);
- p++;
- }
- scr_writew(video_erase_char, p);
- need_wrap = 0;
-}
static void delete_line(int currcons, unsigned int nr)
{
@@ -1327,18 +1249,17 @@ static void delete_line(int currcons, unsigned int nr)
static void csi_at(int currcons, unsigned int nr)
{
- if (nr > video_num_columns)
- nr = video_num_columns;
+ if (nr > video_num_columns - x)
+ nr = video_num_columns - x;
else if (!nr)
nr = 1;
- while (nr--)
- insert_char(currcons);
+ insert_char(currcons, nr);
}
static void csi_L(int currcons, unsigned int nr)
{
- if (nr > video_num_lines)
- nr = video_num_lines;
+ if (nr > video_num_lines - y)
+ nr = video_num_lines - y;
else if (!nr)
nr = 1;
insert_line(currcons, nr);
@@ -1346,18 +1267,17 @@ static void csi_L(int currcons, unsigned int nr)
static void csi_P(int currcons, unsigned int nr)
{
- if (nr > video_num_columns)
- nr = video_num_columns;
+ if (nr > video_num_columns - x)
+ nr = video_num_columns - x;
else if (!nr)
nr = 1;
- while (nr--)
- delete_char(currcons);
+ delete_char(currcons, nr);
}
static void csi_M(int currcons, unsigned int nr)
{
- if (nr > video_num_lines)
- nr = video_num_lines;
+ if (nr > video_num_lines - y)
+ nr = video_num_lines - y;
else if (!nr)
nr=1;
delete_line(currcons, nr);
@@ -1431,6 +1351,8 @@ static void reset_terminal(int currcons, int do_clear)
kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
set_leds();
+ cursor_type = CUR_DEFAULT;
+
default_attr(currcons);
update_attr(currcons);
@@ -1449,61 +1371,380 @@ static void reset_terminal(int currcons, int do_clear)
csi_J(currcons,2);
}
-/*
- * Turn the Scroll-Lock LED on when the tty is stopped
- */
-static void con_stop(struct tty_struct *tty)
+static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
{
- int console_num;
- if (!tty)
+ /*
+ * Control characters can be used in the _middle_
+ * of an escape sequence.
+ */
+ switch (c) {
+ case 0:
return;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
+ case 7:
+ if (bell_duration)
+ kd_mksound(bell_pitch, bell_duration);
return;
-#if !CONFIG_AP1000
- set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
- set_leds();
-#endif
-}
-
-/*
- * Turn the Scroll-Lock LED off when the console is started
- */
-static void con_start(struct tty_struct *tty)
-{
- int console_num;
- if (!tty)
+ case 8:
+ bs(currcons);
return;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
+ case 9:
+ pos -= (x << 1);
+ while (x < video_num_columns - 1) {
+ x++;
+ if (tab_stop[x >> 5] & (1 << (x & 31)))
+ break;
+ }
+ pos += (x << 1);
return;
-#if !CONFIG_AP1000
- clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
- set_leds();
-#endif
+ case 10: case 11: case 12:
+ lf(currcons);
+ if (!is_kbd(lnm))
+ return;
+ case 13:
+ cr(currcons);
+ return;
+ case 14:
+ charset = 1;
+ translate = set_translate(G1_charset);
+ disp_ctrl = 1;
+ return;
+ case 15:
+ charset = 0;
+ translate = set_translate(G0_charset);
+ disp_ctrl = 0;
+ return;
+ case 24: case 26:
+ vc_state = ESnormal;
+ return;
+ case 27:
+ vc_state = ESesc;
+ return;
+ case 127:
+ del(currcons);
+ return;
+ case 128+27:
+ vc_state = ESsquare;
+ return;
+ }
+ switch(vc_state) {
+ case ESesc:
+ vc_state = ESnormal;
+ switch (c) {
+ case '[':
+ vc_state = ESsquare;
+ return;
+ case ']':
+ vc_state = ESnonstd;
+ return;
+ case '%':
+ vc_state = ESpercent;
+ return;
+ case 'E':
+ cr(currcons);
+ lf(currcons);
+ return;
+ case 'M':
+ ri(currcons);
+ return;
+ case 'D':
+ lf(currcons);
+ return;
+ case 'H':
+ tab_stop[x >> 5] |= (1 << (x & 31));
+ return;
+ case 'Z':
+ respond_ID(tty);
+ return;
+ case '7':
+ save_cur(currcons);
+ return;
+ case '8':
+ restore_cur(currcons);
+ return;
+ case '(':
+ vc_state = ESsetG0;
+ return;
+ case ')':
+ vc_state = ESsetG1;
+ return;
+ case '#':
+ vc_state = EShash;
+ return;
+ case 'c':
+ reset_terminal(currcons,1);
+ return;
+ case '>': /* Numeric keypad */
+ clr_kbd(kbdapplic);
+ return;
+ case '=': /* Appl. keypad */
+ set_kbd(kbdapplic);
+ return;
+ }
+ return;
+ case ESnonstd:
+ if (c=='P') { /* palette escape sequence */
+ for (npar=0; npar<NPAR; npar++)
+ par[npar] = 0 ;
+ npar = 0 ;
+ vc_state = ESpalette;
+ return;
+ } else if (c=='R') { /* reset palette */
+ reset_palette (currcons);
+ vc_state = ESnormal;
+ } else
+ vc_state = ESnormal;
+ return;
+ case ESpalette:
+ if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
+ par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
+ if (npar==7) {
+ int i = par[0]*3, j = 1;
+ palette[i] = 16*par[j++];
+ palette[i++] += par[j++];
+ palette[i] = 16*par[j++];
+ palette[i++] += par[j++];
+ palette[i] = 16*par[j++];
+ palette[i] += par[j];
+ set_palette() ;
+ vc_state = ESnormal;
+ }
+ } else
+ vc_state = ESnormal;
+ return;
+ case ESsquare:
+ for(npar = 0 ; npar < NPAR ; npar++)
+ par[npar] = 0;
+ npar = 0;
+ vc_state = ESgetpars;
+ if (c == '[') { /* Function key */
+ vc_state=ESfunckey;
+ return;
+ }
+ ques = (c=='?');
+ if (ques)
+ return;
+ case ESgetpars:
+ if (c==';' && npar<NPAR-1) {
+ npar++;
+ return;
+ } else if (c>='0' && c<='9') {
+ par[npar] *= 10;
+ par[npar] += c-'0';
+ return;
+ } else vc_state=ESgotpars;
+ case ESgotpars:
+ vc_state = ESnormal;
+ switch(c) {
+ case 'h':
+ set_mode(currcons,1);
+ return;
+ case 'l':
+ set_mode(currcons,0);
+ return;
+ case 'c':
+ if (ques) {
+ if (par[0])
+ cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+ else
+ cursor_type = CUR_DEFAULT;
+ return;
+ }
+ break;
+ case 'n':
+ if (!ques) {
+ if (par[0] == 5)
+ status_report(tty);
+ else if (par[0] == 6)
+ cursor_report(currcons,tty);
+ }
+ return;
+ }
+ if (ques) {
+ ques = 0;
+ return;
+ }
+ switch(c) {
+ case 'G': case '`':
+ if (par[0]) par[0]--;
+ gotoxy(currcons,par[0],y);
+ return;
+ case 'A':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x,y-par[0]);
+ return;
+ case 'B': case 'e':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x,y+par[0]);
+ return;
+ case 'C': case 'a':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x+par[0],y);
+ return;
+ case 'D':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,x-par[0],y);
+ return;
+ case 'E':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,0,y+par[0]);
+ return;
+ case 'F':
+ if (!par[0]) par[0]++;
+ gotoxy(currcons,0,y-par[0]);
+ return;
+ case 'd':
+ if (par[0]) par[0]--;
+ gotoxay(currcons,x,par[0]);
+ return;
+ case 'H': case 'f':
+ if (par[0]) par[0]--;
+ if (par[1]) par[1]--;
+ gotoxay(currcons,par[1],par[0]);
+ return;
+ case 'J':
+ csi_J(currcons,par[0]);
+ return;
+ case 'K':
+ csi_K(currcons,par[0]);
+ return;
+ case 'L':
+ csi_L(currcons,par[0]);
+ return;
+ case 'M':
+ csi_M(currcons,par[0]);
+ return;
+ case 'P':
+ csi_P(currcons,par[0]);
+ return;
+ case 'c':
+ if (!par[0])
+ respond_ID(tty);
+ return;
+ case 'g':
+ if (!par[0])
+ tab_stop[x >> 5] &= ~(1 << (x & 31));
+ else if (par[0] == 3) {
+ tab_stop[0] =
+ tab_stop[1] =
+ tab_stop[2] =
+ tab_stop[3] =
+ tab_stop[4] = 0;
+ }
+ return;
+ case 'm':
+ csi_m(currcons);
+ return;
+ case 'q': /* DECLL - but only 3 leds */
+ /* map 0,1,2,3 to 0,1,2,4 */
+ if (par[0] < 4)
+ setledstate(kbd_table + currcons,
+ (par[0] < 3) ? par[0] : 4);
+ return;
+ case 'r':
+ if (!par[0])
+ par[0]++;
+ if (!par[1])
+ par[1] = video_num_lines;
+ /* Minimum allowed region is 2 lines */
+ if (par[0] < par[1] &&
+ par[1] <= video_num_lines) {
+ top=par[0]-1;
+ bottom=par[1];
+ gotoxay(currcons,0,0);
+ }
+ return;
+ case 's':
+ save_cur(currcons);
+ return;
+ case 'u':
+ restore_cur(currcons);
+ return;
+ case 'X':
+ csi_X(currcons, par[0]);
+ return;
+ case '@':
+ csi_at(currcons,par[0]);
+ return;
+ case ']': /* setterm functions */
+ setterm_command(currcons);
+ return;
+ }
+ return;
+ case ESpercent:
+ vc_state = ESnormal;
+ switch (c) {
+ case '@': /* defined in ISO 2022 */
+ utf = 0;
+ return;
+ case 'G': /* prelim official escape code */
+ case '8': /* retained for compatibility */
+ utf = 1;
+ return;
+ }
+ return;
+ case ESfunckey:
+ vc_state = ESnormal;
+ return;
+ case EShash:
+ vc_state = ESnormal;
+ if (c == '8') {
+ /* DEC screen alignment test. kludge :-) */
+ video_erase_char =
+ (video_erase_char & 0xff00) | 'E';
+ csi_J(currcons, 2);
+ video_erase_char =
+ (video_erase_char & 0xff00) | ' ';
+ do_update_region(currcons, origin, screenbuf_size/2);
+ }
+ return;
+ case ESsetG0:
+ if (c == '0')
+ G0_charset = GRAF_MAP;
+ else if (c == 'B')
+ G0_charset = LAT1_MAP;
+ else if (c == 'U')
+ G0_charset = IBMPC_MAP;
+ else if (c == 'K')
+ G0_charset = USER_MAP;
+ if (charset == 0)
+ translate = set_translate(G0_charset);
+ vc_state = ESnormal;
+ return;
+ case ESsetG1:
+ if (c == '0')
+ G1_charset = GRAF_MAP;
+ else if (c == 'B')
+ G1_charset = LAT1_MAP;
+ else if (c == 'U')
+ G1_charset = IBMPC_MAP;
+ else if (c == 'K')
+ G1_charset = USER_MAP;
+ if (charset == 1)
+ translate = set_translate(G1_charset);
+ vc_state = ESnormal;
+ return;
+ default:
+ vc_state = ESnormal;
+ }
}
-static void con_flush_chars(struct tty_struct *tty)
-{
- unsigned int currcons;
- struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-
- currcons = vt->vc_num;
- if (vcmode != KD_GRAPHICS)
- set_cursor(currcons);
-}
-
static int do_con_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
- int c, tc, ok, n = 0;
+#ifdef VT_BUF_VRAM_ONLY
+#define FLUSH do { } while(0);
+#else
+#define FLUSH if (draw_x >= 0) { \
+ sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
+ draw_x = -1; \
+ }
+#endif
+
+ int c, tc, ok, n = 0, draw_x = -1;
unsigned int currcons;
+ unsigned long draw_from = 0, draw_to = 0;
struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-
-#if CONFIG_AP1000
- ap_write(1,buf,count);
- return(count);
-#endif
+ u16 himask, charmask;
currcons = vt->vc_num;
if (!vc_cons_allocated(currcons)) {
@@ -1516,17 +1757,21 @@ static int do_con_write(struct tty_struct * tty, int from_user,
return 0;
}
- if (currcons == sel_cons)
- clear_selection();
-
if (from_user) {
/* just to make sure that noone lurks at places he shouldn't see. */
if (verify_area(VERIFY_READ, buf, count))
return 0; /* ?? are error codes legal here ?? */
}
+ himask = hi_font_mask;
+ charmask = himask ? 0x1ff : 0xff;
+
+ /* undraw cursor first */
+ if (IS_FG)
+ hide_cursor(currcons);
+
disable_bh(CONSOLE_BH);
- while (!tty->stopped && count) {
+ while (!tty->stopped && count) {
enable_bh(CONSOLE_BH);
if (from_user)
__get_user(c, buf);
@@ -1591,11 +1836,11 @@ static int do_con_write(struct tty_struct * tty, int from_user,
if (vc_state == ESnormal && ok) {
/* Now try to find out how to display it */
- tc = conv_uni_to_pc(tc);
+ tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
if ( tc == -4 ) {
/* If we got -4 (not found) then see if we have
defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(0xfffd);
+ tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
/* One reason for the -4 can be that we just
did a clear_unimap();
@@ -1606,429 +1851,86 @@ static int do_con_write(struct tty_struct * tty, int from_user,
/* Bad hash table -- hope for the best */
tc = c;
}
- if (tc & ~console_charmask)
+ if (tc & ~charmask)
continue; /* Conversion failed */
+ if (need_wrap || decim)
+ FLUSH
if (need_wrap) {
cr(currcons);
lf(currcons);
}
if (decim)
- insert_char(currcons);
- scr_writew( video_mode_512ch ?
- ((attr & 0xf7) << 8) + ((tc & 0x100) << 3) +
- (tc & 0x0ff) : (attr << 8) + tc,
- (unsigned short *) pos);
- if (x == video_num_columns - 1)
+ insert_char(currcons, 1);
+ scr_writew(himask ?
+ ((attr & ~himask) << 8) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+ (attr << 8) + tc,
+ (u16 *) pos);
+ if (DO_UPDATE && draw_x < 0) {
+ draw_x = x;
+ draw_from = pos;
+ }
+ if (x == video_num_columns - 1) {
need_wrap = decawm;
- else {
+ draw_to = pos+2;
+ } else {
x++;
- pos+=2;
+ draw_to = (pos+=2);
}
continue;
}
-
- /*
- * Control characters can be used in the _middle_
- * of an escape sequence.
- */
- switch (c) {
- case 0:
- continue;
- case 7:
- if (bell_duration)
- kd_mksound(bell_pitch, bell_duration);
- continue;
- case 8:
- bs(currcons);
- continue;
- case 9:
- pos -= (x << 1);
- while (x < video_num_columns - 1) {
- x++;
- if (tab_stop[x >> 5] & (1 << (x & 31)))
- break;
- }
- pos += (x << 1);
- continue;
- case 10: case 11: case 12:
- lf(currcons);
- if (!is_kbd(lnm))
- continue;
- case 13:
- cr(currcons);
- continue;
- case 14:
- charset = 1;
- translate = set_translate(G1_charset);
- disp_ctrl = 1;
- continue;
- case 15:
- charset = 0;
- translate = set_translate(G0_charset);
- disp_ctrl = 0;
- continue;
- case 24: case 26:
- vc_state = ESnormal;
- continue;
- case 27:
- vc_state = ESesc;
- continue;
- case 127:
- del(currcons);
- continue;
- case 128+27:
- vc_state = ESsquare;
- continue;
- }
- switch(vc_state) {
- case ESesc:
- vc_state = ESnormal;
- switch (c) {
- case '[':
- vc_state = ESsquare;
- continue;
- case ']':
- vc_state = ESnonstd;
- continue;
- case '%':
- vc_state = ESpercent;
- continue;
- case 'E':
- cr(currcons);
- lf(currcons);
- continue;
- case 'M':
- ri(currcons);
- continue;
- case 'D':
- lf(currcons);
- continue;
- case 'H':
- tab_stop[x >> 5] |= (1 << (x & 31));
- continue;
- case 'Z':
- respond_ID(tty);
- continue;
- case '7':
- save_cur(currcons);
- continue;
- case '8':
- restore_cur(currcons);
- continue;
- case '(':
- vc_state = ESsetG0;
- continue;
- case ')':
- vc_state = ESsetG1;
- continue;
- case '#':
- vc_state = EShash;
- continue;
- case 'c':
- reset_terminal(currcons,1);
- continue;
- case '>': /* Numeric keypad */
- clr_kbd(kbdapplic);
- continue;
- case '=': /* Appl. keypad */
- set_kbd(kbdapplic);
- continue;
- }
- continue;
- case ESnonstd:
- if (c=='P') { /* palette escape sequence */
- for (npar=0; npar<NPAR; npar++)
- par[npar] = 0 ;
- npar = 0 ;
- vc_state = ESpalette;
- continue;
- } else if (c=='R') { /* reset palette */
- reset_palette (currcons);
- vc_state = ESnormal;
- } else
- vc_state = ESnormal;
- continue;
- case ESpalette:
- if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
- par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
- if (npar==7) {
- int i = par[0]*3, j = 1;
- palette[i] = 16*par[j++];
- palette[i++] += par[j++];
- palette[i] = 16*par[j++];
- palette[i++] += par[j++];
- palette[i] = 16*par[j++];
- palette[i] += par[j];
- set_palette() ;
- vc_state = ESnormal;
- }
- } else
- vc_state = ESnormal;
- continue;
- case ESsquare:
- for(npar = 0 ; npar < NPAR ; npar++)
- par[npar] = 0;
- npar = 0;
- vc_state = ESgetpars;
- if (c == '[') { /* Function key */
- vc_state=ESfunckey;
- continue;
- }
- ques = (c=='?');
- if (ques)
- continue;
- case ESgetpars:
- if (c==';' && npar<NPAR-1) {
- npar++;
- continue;
- } else if (c>='0' && c<='9') {
- par[npar] *= 10;
- par[npar] += c-'0';
- continue;
- } else vc_state=ESgotpars;
- case ESgotpars:
- vc_state = ESnormal;
- switch(c) {
- case 'h':
- set_mode(currcons,1);
- continue;
- case 'l':
- set_mode(currcons,0);
- continue;
- case 'n':
- if (!ques)
- if (par[0] == 5)
- status_report(tty);
- else if (par[0] == 6)
- cursor_report(currcons,tty);
- continue;
- }
- if (ques) {
- ques = 0;
- continue;
- }
- switch(c) {
- case 'G': case '`':
- if (par[0]) par[0]--;
- gotoxy(currcons,par[0],y);
- continue;
- case 'A':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y-par[0]);
- continue;
- case 'B': case 'e':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y+par[0]);
- continue;
- case 'C': case 'a':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x+par[0],y);
- continue;
- case 'D':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x-par[0],y);
- continue;
- case 'E':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y+par[0]);
- continue;
- case 'F':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y-par[0]);
- continue;
- case 'd':
- if (par[0]) par[0]--;
- gotoxay(currcons,x,par[0]);
- continue;
- case 'H': case 'f':
- if (par[0]) par[0]--;
- if (par[1]) par[1]--;
- gotoxay(currcons,par[1],par[0]);
- continue;
- case 'J':
- csi_J(currcons,par[0]);
- continue;
- case 'K':
- csi_K(currcons,par[0]);
- continue;
- case 'L':
- csi_L(currcons,par[0]);
- continue;
- case 'M':
- csi_M(currcons,par[0]);
- continue;
- case 'P':
- csi_P(currcons,par[0]);
- continue;
- case 'c':
- if (!par[0])
- respond_ID(tty);
- continue;
- case 'g':
- if (!par[0])
- tab_stop[x >> 5] &= ~(1 << (x & 31));
- else if (par[0] == 3) {
- tab_stop[0] =
- tab_stop[1] =
- tab_stop[2] =
- tab_stop[3] =
- tab_stop[4] = 0;
- }
- continue;
- case 'm':
- csi_m(currcons);
- continue;
- case 'q': /* DECLL - but only 3 leds */
- /* map 0,1,2,3 to 0,1,2,4 */
- if (par[0] < 4)
- setledstate(kbd_table + currcons,
- (par[0] < 3) ? par[0] : 4);
- continue;
- case 'r':
- if (!par[0])
- par[0]++;
- if (!par[1])
- par[1] = video_num_lines;
- /* Minimum allowed region is 2 lines */
- if (par[0] < par[1] &&
- par[1] <= video_num_lines) {
- top=par[0]-1;
- bottom=par[1];
- gotoxay(currcons,0,0);
- }
- continue;
- case 's':
- save_cur(currcons);
- continue;
- case 'u':
- restore_cur(currcons);
- continue;
- case 'X':
- csi_X(currcons, par[0]);
- continue;
- case '@':
- csi_at(currcons,par[0]);
- continue;
- case ']': /* setterm functions */
- setterm_command(currcons);
- continue;
- }
- continue;
- case ESpercent:
- vc_state = ESnormal;
- switch (c) {
- case '@': /* defined in ISO 2022 */
- utf = 0;
- continue;
- case 'G': /* prelim official escape code */
- case '8': /* retained for compatibility */
- utf = 1;
- continue;
- }
- continue;
- case ESfunckey:
- vc_state = ESnormal;
- continue;
- case EShash:
- vc_state = ESnormal;
- if (c == '8') {
- /* DEC screen alignment test. kludge :-) */
- video_erase_char =
- (video_erase_char & 0xff00) | 'E';
- csi_J(currcons, 2);
- video_erase_char =
- (video_erase_char & 0xff00) | ' ';
- }
- continue;
- case ESsetG0:
- if (c == '0')
- G0_charset = GRAF_MAP;
- else if (c == 'B')
- G0_charset = LAT1_MAP;
- else if (c == 'U')
- G0_charset = IBMPC_MAP;
- else if (c == 'K')
- G0_charset = USER_MAP;
- if (charset == 0)
- translate = set_translate(G0_charset);
- vc_state = ESnormal;
- continue;
- case ESsetG1:
- if (c == '0')
- G1_charset = GRAF_MAP;
- else if (c == 'B')
- G1_charset = LAT1_MAP;
- else if (c == 'U')
- G1_charset = IBMPC_MAP;
- else if (c == 'K')
- G1_charset = USER_MAP;
- if (charset == 1)
- translate = set_translate(G1_charset);
- vc_state = ESnormal;
- continue;
- default:
- vc_state = ESnormal;
- }
+ FLUSH
+ do_con_trol(tty, currcons, c);
}
+ FLUSH
enable_bh(CONSOLE_BH);
return n;
+#undef FLUSH
}
-static int con_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
-{
- int retval;
-
- retval = do_con_write(tty, from_user, buf, count);
- con_flush_chars(tty);
-
- return retval;
-}
-
-static void con_put_char(struct tty_struct *tty, unsigned char ch)
-{
- do_con_write(tty, 0, &ch, 1);
-}
-
-static int con_write_room(struct tty_struct *tty)
-{
- if (tty->stopped)
- return 0;
- return 4096; /* No limit, really; we're not buffering */
-}
-
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
- return 0; /* we're not buffering */
-}
-
-void poke_blanked_console(void)
+/*
+ * This is the console switching bottom half handler.
+ *
+ * Doing console switching in a bottom half handler allows
+ * us to do the switches asynchronously (needed when we want
+ * to switch due to a keyboard interrupt), while still giving
+ * us the option to easily disable it to avoid races when we
+ * need to write to the console.
+ */
+static void console_bh(void)
{
- timer_active &= ~(1<<BLANK_TIMER);
- if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
- return;
- if (console_blanked) {
- timer_table[BLANK_TIMER].fn = unblank_screen;
- timer_table[BLANK_TIMER].expires = 0;
- timer_active |= 1<<BLANK_TIMER;
- } else if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
+ run_task_queue(&con_task_queue);
+ if (want_console >= 0) {
+ if (want_console != fg_console && vc_cons_allocated(want_console)) {
+ hide_cursor(fg_console);
+ save_screen();
+ change_console(want_console);
+ /* we only changed when the console had already
+ been allocated - a new console is not created
+ in an interrupt routine */
+ }
+ want_console = -1;
+ }
+ if (do_poke_blanked_console) { /* do not unblank for a LED change */
+ do_poke_blanked_console = 0;
+ poke_blanked_console();
}
}
+/*
+ * Console on virtual terminal
+ */
+
#ifdef CONFIG_VT_CONSOLE
void vt_console_print(struct console *co, const char * b, unsigned count)
{
int currcons = fg_console;
unsigned char c;
static int printing = 0;
+ const ushort *start;
+ ushort cnt = 0;
+ ushort myx = x;
-#if CONFIG_AP1000
- prom_printf(b);
- return;
-#endif
if (!printable || printing)
return; /* console not yet initialized */
printing = 1;
@@ -2039,36 +1941,68 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
if (!vc_cons_allocated(currcons)) {
/* impossible */
printk("vt_console_print: tty %d not allocated ??\n", currcons+1);
- return;
+ goto quit;
}
-#ifdef CONFIG_SERIAL_ECHO
- serial_echo_print(b);
-#endif /* CONFIG_SERIAL_ECHO */
+ /* undraw cursor first */
+ if (IS_FG)
+ hide_cursor(currcons);
+
+ start = (ushort *)pos;
- while (count-- > 0) {
- c = *(b++);
- if (c == 10 || c == 13 || need_wrap) {
+ /* Contrived structure to try to emulate original need_wrap behaviour
+ * Problems caused when we have need_wrap set on '\n' character */
+ disable_bh(CONSOLE_BH);
+ while (count--) {
+ enable_bh(CONSOLE_BH);
+ c = *b++;
+ disable_bh(CONSOLE_BH);
+ if (c == 10 || c == 13 || c == 8 || need_wrap) {
+ if (cnt > 0) {
+ if (IS_VISIBLE)
+ sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
+ x += cnt;
+ if (need_wrap)
+ x--;
+ cnt = 0;
+ }
+ if (c == 8) { /* backspace */
+ bs(currcons);
+ start = (ushort *)pos;
+ myx = x;
+ continue;
+ }
if (c != 13)
lf(currcons);
cr(currcons);
+ start = (ushort *)pos;
+ myx = x;
if (c == 10 || c == 13)
continue;
}
- if (c == 8) { /* backspace */
- bs(currcons);
- continue;
- }
scr_writew((attr << 8) + c, (unsigned short *) pos);
- if (x == video_num_columns - 1) {
+ cnt++;
+ if (myx == video_num_columns - 1) {
need_wrap = 1;
continue;
}
- x++;
pos+=2;
+ myx++;
}
+ if (cnt > 0) {
+ if (IS_VISIBLE)
+ sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
+ x += cnt;
+ if (x == video_num_columns) {
+ x--;
+ need_wrap = 1;
+ }
+ }
+ enable_bh(CONSOLE_BH);
set_cursor(currcons);
poke_blanked_console();
+
+quit:
printing = 0;
}
@@ -2077,8 +2011,6 @@ static kdev_t vt_console_device(struct console *c)
return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
}
-extern int keyboard_wait_for_keypress(struct console *);
-
struct console vt_console_driver = {
"tty",
vt_console_print,
@@ -2095,6 +2027,92 @@ struct console vt_console_driver = {
#endif
/*
+ * Handling of Linux-specific VC ioctls
+ */
+
+int tioclinux(struct tty_struct *tty, unsigned long arg)
+{
+ char type, data;
+
+ if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
+ return -EINVAL;
+ if (current->tty != tty && !suser())
+ return -EPERM;
+ if (get_user(type, (char *)arg))
+ return -EFAULT;
+ switch (type)
+ {
+ case 2:
+ return set_selection(arg, tty, 1);
+ case 3:
+ return paste_selection(tty);
+ case 4:
+ do_unblank_screen();
+ return 0;
+ case 5:
+ return sel_loadlut(arg);
+ case 6:
+
+ /*
+ * Make it possible to react to Shift+Mousebutton.
+ * Note that 'shift_state' is an undocumented
+ * kernel-internal variable; programs not closely
+ * related to the kernel should not use this.
+ */
+ data = shift_state;
+ return __put_user(data, (char *) arg);
+ case 7:
+ data = mouse_reporting();
+ return __put_user(data, (char *) arg);
+ case 10:
+ set_vesa_blanking(arg);
+ return 0;
+ case 11: /* set kmsg redirect */
+ if (!suser())
+ return -EPERM;
+ if (get_user(data, (char *)arg+1))
+ return -EFAULT;
+ kmsg_redirect = data;
+ return 0;
+ case 12: /* get fg_console */
+ return fg_console;
+ }
+ return -EINVAL;
+}
+
+/*
+ * /dev/ttyN handling
+ */
+
+static int con_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int retval;
+
+ retval = do_con_write(tty, from_user, buf, count);
+ con_flush_chars(tty);
+
+ return retval;
+}
+
+static void con_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ do_con_write(tty, 0, &ch, 1);
+}
+
+static int con_write_room(struct tty_struct *tty)
+{
+ if (tty->stopped)
+ return 0;
+ return 4096; /* No limit, really; we're not buffering */
+}
+
+static int con_chars_in_buffer(struct tty_struct *tty)
+{
+ return 0; /* we're not buffering */
+}
+
+/*
* con_throttle and con_unthrottle are only used for
* paste_selection(), which has to stuff in a large number of
* characters...
@@ -2110,9 +2128,69 @@ static void con_unthrottle(struct tty_struct *tty)
wake_up_interruptible(&vt->paste_wait);
}
-static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear)
+/*
+ * Turn the Scroll-Lock LED on when the tty is stopped
+ */
+static void con_stop(struct tty_struct *tty)
+{
+ int console_num;
+ if (!tty)
+ return;
+ console_num = MINOR(tty->device) - (tty->driver.minor_start);
+ if (!vc_cons_allocated(console_num))
+ return;
+ set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+ set_leds();
+}
+
+/*
+ * Turn the Scroll-Lock LED off when the console is started
+ */
+static void con_start(struct tty_struct *tty)
+{
+ int console_num;
+ if (!tty)
+ return;
+ console_num = MINOR(tty->device) - (tty->driver.minor_start);
+ if (!vc_cons_allocated(console_num))
+ return;
+ clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+ set_leds();
+}
+
+static void con_flush_chars(struct tty_struct *tty)
+{
+ struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+
+ set_cursor(vt->vc_num);
+}
+
+/*
+ * Allocate the console screen memory.
+ */
+static int con_open(struct tty_struct *tty, struct file * filp)
+{
+ unsigned int currcons;
+ int i;
+
+ currcons = MINOR(tty->device) - tty->driver.minor_start;
+
+ i = vc_allocate(currcons, 0);
+ if (i)
+ return i;
+
+ vt_cons[currcons]->vc_num = currcons;
+ tty->driver_data = vt_cons[currcons];
+
+ if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+ tty->winsize.ws_row = video_num_lines;
+ tty->winsize.ws_col = video_num_columns;
+ }
+ return 0;
+}
+
+static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
{
- long base = (long) vc_scrbuf[currcons];
int j, k ;
video_num_columns = cols;
@@ -2120,9 +2198,8 @@ static void vc_init(unsigned int currcons, unsigned long rows, unsigned long col
video_size_row = cols<<1;
video_screen_size = video_num_lines * video_size_row;
- pos = origin = video_mem_start = base;
- scr_end = base + video_screen_size;
- video_mem_end = base + video_screen_size;
+ set_origin(currcons);
+ pos = origin;
reset_vc(currcons);
for (j=k=0; j<16; j++) {
vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
@@ -2136,83 +2213,26 @@ static void vc_init(unsigned int currcons, unsigned long rows, unsigned long col
reset_terminal(currcons, do_clear);
}
-static void con_setsize(unsigned long rows, unsigned long cols)
-{
- video_num_lines = rows;
- video_num_columns = cols;
- video_size_row = 2 * cols;
- video_screen_size = video_num_lines * video_size_row;
-}
-
/*
- * This is the console switching bottom half handler.
- *
- * Doing console switching in a bottom half handler allows
- * us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt), while still giving
- * us the option to easily disable it to avoid races when we
- * need to write to the console.
- */
-static void console_bh(void)
-{
- if (want_console >= 0) {
- if (want_console != fg_console) {
- change_console(want_console);
- /* we only changed when the console had already
- been allocated - a new console is not created
- in an interrupt routine */
- }
- want_console = -1;
- }
- if (do_poke_blanked_console) { /* do not unblank for a LED change */
- do_poke_blanked_console = 0;
- poke_blanked_console();
- }
-}
-
-/*
- * unsigned long con_init(unsigned long);
- *
* This routine initializes console interrupts, and does nothing
* else. If you want the screen to clear, call tty_write with
* the appropriate escape-sequence.
- *
- * Reads the information preserved by setup.s to determine the current display
- * type and sets everything accordingly.
- *
- * FIXME: return early if we don't _have_ a video card installed.
- *
*/
-__initfunc(unsigned long con_init(unsigned long kmem_start))
-{
- const char *display_desc = "????";
- int currcons = 0;
- int orig_x = ORIG_X;
- int orig_y = ORIG_Y;
-
-#ifdef CONFIG_SGI
- if (serial_console) {
- fg_console = 0;
- rs_cons_hook(0, 0, serial_console);
- rs_cons_hook(0, 1, serial_console);
+struct tty_driver console_driver;
+static int console_refcount;
- return kmem_start;
- }
-#endif
+__initfunc(unsigned long con_init(unsigned long kmem_start))
+{
+ const char *display_desc = NULL;
+ unsigned int currcons = 0;
-#ifdef __sparc__
- if (serial_console) {
+ if (conswitchp)
+ display_desc = conswitchp->con_startup();
+ if (!display_desc) {
fg_console = 0;
-
-#if CONFIG_SUN_SERIAL
- rs_cons_hook(0, 0, serial_console);
- rs_cons_hook(0, 1, serial_console);
-#endif
-
return kmem_start;
}
-#endif
memset(&console_driver, 0, sizeof(struct tty_driver));
console_driver.magic = TTY_DRIVER_MAGIC;
@@ -2244,11 +2264,6 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
if (tty_register_driver(&console_driver))
panic("Couldn't register console driver\n");
-#if CONFIG_AP1000
- return(kmem_start);
-#endif
- con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
-
timer_table[BLANK_TIMER].fn = blank_screen;
timer_table[BLANK_TIMER].expires = 0;
if (blankinterval) {
@@ -2256,16 +2271,7 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
timer_active |= 1<<BLANK_TIMER;
}
- kmem_start = con_type_init(kmem_start, &display_desc);
-
- hardscroll_enabled = (hardscroll_disabled_by_init ? 0 :
- (video_type == VIDEO_TYPE_EGAC
- || video_type == VIDEO_TYPE_VGAC
- || video_type == VIDEO_TYPE_EGAM
- || video_type == VIDEO_TYPE_PICA_S3
- || video_type == VIDEO_TYPE_SNI_RM ));
- has_wrapped = 0 ;
-
+ /* Unfortunately, kmalloc is not running yet */
/* Due to kmalloc roundup allocating statically is more efficient -
so provide MIN_NR_CONSOLES for people with very little memory */
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
@@ -2275,11 +2281,12 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
kmem_start += sizeof(struct vc_data);
vt_cons[currcons] = (struct vt_struct *) kmem_start;
kmem_start += sizeof(struct vt_struct);
- vc_scrbuf[currcons] = (unsigned short *) kmem_start;
+ visual_init(currcons);
+ screenbuf = (unsigned short *) kmem_start;
kmem_start += video_screen_size;
kmalloced = 0;
- screenbuf_size = video_screen_size;
- vc_init(currcons, video_num_lines, video_num_columns, currcons);
+ vc_init(currcons, video_num_lines, video_num_columns,
+ currcons || !sw->con_save_screen);
for (j=k=0; j<16; j++) {
vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
@@ -2288,77 +2295,100 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
}
currcons = fg_console = 0;
-
- video_mem_start = video_mem_base;
- video_mem_end = video_mem_term;
- origin = video_mem_start;
- scr_end = video_mem_start + video_num_lines * video_size_row;
- gotoxy(currcons,orig_x,orig_y);
+ master_display_fg = vc_cons[currcons].d;
set_origin(currcons);
+ save_screen();
+ gotoxy(currcons,x,y);
csi_J(currcons, 0);
+ update_screen(fg_console);
+ set_cursor(currcons);
+ printk("Console: %s %s %dx%d",
+ can_do_color ? "colour" : "mono",
+ display_desc, video_num_columns, video_num_lines);
+ printable = 1;
+ printk("\n");
- /* Figure out the size of the screen and screen font so we
- can figure out the appropriate screen size should we load
- a different font */
+#ifdef CONFIG_VT_CONSOLE
+ register_console(&vt_console_driver);
+#endif
- printable = 1;
- if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC
- || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC
- || video_type == VIDEO_TYPE_SGI || video_type == VIDEO_TYPE_SUN )
- {
- default_font_height = video_font_height = ORIG_VIDEO_POINTS;
- /* This may be suboptimal but is a safe bet - go with it */
- video_scan_lines = video_font_height * video_num_lines;
+ init_bh(CONSOLE_BH, console_bh);
+
+ return kmem_start;
+}
-#ifdef CONFIG_SERIAL_ECHO
- serial_echo_init(SERIAL_ECHO_PORT);
-#endif /* CONFIG_SERIAL_ECHO */
+/*
+ * If we support more console drivers, this function is used
+ * when a driver wants to take over some existing consoles
+ * and become default driver for newly opened ones.
+ */
- printk("Console: %ld point font, %ld scans\n",
- video_font_height, video_scan_lines);
- }
-#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI)
- else if (video_type == VIDEO_TYPE_PICA_S3 ||
- video_type == VIDEO_TYPE_SNI_RM)
- {
- /*
- * Fixme: we should detect this. But still 16 is a reasonable
- * assumption.
- */
- default_font_height = video_font_height = 16;
- /* This may be suboptimal but is a safe bet - go with it */
- video_scan_lines = video_font_height * video_num_lines;
-
-#ifdef CONFIG_SERIAL_ECHO
- serial_echo_init(SERIAL_ECHO_PORT);
-#endif /* CONFIG_SERIAL_ECHO */
-
- printk("Console: %ld point font, %ld scans\n",
- video_font_height, video_scan_lines);
- }
-#endif
+#ifndef VT_BUF_VRAM_ONLY
- printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
- can_do_color ? "colour" : "mono",
- display_desc, video_num_columns, video_num_lines,
- MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s",
- MAX_NR_CONSOLES);
+void take_over_console(struct consw *csw, int first, int last, int deflt)
+{
+ int i;
+ const char *desc;
- con_type_init_finish();
+ if (deflt)
+ conswitchp = csw;
+ desc = csw->con_startup();
+ if (!desc) return;
+
+ for (i = first; i <= last; i++) {
+ if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
+ continue;
+ if (i == fg_console &&
+ vc_cons[i].d->vc_sw->con_save_screen)
+ vc_cons[i].d->vc_sw->con_save_screen(vc_cons[i].d);
+ vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
+ vc_cons[i].d->vc_sw = csw;
+ vc_cons[i].d->vc_sw->con_init(vc_cons[i].d, 0);
+ }
+ printk("Console: switching to %s %s %dx%d\n",
+ vc_cons[fg_console].d->vc_can_do_color ? "colour" : "mono",
+ desc, vc_cons[fg_console].d->vc_cols, vc_cons[fg_console].d->vc_rows);
+ set_palette();
+}
- /*
- * can't register TGA yet, because PCI bus probe has *not* taken
- * place before con_init() gets called. Trigger the real TGA hw
- * initialization and register_console() event from
- * within the bus probing code... :-(
- */
-#ifdef CONFIG_VT_CONSOLE
- if (video_type != VIDEO_TYPE_TGAC && con_is_present())
- register_console(&vt_console_driver);
#endif
- init_bh(CONSOLE_BH, console_bh);
- return kmem_start;
+/*
+ * Screen blanking
+ */
+
+void set_vesa_blanking(unsigned long arg)
+{
+ char *argp = (char *)arg + 1;
+ unsigned int mode;
+ get_user(mode, argp);
+ vesa_blank_mode = (mode < 4) ? mode : 0;
+}
+
+void vesa_blank(void)
+{
+ struct vc_data *c = vc_cons[fg_console].d;
+ c->vc_sw->con_blank(c, vesa_blank_mode + 1);
+}
+
+void vesa_powerdown(void)
+{
+ struct vc_data *c = vc_cons[fg_console].d;
+ /*
+ * Power down if currently suspended (1 or 2),
+ * suspend if currently blanked (0),
+ * else do nothing (i.e. already powered down (3)).
+ * Called only if powerdown features are allowed.
+ */
+ switch (vesa_blank_mode) {
+ case VESA_NO_BLANKING:
+ c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1);
+ break;
+ case VESA_VSYNC_SUSPEND:
+ case VESA_HSYNC_SUSPEND:
+ c->vc_sw->con_blank(c, VESA_POWERDOWN+1);
+ break;
+ }
}
void vesa_powerdown_screen(void)
@@ -2371,11 +2401,29 @@ void vesa_powerdown_screen(void)
void do_blank_screen(int nopowersave)
{
- int currcons;
+ int currcons = fg_console;
+ int i;
if (console_blanked)
return;
+ /* entering graphics mode? */
+ if (nopowersave) {
+ hide_cursor(currcons);
+ save_screen();
+ sw->con_blank(vc_cons[currcons].d, -1);
+ console_blanked = fg_console + 1;
+ set_origin(currcons);
+ return;
+ }
+
+ /* don't blank graphics */
+ if (vt_cons[fg_console]->vc_mode != KD_TEXT) {
+ console_blanked = fg_console + 1;
+ return;
+ }
+
+ hide_cursor(fg_console);
if(vesa_off_interval && !nopowersave) {
timer_table[BLANK_TIMER].fn = vesa_powerdown_screen;
timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval;
@@ -2385,18 +2433,12 @@ void do_blank_screen(int nopowersave)
timer_table[BLANK_TIMER].fn = unblank_screen;
}
- /* try not to lose information by blanking, and not to waste memory */
- currcons = fg_console;
- has_scrolled = 0;
- blank__origin = __origin;
- blank_origin = origin;
- set_origin(fg_console);
- get_scrmem(fg_console);
- unblank_origin = origin;
- memsetw((void *)blank_origin, BLANK,
- 2*video_num_lines*video_num_columns);
- hide_cursor();
+ save_screen();
+ /* In case we need to reset origin, blanking hook returns 1 */
+ i = sw->con_blank(vc_cons[currcons].d, 1);
console_blanked = fg_console + 1;
+ if (i)
+ set_origin(currcons);
if(!nopowersave)
{
@@ -2411,9 +2453,6 @@ void do_blank_screen(int nopowersave)
void do_unblank_screen(void)
{
int currcons;
- int resetorg;
- long offset;
-
if (!console_blanked)
return;
if (!vc_cons_allocated(fg_console)) {
@@ -2428,34 +2467,16 @@ void do_unblank_screen(void)
}
currcons = fg_console;
- offset = 0;
- resetorg = 0;
- if (console_blanked == fg_console + 1 && origin == unblank_origin
- && !has_scrolled) {
- /* try to restore the exact situation before blanking */
- resetorg = 1;
- offset = (blank_origin - video_mem_base)
- - (unblank_origin - video_mem_start);
- }
-
console_blanked = 0;
- set_scrmem(fg_console, offset);
- set_origin(fg_console);
- set_cursor(fg_console);
- if (resetorg)
- __set_origin(blank__origin);
-
- vesa_unblank();
#ifdef CONFIG_APM
- if (apm_display_unblank())
- return;
+ apm_display_unblank();
#endif
+ if (sw->con_blank(vc_cons[currcons].d, 0))
+ /* Low-level driver cannot restore -> do it ourselves */
+ update_screen(fg_console);
+ set_cursor(fg_console);
}
-/*
- * If a blank_screen is due to a timer, then a power save is allowed.
- * If it is related to console_switching, then avoid vesa_blank().
- */
static void blank_screen(void)
{
do_blank_screen(0);
@@ -2466,62 +2487,60 @@ static void unblank_screen(void)
do_unblank_screen();
}
-void update_screen(int new_console)
+void poke_blanked_console(void)
{
- static int lock = 0;
-
- if (new_console == fg_console || lock)
- return;
- if (!vc_cons_allocated(new_console)) {
- /* strange ... */
- printk("update_screen: tty %d not allocated ??\n", new_console+1);
+ timer_active &= ~(1<<BLANK_TIMER);
+ if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
return;
+ if (console_blanked) {
+ timer_table[BLANK_TIMER].fn = unblank_screen;
+ timer_table[BLANK_TIMER].expires = 0;
+ timer_active |= 1<<BLANK_TIMER;
+ } else if (blankinterval) {
+ timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
+ timer_active |= 1<<BLANK_TIMER;
}
- lock = 1;
-
- clear_selection();
-
- if (!console_blanked)
- get_scrmem(fg_console);
- else
- console_blanked = -1; /* no longer of the form console+1 */
- fg_console = new_console; /* this is the only (nonzero) assignment to fg_console */
- /* consequently, fg_console will always be allocated */
- set_scrmem(fg_console, 0);
- set_origin(fg_console);
- set_cursor(fg_console);
- set_leds();
- compute_shiftstate();
- lock = 0;
}
/*
- * Allocate the console screen memory.
+ * Palettes
*/
-static int con_open(struct tty_struct *tty, struct file * filp)
-{
- unsigned int idx;
- int i;
-
- idx = MINOR(tty->device) - tty->driver.minor_start;
- i = vc_allocate(idx);
- if (i)
- return i;
+void set_palette(void)
+{
+ if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS)
+ vc_cons[fg_console].d->vc_sw->con_set_palette(vc_cons[fg_console].d, color_table);
+}
- vt_cons[idx]->vc_num = idx;
- tty->driver_data = vt_cons[idx];
+int set_get_cmap(unsigned char *arg, int set)
+{
+ int i, j, k;
- if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
- tty->winsize.ws_row = video_num_lines;
- tty->winsize.ws_col = video_num_columns;
+ for (i = 0; i < 16; i++)
+ if (set) {
+ get_user(default_red[i], arg++);
+ get_user(default_grn[i], arg++);
+ get_user(default_blu[i], arg++);
+ } else {
+ put_user(default_red[i], arg++);
+ put_user(default_grn[i], arg++);
+ put_user(default_blu[i], arg++);
}
- return 0;
+ if (set) {
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ if (vc_cons_allocated(i))
+ for (j = k = 0; j < 16; j++) {
+ vc_cons[i].d->vc_palette[k++] = default_red[j];
+ vc_cons[i].d->vc_palette[k++] = default_grn[j];
+ vc_cons[i].d->vc_palette[k++] = default_blu[j];
+ }
+ set_palette();
+ }
+ return 0;
}
-
/*
- * Load palette into the EGA/VGA DAC registers. arg points to a colour
+ * Load palette into the DAC registers. arg points to a colour
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
*/
@@ -2547,25 +2566,164 @@ void reset_palette (int currcons)
}
/*
- * Load font into the EGA/VGA character generator. arg points to a 8192
- * byte map, 32 bytes per character. Only first H of them are used for
- * 8xH fonts (0 < H <= 32).
+ * Font switching
+ *
+ * Currently we only support fonts up to 32 pixels wide, at a maximum height
+ * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints,
+ * depending on width) reserved for each character which is kinda wasty, but
+ * this is done in order to maintain compatibility with the EGA/VGA fonts. It
+ * is upto the actual low-level console-driver convert data into its favorite
+ * format (maybe we should add a `fontoffset' field to the `display'
+ * structure so we wont have to convert the fontdata all the time.
+ * /Jes
+ */
+
+#define max_font_size 65536
+
+int con_font_op(int currcons, struct console_font_op *op)
+{
+ int rc = -EINVAL;
+ int size = max_font_size, set;
+ u8 *temp = NULL;
+ struct console_font_op old_op;
+
+ if (vt_cons[currcons]->vc_mode != KD_TEXT)
+ goto quit;
+ memcpy(&old_op, op, sizeof(old_op));
+ if (op->op == KD_FONT_OP_SET) {
+ if (!op->data)
+ return -EINVAL;
+ if (op->charcount > 512)
+ goto quit;
+ if (!op->height) { /* Need to guess font height [compat] */
+ int h, i;
+ u8 *charmap = op->data, tmp;
+
+ /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+ so that we can get rid of this soon */
+ if (!(op->flags & KD_FONT_FLAG_OLD))
+ goto quit;
+ rc = -EFAULT;
+ for (h = 32; h > 0; h--)
+ for (i = 0; i < op->charcount; i++) {
+ if (get_user(tmp, &charmap[32*i+h-1]))
+ goto quit;
+ if (tmp)
+ goto nonzero;
+ }
+ rc = -EINVAL;
+ goto quit;
+ nonzero:
+ rc = -EINVAL;
+ op->height = h;
+ }
+ if (op->width > 32 || op->height > 32)
+ goto quit;
+ size = (op->width+7)/8 * 32 * op->charcount;
+ if (size > max_font_size)
+ return -ENOSPC;
+ set = 1;
+ } else if (op->op == KD_FONT_OP_GET)
+ set = 0;
+ else
+ return sw->con_font_op(vc_cons[currcons].d, op);
+ if (op->data) {
+ temp = kmalloc(size, GFP_KERNEL);
+ if (!temp)
+ return -ENOMEM;
+ if (set && copy_from_user(temp, op->data, size)) {
+ rc = -EFAULT;
+ goto quit;
+ }
+ op->data = temp;
+ }
+ rc = sw->con_font_op(vc_cons[currcons].d, op);
+ op->data = old_op.data;
+ if (!rc && !set) {
+ int c = (op->width+7)/8 * 32 * op->charcount;
+
+ if (op->data && op->charcount > old_op.charcount)
+ rc = -ENOSPC;
+ if (!(op->flags & KD_FONT_FLAG_OLD)) {
+ if (op->width > old_op.width ||
+ op->height > old_op.height)
+ rc = -ENOSPC;
+ } else {
+ if (op->width != 8)
+ rc = -EIO;
+ else if ((old_op.height && op->height > old_op.height) ||
+ op->height > 32)
+ rc = -ENOSPC;
+ }
+ if (!rc && op->data && copy_to_user(op->data, temp, c))
+ rc = -EFAULT;
+ }
+quit: if (temp)
+ kfree_s(temp, size);
+ return rc;
+}
+
+/*
+ * Interface exported to selection and vcs.
*/
-int con_set_font (char *arg, int ch512)
+/* used by selection */
+u16 screen_glyph(int currcons, int offset)
{
- int i;
+ u16 w = scr_readw(screenpos(currcons, offset, 1));
+ u16 c = w & 0xff;
- i = set_get_font (arg,1,ch512);
- if ( !i ) {
- hashtable_contents_valid = 0;
- video_mode_512ch = ch512;
- console_charmask = ch512 ? 0x1ff : 0x0ff;
- }
- return i;
+ if (w & hi_font_mask)
+ c |= 0x100;
+ return c;
+}
+
+/* used by vcs - note the word offset */
+unsigned short *screen_pos(int currcons, int w_offset, int viewed)
+{
+ return screenpos(currcons, 2 * w_offset, viewed);
+}
+
+void getconsxy(int currcons, char *p)
+{
+ p[0] = x;
+ p[1] = y;
}
-int con_get_font (char *arg)
+void putconsxy(int currcons, char *p)
{
- return set_get_font (arg,0,video_mode_512ch);
+ gotoxy(currcons, p[0], p[1]);
+ set_cursor(currcons);
}
+
+u16 vcs_scr_readw(int currcons, u16 *org)
+{
+ if ((unsigned long)org == pos && softcursor_original != -1)
+ return softcursor_original;
+ return scr_readw(org);
+}
+
+void vcs_scr_writew(int currcons, u16 val, u16 *org)
+{
+ scr_writew(val, org);
+ if ((unsigned long)org == pos) {
+ softcursor_original = -1;
+ add_softcursor(currcons);
+ }
+}
+
+
+/*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(color_table);
+EXPORT_SYMBOL(default_red);
+EXPORT_SYMBOL(default_grn);
+EXPORT_SYMBOL(default_blu);
+EXPORT_SYMBOL(video_font_height);
+EXPORT_SYMBOL(video_scan_lines);
+
+#ifndef VT_BUF_VRAM_ONLY
+EXPORT_SYMBOL(take_over_console);
+#endif
diff --git a/drivers/char/console_macros.h b/drivers/char/console_macros.h
new file mode 100644
index 000000000..f10984ed0
--- /dev/null
+++ b/drivers/char/console_macros.h
@@ -0,0 +1,71 @@
+#define cons_num (vc_cons[currcons].d->vc_num)
+#define sw (vc_cons[currcons].d->vc_sw)
+#define screenbuf (vc_cons[currcons].d->vc_screenbuf)
+#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size)
+#define origin (vc_cons[currcons].d->vc_origin)
+#define scr_top (vc_cons[currcons].d->vc_scr_top)
+#define visible_origin (vc_cons[currcons].d->vc_visible_origin)
+#define scr_end (vc_cons[currcons].d->vc_scr_end)
+#define pos (vc_cons[currcons].d->vc_pos)
+#define top (vc_cons[currcons].d->vc_top)
+#define bottom (vc_cons[currcons].d->vc_bottom)
+#define x (vc_cons[currcons].d->vc_x)
+#define y (vc_cons[currcons].d->vc_y)
+#define vc_state (vc_cons[currcons].d->vc_state)
+#define npar (vc_cons[currcons].d->vc_npar)
+#define par (vc_cons[currcons].d->vc_par)
+#define ques (vc_cons[currcons].d->vc_ques)
+#define attr (vc_cons[currcons].d->vc_attr)
+#define saved_x (vc_cons[currcons].d->vc_saved_x)
+#define saved_y (vc_cons[currcons].d->vc_saved_y)
+#define translate (vc_cons[currcons].d->vc_translate)
+#define G0_charset (vc_cons[currcons].d->vc_G0_charset)
+#define G1_charset (vc_cons[currcons].d->vc_G1_charset)
+#define saved_G0 (vc_cons[currcons].d->vc_saved_G0)
+#define saved_G1 (vc_cons[currcons].d->vc_saved_G1)
+#define utf (vc_cons[currcons].d->vc_utf)
+#define utf_count (vc_cons[currcons].d->vc_utf_count)
+#define utf_char (vc_cons[currcons].d->vc_utf_char)
+#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start)
+#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end)
+#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
+#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl)
+#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta)
+#define decscnm (vc_cons[currcons].d->vc_decscnm)
+#define decom (vc_cons[currcons].d->vc_decom)
+#define decawm (vc_cons[currcons].d->vc_decawm)
+#define deccm (vc_cons[currcons].d->vc_deccm)
+#define decim (vc_cons[currcons].d->vc_decim)
+#define deccolm (vc_cons[currcons].d->vc_deccolm)
+#define need_wrap (vc_cons[currcons].d->vc_need_wrap)
+#define kmalloced (vc_cons[currcons].d->vc_kmalloced)
+#define report_mouse (vc_cons[currcons].d->vc_report_mouse)
+#define color (vc_cons[currcons].d->vc_color)
+#define s_color (vc_cons[currcons].d->vc_s_color)
+#define def_color (vc_cons[currcons].d->vc_def_color)
+#define foreground (color & 0x0f)
+#define background (color & 0xf0)
+#define charset (vc_cons[currcons].d->vc_charset)
+#define s_charset (vc_cons[currcons].d->vc_s_charset)
+#define intensity (vc_cons[currcons].d->vc_intensity)
+#define underline (vc_cons[currcons].d->vc_underline)
+#define blink (vc_cons[currcons].d->vc_blink)
+#define reverse (vc_cons[currcons].d->vc_reverse)
+#define s_intensity (vc_cons[currcons].d->vc_s_intensity)
+#define s_underline (vc_cons[currcons].d->vc_s_underline)
+#define s_blink (vc_cons[currcons].d->vc_s_blink)
+#define s_reverse (vc_cons[currcons].d->vc_s_reverse)
+#define ulcolor (vc_cons[currcons].d->vc_ulcolor)
+#define halfcolor (vc_cons[currcons].d->vc_halfcolor)
+#define tab_stop (vc_cons[currcons].d->vc_tab_stop)
+#define palette (vc_cons[currcons].d->vc_palette)
+#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch)
+#define bell_duration (vc_cons[currcons].d->vc_bell_duration)
+#define cursor_type (vc_cons[currcons].d->vc_cursor_type)
+#define display_fg (vc_cons[currcons].d->vc_display_fg)
+#define complement_mask (vc_cons[currcons].d->vc_complement_mask)
+#define hi_font_mask (vc_cons[currcons].d->vc_hi_font_mask)
+
+#define vcmode (vt_cons[currcons]->vc_mode)
+
+#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct))
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 5a9300bf8..e63386d7c 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -5,6 +5,8 @@
* to font positions.
*
* aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
*/
#include <linux/kd.h>
@@ -14,6 +16,8 @@
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/consolemap.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
static unsigned short translations[][256] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
@@ -163,29 +167,36 @@ static unsigned short translations[][256] = {
#define MAX_GLYPH 512 /* Max possible glyph value */
-static unsigned char * inv_translate = NULL;
-static unsigned char inv_norm_transl[MAX_GLYPH];
-static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
+static int inv_translate;
+
+struct uni_pagedir {
+ u16 **uni_pgdir[32];
+ unsigned long refcount;
+ unsigned long sum;
+ unsigned char *inverse_translations[4];
+ int readonly;
+};
-static void set_inverse_transl(int i)
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
{
int j, glyph;
- unsigned short *p = translations[i];
- unsigned char *q = inverse_translations[i];
+ unsigned short *t = translations[i];
+ unsigned char *q;
+
+ if (!p) return;
+ q = p->inverse_translations[i];
if (!q) {
- /* slightly messy to avoid calling kmalloc too early */
- q = inverse_translations[i] = ((i == LAT1_MAP)
- ? inv_norm_transl
- : (unsigned char *) kmalloc(MAX_GLYPH, GFP_KERNEL));
- if (!q)
- return;
+ q = p->inverse_translations[i] = (unsigned char *)
+ kmalloc(MAX_GLYPH, GFP_KERNEL);
+ if (!q) return;
}
- for (j=0; j<MAX_GLYPH; j++)
- q[j] = 0;
+ memset(q, 0, MAX_GLYPH);
- for (j=0; j<E_TABSZ; j++) {
- glyph = conv_uni_to_pc(p[j]);
+ for (j = 0; j < E_TABSZ; j++) {
+ glyph = conv_uni_to_pc(conp, t[j]);
if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
/* prefer '-' above SHY etc. */
q[glyph] = j;
@@ -195,9 +206,7 @@ static void set_inverse_transl(int i)
unsigned short *set_translate(int m)
{
- if (!inverse_translations[m])
- set_inverse_transl(m);
- inv_translate = inverse_translations[m];
+ inv_translate = m;
return translations[m];
}
@@ -208,13 +217,33 @@ unsigned short *set_translate(int m)
* was active, or using Unicode.
* Still, it is now possible to a certain extent to cut and paste non-ASCII.
*/
-unsigned char inverse_translate(int glyph) {
- if ( glyph < 0 || glyph >= MAX_GLYPH )
+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])
+ return glyph;
else
- return ((inv_translate && inv_translate[glyph])
- ? inv_translate[glyph]
- : (unsigned char)(glyph & 0xff));
+ return p->inverse_translations[inv_translate][glyph];
+}
+
+static void update_user_maps(void)
+{
+ int i;
+ struct uni_pagedir *p, *q = NULL;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ if (p && p != q) {
+ set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+ q = p;
+ }
+ }
}
/*
@@ -240,7 +269,7 @@ int con_set_trans_old(unsigned char * arg)
p[i] = UNI_DIRECT_BASE | uc;
}
- set_inverse_transl(USER_MAP);
+ update_user_maps();
return 0;
}
@@ -255,7 +284,7 @@ int con_get_trans_old(unsigned char * arg)
for (i=0; i<E_TABSZ ; i++)
{
- ch = conv_uni_to_pc(p[i]);
+ ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
__put_user((ch & ~0xff) ? 0 : ch, arg+i);
}
return 0;
@@ -277,7 +306,7 @@ int con_set_trans_new(ushort * arg)
p[i] = us;
}
- set_inverse_transl(USER_MAP);
+ update_user_maps();
return 0;
}
@@ -310,90 +339,188 @@ int con_get_trans_new(ushort * arg)
extern u8 dfont_unicount[]; /* Defined in console_defmap.c */
extern u16 dfont_unitable[];
-int hashtable_contents_valid = 0; /* Use ASCII-only mode for bootup */
+static void con_release_unimap(struct uni_pagedir *p)
+{
+ u16 **p1;
+ int i, j;
+
+ if (p == dflt) dflt = NULL;
+ for (i = 0; i < 32; i++) {
+ if ((p1 = p->uni_pgdir[i]) != NULL) {
+ for (j = 0; j < 32; j++)
+ if (p1[j])
+ kfree(p1[j]);
+ kfree(p1);
+ }
+ p->uni_pgdir[i] = NULL;
+ }
+ for (i = 0; i < 4; i++)
+ if (p->inverse_translations[i]) {
+ kfree(p->inverse_translations[i]);
+ p->inverse_translations[i] = NULL;
+ }
+}
-static u16 **uni_pagedir[32] =
+void con_free_unimap(int con)
{
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (!p) return;
+ *conp->vc_uni_pagedir_loc = 0;
+ if (--p->refcount) return;
+ con_release_unimap(p);
+ kfree(p);
+}
+
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+ int i, j, k;
+ struct uni_pagedir *q;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+ if (!q || q == p || q->sum != p->sum)
+ continue;
+ for (j = 0; j < 32; j++) {
+ u16 **p1, **q1;
+ p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+ if (!p1 && !q1)
+ continue;
+ if (!p1 || !q1)
+ break;
+ for (k = 0; k < 32; k++) {
+ if (!p1[k] && !q1[k])
+ continue;
+ if (!p1[k] || !q1[k])
+ break;
+ if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+ break;
+ }
+ if (k < 32)
+ break;
+ }
+ if (j == 32) {
+ q->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ con_release_unimap(p);
+ kfree(p);
+ return 1;
+ }
+ }
+ return 0;
+}
static int
-con_insert_unipair(u_short unicode, u_short fontpos)
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
{
- int i, n;
- u16 **p1, *p2;
-
- if ( !(p1 = uni_pagedir[n = unicode >> 11]) )
- {
- p1 = uni_pagedir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
- if ( !p1 )
- return -ENOMEM;
-
- for ( i = 0 ; i < 32 ; i++ )
- p1[i] = NULL;
- }
-
- if ( !(p2 = p1[n = (unicode >> 6) & 0x1f]) )
- {
- p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
- if ( !p2 )
- return -ENOMEM;
-
- for ( i = 0 ; i < 64 ; i++ )
- p2[i] = 0xffff; /* No glyph for this character (yet) */
- }
-
- p2[unicode & 0x3f] = fontpos;
-
- return 0;
+ int i, n;
+ u16 **p1, *p2;
+
+ if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+ p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+ if (!p1) return -ENOMEM;
+ for (i = 0; i < 32; i++)
+ p1[i] = NULL;
+ }
+
+ if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+ p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+ if (!p2) return -ENOMEM;
+ memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+ }
+
+ p2[unicode & 0x3f] = fontpos;
+
+ p->sum += (fontpos << 20) + unicode;
+
+ return 0;
}
-
+
/* ui is a leftover from using a hashtable, but might be used again */
-void
-con_clear_unimap(struct unimapinit *ui)
+int con_clear_unimap(int con, struct unimapinit *ui)
{
- int i, j;
- u16 **p1;
+ struct uni_pagedir *p, *q;
+ struct vc_data *conp = vc_cons[con].d;
- for ( i = 0 ; i < 32 ; i++ )
- {
- if ( (p1 = uni_pagedir[i]) != NULL )
- {
- for ( j = 0 ; j < 32 ; j++ )
- {
- if ( p1[j] )
- kfree(p1[j]);
- }
- kfree(p1);
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p && p->readonly) return -EIO;
+ if (!p || --p->refcount) {
+ q = (struct uni_pagedir *)kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!q) {
+ if (p) p->refcount++;
+ return -ENOMEM;
+ }
+ memset(q, 0, sizeof(*q));
+ q->refcount=1;
+ *conp->vc_uni_pagedir_loc = (unsigned long)q;
+ } else {
+ if (p == dflt) dflt = NULL;
+ p->refcount++;
+ p->sum = 0;
+ con_release_unimap(p);
}
- uni_pagedir[i] = NULL;
- }
-
- hashtable_contents_valid = 1;
+ return 0;
}
int
-con_set_unimap(ushort ct, struct unipair *list)
+con_set_unimap(int con, ushort ct, struct unipair *list)
{
- int err = 0, err1, i;
-
- while( ct-- )
- {
- unsigned short unicode, fontpos;
- __get_user(unicode, &list->unicode);
- __get_user(fontpos, &list->fontpos);
- if ( (err1 = con_insert_unipair(unicode,fontpos)) != 0 )
- err = err1;
- list++;
- }
-
- for ( i = 0 ; i <= 3 ; i++ )
- set_inverse_transl(i); /* Update all inverse translations */
+ int err = 0, err1, i;
+ struct uni_pagedir *p, *q;
+ struct vc_data *conp = vc_cons[con].d;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p->readonly) return -EIO;
+
+ if (!ct) return 0;
+
+ if (p->refcount > 1) {
+ int j, k;
+ u16 **p1, *p2, l;
+
+ err1 = con_clear_unimap(con, NULL);
+ if (err1) return err1;
+
+ q = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ for (i = 0, l = 0; i < 32; i++)
+ if ((p1 = p->uni_pgdir[i]))
+ for (j = 0; j < 32; j++)
+ if ((p2 = p1[j]))
+ for (k = 0; k < 64; k++, l++)
+ if (p2[k] != 0xffff) {
+ err1 = con_insert_unipair(q, l, p2[k]);
+ if (err1) {
+ p->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)p;
+ con_release_unimap(q);
+ kfree(q);
+ return err1;
+ }
+ }
+ p = q;
+ } else if (p == dflt)
+ dflt = NULL;
+
+ while (ct--) {
+ unsigned short unicode, fontpos;
+ __get_user(unicode, &list->unicode);
+ __get_user(fontpos, &list->fontpos);
+ if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+ err = err1;
+ list++;
+ }
+
+ if (con_unify_unimap(conp, p))
+ return err;
+
+ for (i = 0; i <= 3; i++)
+ set_inverse_transl(conp, p, i); /* Update all inverse translations */
- return err;
+ return err;
}
/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
@@ -401,83 +528,123 @@ con_set_unimap(ushort ct, struct unipair *list)
with. This routine is executed at sys_setup time, and when the
PIO_FONTRESET ioctl is called. */
-void
-con_set_default_unimap(void)
+int
+con_set_default_unimap(int con)
{
- int i, j;
- u16 *p;
-
- /* The default font is always 256 characters */
-
- con_clear_unimap(NULL);
+ int i, j, err = 0, err1;
+ u16 *q;
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
+
+ if (dflt) {
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if (p == dflt)
+ return 0;
+ dflt->refcount++;
+ *conp->vc_uni_pagedir_loc = (unsigned long)dflt;
+ if (p && --p->refcount) {
+ con_release_unimap(p);
+ kfree(p);
+ }
+ return 0;
+ }
+
+ /* The default font is always 256 characters */
- p = dfont_unitable;
- for ( i = 0 ; i < 256 ; i++ )
- for ( j = dfont_unicount[i] ; j ; j-- )
- con_insert_unipair(*(p++), i);
+ err = con_clear_unimap(con,NULL);
+ if (err) return err;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ q = dfont_unitable;
+
+ for (i = 0; i < 256; i++)
+ for (j = dfont_unicount[i]; j; j--) {
+ err1 = con_insert_unipair(p, *(q++), i);
+ if (err1)
+ err = err1;
+ }
+
+ if (con_unify_unimap(conp, p)) {
+ dflt = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ return err;
+ }
- for ( i = 0 ; i <= 3 ; i++ )
- set_inverse_transl(i); /* Update all inverse translations */
+ for (i = 0; i <= 3; i++)
+ set_inverse_transl(conp, p, i); /* Update all inverse translations */
+ dflt = p;
+ return err;
}
int
-con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
+con_get_unimap(int con, ushort ct, ushort *uct, struct unipair *list)
+{
int i, j, k, ect;
u16 **p1, *p2;
+ struct uni_pagedir *p;
+ struct vc_data *conp = vc_cons[con].d;
ect = 0;
- if (hashtable_contents_valid)
- {
- for ( i = 0 ; i < 32 ; i++ )
- if ( (p1 = uni_pagedir[i]) != NULL )
- for ( j = 0 ; j < 32 ; j++ )
- if ( (p2 = *(p1++)) != NULL )
- for ( k = 0 ; k < 64 ; k++ )
- {
- if ( *p2 < MAX_GLYPH && ect++ < ct )
- {
- __put_user((u_short)((i<<11)+(j<<6)+k),
- &list->unicode);
- __put_user((u_short) *p2, &list->fontpos);
- list++;
- }
- p2++;
- }
- }
+ if (*conp->vc_uni_pagedir_loc) {
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ for (i = 0; i < 32; i++)
+ if ((p1 = p->uni_pgdir[i]))
+ for (j = 0; j < 32; j++)
+ if ((p2 = *(p1++)))
+ for (k = 0; k < 64; k++) {
+ if (*p2 < MAX_GLYPH && ect++ < ct) {
+ __put_user((u_short)((i<<11)+(j<<6)+k),
+ &list->unicode);
+ __put_user((u_short) *p2,
+ &list->fontpos);
+ list++;
+ }
+ p2++;
+ }
+ }
__put_user(ect, uct);
return ((ect <= ct) ? 0 : -ENOMEM);
}
+void con_protect_unimap(int con, int rdonly)
+{
+ struct uni_pagedir *p = (struct uni_pagedir *)
+ *vc_cons[con].d->vc_uni_pagedir_loc;
+
+ if (p) p->readonly = rdonly;
+}
+
int
-conv_uni_to_pc(long ucs)
+conv_uni_to_pc(struct vc_data *conp, long ucs)
{
- int h;
- u16 **p1, *p2;
-
- /* Only 16-bit codes supported at this time */
- if (ucs > 0xffff)
- ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
- else if (ucs < 0x20 || ucs >= 0xfffe)
- return -1; /* Not a printable character */
- else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
- return -2; /* Zero-width space */
- /*
- * UNI_DIRECT_BASE indicates the start of the region in the User Zone
- * which always has a 1:1 mapping to the currently loaded font. The
- * UNI_DIRECT_MASK indicates the bit span of the region.
- */
- else if ( (ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE )
- return ucs & UNI_DIRECT_MASK;
+ int h;
+ u16 **p1, *p2;
+ struct uni_pagedir *p;
- if (!hashtable_contents_valid)
- return -3;
+ /* Only 16-bit codes supported at this time */
+ if (ucs > 0xffff)
+ ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
+ else if (ucs < 0x20 || ucs >= 0xfffe)
+ return -1; /* Not a printable character */
+ else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+ return -2; /* Zero-width space */
+ /*
+ * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+ * which always has a 1:1 mapping to the currently loaded font. The
+ * UNI_DIRECT_MASK indicates the bit span of the region.
+ */
+ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+ return ucs & UNI_DIRECT_MASK;
- if ( (p1 = uni_pagedir[ucs >> 11]) &&
- (p2 = p1[(ucs >> 6) & 0x1f]) &&
- (h = p2[ucs & 0x3f]) < MAX_GLYPH )
- return h;
+ if (!*conp->vc_uni_pagedir_loc)
+ return -3;
+
+ p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;
+ if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+ (p2 = p1[(ucs >> 6) & 0x1f]) &&
+ (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+ return h;
- return -4; /* not found */
+ return -4; /* not found */
}
/*
@@ -488,5 +655,9 @@ conv_uni_to_pc(long ucs)
__initfunc(void
console_map_init(void))
{
- con_set_default_unimap();
+ int i;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+ con_set_default_unimap(i);
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 9f51607fe..976219825 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,9 +1,7 @@
#define BLOCKMOVE
-#define NEW_INTR_FLOW
#define Z_WAKE
-#define NEW_PCI
static char rcsid[] =
-"$Revision: 2.2.1.1 $$Date: 1998/03/19 16:43:12 $";
+"$Revision: 2.2.1.5 $$Date: 1998/08/10 18:10:28 $";
/*
* linux/drivers/char/cyclades.c
@@ -33,6 +31,22 @@ static char rcsid[] =
* void cleanup_module(void);
*
* $Log: cyclades.c,v $
+ * Revision 2.2.1.5 1998/08/10 18:10:28 ivan
+ * Fixed Cyclom-4Yo hardware detection bug.
+ *
+ * Revision 2.2.1.4 1998/08/04 11:02:50 ivan
+ * /proc/cyclades implementation with great collaboration of
+ * Marc Lewis <marc@blarg.net>;
+ * cyy_interrupt was changed to avoid occurence of kernel oopses
+ * during PPP operation.
+ *
+ * Revision 2.2.1.3 1998/06/01 12:09:10 ivan
+ * General code review in order to comply with 2.1 kernel standards;
+ * data loss prevention for slow devices revisited (cy_wait_until_sent
+ * was created);
+ * removed conditional compilation for new/old PCI structure support
+ * (now the driver only supports the new PCI structure).
+ *
* Revision 2.2.1.1 1998/03/19 16:43:12 ivan
* added conditional compilation for new/old PCI structure support;
* removed kernel series (2.0.x / 2.1.x) conditional compilation.
@@ -40,7 +54,7 @@ static char rcsid[] =
* Revision 2.1.1.3 1998/03/16 18:01:12 ivan
* cleaned up the data loss fix;
* fixed XON/XOFF handling once more (Cyclades-Z);
- * general revision in the driver routines;
+ * general review of the driver routines;
* introduction of a mechanism to prevent data loss with slow
* printers, by forcing a delay before closing the port.
*
@@ -138,7 +152,7 @@ static char rcsid[] =
* Price <stevep@fa.tdktca.com> for help on this)
*
* Revision 1.36.4.21 1996/09/10 17:00:10 bentson
- * shift from cpu-bound to memcopy in cyz_polling operation
+ * shift from CPU-bound to memcopy in cyz_polling operation
*
* Revision 1.36.4.20 1996/09/09 18:30:32 Bentson
* Added support to set and report higher speeds.
@@ -482,14 +496,15 @@ static char rcsid[] =
#define ZE_V1 2
#define SERIAL_PARANOIA_CHECK
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_OTHER
-#undef SERIAL_DEBUG_IO
-#undef SERIAL_DEBUG_COUNT
-#undef SERIAL_DEBUG_DTR
-#undef CYCLOM_16Y_HACK
-#undef CYCLOM_ENABLE_MONITORING
+#undef CY_DEBUG_OPEN
+#undef CY_DEBUG_THROTTLE
+#undef CY_DEBUG_OTHER
+#undef CY_DEBUG_IO
+#undef CY_DEBUG_COUNT
+#undef CY_DEBUG_DTR
+#undef CY_DEBUG_WAIT_UNTIL_SENT
+#undef CY_16Y_HACK
+#undef CY_ENABLE_MONITORING
#undef CY_PCI_DEBUG
#if 0
@@ -519,40 +534,42 @@ static char rcsid[] =
(cy_readl(&buf_ctrl->tx_bufsize) - 1))
#endif
+/*
+ * Include section
+ */
+#include <linux/config.h>
#include <linux/module.h>
-
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
+#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/serial.h>
-#include <linux/interrupt.h>
+#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/cyclades.h>
-#include <linux/delay.h>
-#include <linux/major.h>
#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/segment.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
#include <asm/bitops.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#ifndef NEW_PCI
-#include <linux/bios32.h>
-#endif
#include <linux/pci.h>
-
#include <linux/version.h>
-#include <asm/uaccess.h>
-#include <linux/init.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif
#define cy_put_user put_user
@@ -569,7 +586,7 @@ static unsigned long cy_get_user(unsigned long *addr)
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
-#define IS_CYC_Z(card) ((card).num_chips == 1)
+#define IS_CYC_Z(card) ((card).num_chips == -1)
#define Z_FPGA_CHECK(card) \
((cy_readl(&((struct RUNTIME_9060 *) \
@@ -585,19 +602,18 @@ static unsigned long cy_get_user(unsigned long *addr)
#define STD_COM_FLAGS (0)
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
+#define JIFFIES_DIFF(n, j) ((n) - (j))
static DECLARE_TASK_QUEUE(tq_cyclades);
static struct tty_driver cy_serial_driver, cy_callout_driver;
+static int serial_refcount;
static volatile int cy_irq_triggered;
static volatile int cy_triggered;
static int cy_wild_int_mask;
static volatile ucchar *intr_base_addr;
-
/* This is the address lookup table. The driver will probe for
Cyclom-Y/ISA boards at all addresses in here. If you want the
driver to probe addresses at a different address, add it to
@@ -632,8 +648,6 @@ static struct cyclades_port cy_port[NR_PORTS];
static int cy_next_channel = 0; /* next minor available */
-static int serial_refcount;
-
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
@@ -641,8 +655,7 @@ static struct termios *serial_termios_locked[NR_PORTS];
/* This is the per-irq data structure,
it maps an irq to the corresponding card */
-static struct cyclades_card *IRQ_cards[16];
-
+static struct cyclades_card *IRQ_cards[NR_IRQS];
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
@@ -654,7 +667,7 @@ static struct cyclades_card *IRQ_cards[16];
* memory if large numbers of serial ports are open. This buffer is
* allocated when the first cy_open occurs.
*/
-static unsigned char *tmp_buf = 0;
+static unsigned char *tmp_buf;
static struct semaphore tmp_buf_sem = MUTEX;
/*
@@ -750,6 +763,10 @@ 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;
@@ -799,41 +816,6 @@ serial_paranoia_check(struct cyclades_port *info,
return 0;
} /* serial_paranoia_check */
-
-/* The following diagnostic routines allow the driver to spew
- information on the screen, even (especially!) during interrupts.
- */
-static void
-SP(char *data){
- unsigned long flags;
- save_flags(flags); cli();
- console_print(data);
- restore_flags(flags);
-}/* SP */
-
-static void
-CP(char data){
- unsigned long flags;
- char scrn[2];
- save_flags(flags); cli();
- scrn[0] = data;
- scrn[1] = '\0';
- console_print(scrn);
- restore_flags(flags);
-}/* CP */
-
-static void CP4(int data)
- { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP4 */
-static void CP8(int data)
- { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */
-#if 0
-static void CP16(int data)
- { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */
-static void CP32(long data)
- { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */
-#endif
-
-
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver
@@ -1125,11 +1107,6 @@ cy_probe(int irq, void *dev_id, struct pt_regs *regs)
if(cy_readb(intr_base_addr+(CySVRR<<index)) != 0) {
save_xir = (u_char) cy_readb(intr_base_addr+(CyTIR<<index));
save_car = cy_readb(intr_base_addr+(CyCAR<<index));
- if ((save_xir & 0x3) != 0){
- SP("channel ");
- CP8(save_xir);
- SP(" requesting unexpected interrupt\n");
- }
cy_writeb((u_long)intr_base_addr+(CyCAR<<index), (save_xir & 0x3));
cy_writeb((u_long)intr_base_addr+(CySRER<<index),
cy_readb(intr_base_addr+(CySRER<<index)) & ~CyTxMpty);
@@ -1244,11 +1221,13 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
TTY_FRAME;
*tty->flip.char_buf_ptr++ =
cy_readb(base_addr+(CyRDSR<<index));
+ info->idle_stats.frame_errs++;
}else if(data & CyPARITY){
*tty->flip.flag_buf_ptr++ =
TTY_PARITY;
*tty->flip.char_buf_ptr++ =
cy_readb(base_addr+(CyRDSR<<index));
+ info->idle_stats.parity_errs++;
}else if(data & CyOVERRUN){
*tty->flip.flag_buf_ptr++ =
TTY_OVERRUN;
@@ -1265,6 +1244,7 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
*tty->flip.char_buf_ptr++ =
cy_readb(base_addr+(CyRDSR<<index));
}
+ info->idle_stats.overruns++;
/* These two conditions may imply */
/* a normal read should be done. */
/* }else if(data & CyTIMEOUT){ */
@@ -1281,18 +1261,21 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
/* there was a software buffer
overrun and nothing could be
done about it!!! */
+ info->idle_stats.overruns++;
}
} else { /* normal character reception */
/* load # chars available from the chip */
char_count = cy_readb(base_addr+(CyRDCR<<index));
-#ifdef CYCLOM_ENABLE_MONITORING
+#ifdef CY_ENABLE_MONITORING
++info->mon.int_count;
info->mon.char_count += char_count;
if (char_count > info->mon.char_max)
info->mon.char_max = char_count;
info->mon.char_last = char_count;
#endif
+ info->idle_stats.recv_bytes += char_count;
+ info->idle_stats.recv_idle = jiffies;
while(char_count--){
if (tty->flip.count >= TTY_FLIPBUF_SIZE){
break;
@@ -1301,7 +1284,7 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip);
data = cy_readb(base_addr+(CyRDSR<<index));
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
*tty->flip.char_buf_ptr++ = data;
-#ifdef CYCLOM_16Y_HACK
+#ifdef CY_16Y_HACK
udelay(10L);
#endif
}
@@ -1387,45 +1370,25 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip);
info->x_break = 0;
}
-#ifdef NEW_INTR_FLOW
- if (!info->xmit_cnt){
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
- goto txdone;
- }
- if (info->xmit_buf == 0){
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- goto txdone;
- }
- if (info->tty->stopped || info->tty->hw_stopped){
- cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- goto txdone;
- }
-#endif
while (char_count-- > 0){
-#ifdef NEW_INTR_FLOW
- if (!info->xmit_cnt){
- goto txdone;
- }
-#else
- if (!info->xmit_cnt){
+ if (!info->xmit_cnt){
cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
- goto txdone;
- }
- if (info->xmit_buf == 0){
+ cy_readb(base_addr+(CySRER<<index)) &
+ ~CyTxMpty);
+ goto txdone;
+ }
+ if (info->xmit_buf == 0){
cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+ cy_readb(base_addr+(CySRER<<index)) &
+ ~CyTxMpty);
goto txdone;
- }
- if (info->tty->stopped || info->tty->hw_stopped){
+ }
+ if (info->tty->stopped || info->tty->hw_stopped){
cy_writeb((u_long)base_addr+(CySRER<<index),
- cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+ cy_readb(base_addr+(CySRER<<index)) &
+ ~CyTxMpty);
+ goto txdone;
}
-#endif
/* Because the Embedded Transmit Commands have
been enabled, we must check to see if the
escape character, NULL, is being sent. If it
@@ -1725,14 +1688,12 @@ cyz_poll(unsigned long arg)
if ((fw_ver > 241 ?
((u_long)param) :
cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) {
- /* SP("Open Wakeup\n"); */
cy_sched_event(info,
Cy_EVENT_OPEN_WAKEUP);
}else if(!((info->flags
& ASYNC_CALLOUT_ACTIVE)
&&(info->flags
& ASYNC_CALLOUT_NOHUP))){
- /* SP("Hangup\n"); */
cy_sched_event(info,
Cy_EVENT_HANGUP);
}
@@ -1744,7 +1705,6 @@ cyz_poll(unsigned long arg)
if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){
/* cy_start isn't used because...
HW flow is handled by the board */
- /* SP("Write Wakeup\n"); */
cy_sched_event(info,
Cy_EVENT_WRITE_WAKEUP);
}
@@ -1752,7 +1712,6 @@ cyz_poll(unsigned long arg)
if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){
/* cy_stop isn't used because
HW flow is handled by the board */
- /* SP("Write stop\n"); */
}
}
}
@@ -1796,17 +1755,18 @@ cyz_poll(unsigned long arg)
info->last_active = jiffies;
info->jiffies[1] = jiffies;
-#ifdef CYCLOM_ENABLE_MONITORING
+#ifdef CY_ENABLE_MONITORING
info->mon.int_count++;
info->mon.char_count += char_count;
if (char_count > info->mon.char_max)
info->mon.char_max = char_count;
info->mon.char_last = char_count;
#endif
+ info->idle_stats.recv_bytes += char_count;
+ info->idle_stats.recv_idle = jiffies;
if( tty == 0){
/* flush received characters */
rx_get = (rx_get + char_count) & (rx_bufsize - 1);
- /* SP("-"); */
info->rflush_count++;
}else{
#ifdef BLOCKMOVE
@@ -1986,7 +1946,7 @@ startup(struct cyclades_port * info)
base_addr = (unsigned char*)
(cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc startup card %d, chip %d, channel %d, base_addr %lx\n",
card, chip, channel, (long)base_addr);/**/
#endif
@@ -2004,7 +1964,7 @@ startup(struct cyclades_port * info)
cy_writeb((ulong)base_addr+(CyMSVR1<<index), CyRTS);
cy_writeb((ulong)base_addr+(CyMSVR2<<index), CyDTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:startup raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -2019,6 +1979,10 @@ startup(struct cyclades_port * info)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
restore_flags(flags);
} else {
struct FIRM_ID *firm_id;
@@ -2040,7 +2004,7 @@ startup(struct cyclades_port * info)
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
card, channel, (long)base_addr);/**/
#endif
@@ -2068,7 +2032,7 @@ startup(struct cyclades_port * info)
if (retval != 0){
printk("cyc:startup(2) retval was %x\n", retval);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:startup raising Z DTR\n");
#endif
@@ -2080,9 +2044,13 @@ startup(struct cyclades_port * info)
}
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
+ info->idle_stats.in_use =
+ info->idle_stats.recv_idle =
+ info->idle_stats.xmit_idle = jiffies;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk(" cyc startup done\n");
#endif
return 0;
@@ -2142,7 +2110,7 @@ shutdown(struct cyclades_port * info)
(cy_card[card].base_addr
+ (cy_chip_offset[chip]<<index));
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc shutdown Y card %d, chip %d, channel %d, base_addr %lx\n",
card, chip, channel, (long)base_addr);
#endif
@@ -2159,7 +2127,7 @@ shutdown(struct cyclades_port * info)
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc shutdown dropping DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -2183,7 +2151,7 @@ shutdown(struct cyclades_port * info)
int retval;
base_addr = (unsigned char*) (cy_card[card].base_addr);
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
card, channel, (long)base_addr);
#endif
@@ -2217,7 +2185,7 @@ shutdown(struct cyclades_port * info)
if (retval != 0){
printk("cyc:shutdown retval (2) was %x\n", retval);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:shutdown dropping Z DTR\n");
#endif
}
@@ -2230,7 +2198,7 @@ shutdown(struct cyclades_port * info)
restore_flags(flags);
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk(" cyc shutdown done\n");
#endif
return;
@@ -2262,11 +2230,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
if (info->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&info->close_wait);
}
- if (info->flags & ASYNC_HUP_NOTIFY){
- return -EAGAIN;
- }else{
- return -ERESTARTSYS;
- }
+ return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
}
/*
@@ -2313,7 +2277,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/
retval = 0;
add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
@@ -2321,7 +2285,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
if (!tty_hung_up_p(filp))
info->count--;
restore_flags(flags);
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc block_til_ready: (%d): decrementing count to %d\n",
current->pid, info->count);
#endif
@@ -2338,11 +2302,12 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
while (1) {
save_flags(flags); cli();
- if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD)){
cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:block_til_ready raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -2353,11 +2318,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
- if (info->flags & ASYNC_HUP_NOTIFY) {
- retval = -EAGAIN;
- }else{
- retval = -ERESTARTSYS;
- }
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
break;
}
save_flags(flags); cli();
@@ -2374,7 +2336,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
retval = -ERESTARTSYS;
break;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
@@ -2408,18 +2370,15 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
if (retval != 0){
printk("cyc:block_til_ready retval was %x\n", retval);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:block_til_ready raising Z DTR\n");
#endif
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp)
|| !(info->flags & ASYNC_INITIALIZED) ){
- if (info->flags & ASYNC_HUP_NOTIFY) {
- retval = -EAGAIN;
- }else{
- retval = -ERESTARTSYS;
- }
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
break;
}
if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
@@ -2432,7 +2391,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
retval = -ERESTARTSYS;
break;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc block_til_ready blocking: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
@@ -2443,13 +2402,13 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp)){
info->count++;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:block_til_ready (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
}
info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
@@ -2464,11 +2423,12 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
* This routine is called whenever a serial port is opened. It
* performs the serial-specific initialization for the tty structure.
*/
-int
+static int
cy_open(struct tty_struct *tty, struct file * filp)
{
struct cyclades_port *info;
int retval, line;
+ unsigned long page;
line = MINOR(tty->device) - tty->driver.minor_start;
if ((line < 0) || (NR_PORTS <= line)){
@@ -2491,46 +2451,50 @@ cy_open(struct tty_struct *tty, struct file * filp)
(ZFIRM_HLT==cy_readl(&((struct FIRM_ID *)
((cy_card[info->card]).base_addr+ID_ADDRESS))->signature)))
{
- printk ("Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
+ printk ("cyc:Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n");
} else {
- printk("Cyclades-Z firmware not yet loaded\n");
+ printk("cyc:Cyclades-Z firmware not yet loaded\n");
}
return -ENODEV;
}
}
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_open ttyC%d\n", info->line); /* */
#endif
if (serial_paranoia_check(info, tty->device, "cy_open")){
return -ENODEV;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:cy_open ttyC%d, count = %d\n",
info->line, info->count);/**/
#endif
info->count++;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cy_open (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
tty->driver_data = info;
info->tty = tty;
- /* Some drivers have (incorrect/incomplete) code to test
- against a race condition. Should add good code here!!! */
if (!tmp_buf) {
- tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
- if (!tmp_buf){
- return -ENOMEM;
- }
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
}
- if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
- if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
- *tty->termios = info->normal_termios;
- else
- *tty->termios = info->callout_termios;
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
}
+
/*
* Start up serial port
*/
@@ -2543,17 +2507,24 @@ cy_open(struct tty_struct *tty, struct file * filp)
retval = block_til_ready(tty, filp, info);
if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:cy_open returning after block_til_ready with %d\n",
retval);
#endif
return retval;
}
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ }
+
info->session = current->session;
info->pgrp = current->pgrp;
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk(" cyc:cy_open done\n");/**/
#endif
@@ -2562,6 +2533,76 @@ cy_open(struct tty_struct *tty, struct file * filp)
/*
+ * cy_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
+ unsigned char *base_addr;
+ int card,chip,channel,index;
+ unsigned long orig_jiffies, char_time;
+
+ if (serial_paranoia_check(info, tty->device, "cy_wait_until_sent"))
+ return;
+
+ orig_jiffies = jiffies;
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout < 0)
+ timeout = 0;
+ if (timeout)
+ char_time = MIN(char_time, timeout);
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+ printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk("jiff=%lu...", jiffies);
+#endif
+ card = info->card;
+ channel = (info->line) - (cy_card[card].first_line);
+ if (!IS_CYC_Z(cy_card[card])) {
+ chip = channel>>2;
+ channel &= 0x03;
+ index = cy_card[card].bus_index;
+ base_addr = (unsigned char *)
+ (cy_card[card].base_addr + (cy_chip_offset[chip]<<index));
+ while (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+ printk("Not clean (jiff=%lu)...", jiffies);
+#endif
+ current->state = TASK_INTERRUPTIBLE;
+ current->counter = 0; /* make us low-priority */
+ current->timeout = jiffies + char_time;
+ schedule();
+ if (signal_pending(current))
+ break;
+ if (timeout && ((orig_jiffies + timeout) < jiffies))
+ break;
+ }
+ current->state = TASK_RUNNING;
+ } else {
+ // Nothing to do!
+ }
+ /* Run one more char cycle */
+ current->state = TASK_INTERRUPTIBLE;
+ current->counter = 0; /* make us low-priority */
+ current->timeout = jiffies + (char_time * 5);
+ schedule();
+ current->state = TASK_RUNNING;
+#ifdef CY_DEBUG_WAIT_UNTIL_SENT
+ printk("Clean (jiff=%lu)...done\n", jiffies);
+#endif
+}
+
+/*
* This routine is called when a particular tty device is closed.
*/
static void
@@ -2570,7 +2611,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_close ttyC%d\n", info->line);
#endif
@@ -2578,7 +2619,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
|| serial_paranoia_check(info, tty->device, "cy_close")){
return;
}
-#ifdef SERIAL_DEBUG_OPEN
+#ifdef CY_DEBUG_OPEN
printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
#endif
@@ -2586,6 +2627,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
/* If the TTY is being hung up, nothing to do */
if (tty_hung_up_p(filp)) {
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
@@ -2602,18 +2644,18 @@ cy_close(struct tty_struct * tty, struct file * filp)
"info->count is %d\n", info->count);
info->count = 1;
}
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cy_close at (%d): decrementing count to %d\n",
current->pid, info->count - 1);
#endif
if (--info->count < 0) {
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cyc_close setting count to 0\n");
#endif
info->count = 0;
}
if (info->count) {
- MOD_DEC_USE_COUNT;
+ MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
@@ -2632,28 +2674,25 @@ cy_close(struct tty_struct * tty, struct file * filp)
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- if (info->closing_wait2 != 0) { /* The port's being forced to wait,
- independent on the port settings */
- tty_wait_until_sent(tty, info->closing_wait2*HZ);
- } else {
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait*HZ);
+ if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
+ tty_wait_until_sent(tty, info->closing_wait);
}
- /* Waiting for on-board buffers to be empty before closing the port */
if (!IS_CYC_Z(cy_card[info->card])) {
-#ifdef NEW_INTR_FLOW
unsigned char *base_addr = (unsigned char *)
cy_card[info->card].base_addr;
int index = cy_card[info->card].bus_index;
-
- if (cy_readb(base_addr+(CySRER<<index)) & CyTxMpty) {
- /* Interrupts are enabled, so go to sleep */
- interruptible_sleep_on(&info->shutdown_wait);
+ /* Stop accepting input */
+ cy_writeb((u_long)base_addr+(CySRER<<index),
+ cy_readb(base_addr+(CySRER<<index)) & ~CyRxData);
+ if (info->flags & ASYNC_INITIALIZED) {
+ /* Waiting for on-board buffers to be empty before closing
+ the port */
+ cy_wait_until_sent(tty, info->timeout);
}
-#endif
} else {
#ifdef Z_WAKE
+ /* Waiting for on-board buffers to be empty before closing the port */
unsigned char *base_addr = (unsigned char *)
cy_card[info->card].base_addr;
struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
@@ -2693,7 +2732,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk(" cyc:cy_close done\n");
#endif
@@ -2722,9 +2761,9 @@ cy_write(struct tty_struct * tty, int from_user,
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
- int c, total = 0;
+ int c, ret = 0;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_write ttyC%d\n", info->line); /* */
#endif
@@ -2736,42 +2775,61 @@ cy_write(struct tty_struct * tty, int from_user,
return 0;
}
- if (from_user)
- down(&tmp_buf_sem);
save_flags(flags);
- while (1) {
- cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
- if (from_user) {
- copy_from_user(tmp_buf, buf, c);
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- } else
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
-#if 0
- SP("CW");
- CP16(c);
- SP(" ");
-#endif
- }
- if (from_user)
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret) {
+ ret = -EFAULT;
+ }
+ break;
+ }
+ cli();
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ }
+
+ info->idle_stats.xmit_bytes += ret;
+ info->idle_stats.xmit_idle = jiffies;
+
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
start_xmit(info);
}
- restore_flags(flags);
- return total;
+ return ret;
} /* cy_write */
@@ -2788,7 +2846,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_put_char ttyC%d\n", info->line);
#endif
@@ -2807,10 +2865,9 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
info->xmit_cnt++;
+ info->idle_stats.xmit_bytes++;
+ info->idle_stats.xmit_idle = jiffies;
restore_flags(flags);
-#if 0
- SP("+");
-#endif
} /* cy_put_char */
@@ -2826,7 +2883,7 @@ cy_flush_chars(struct tty_struct *tty)
unsigned char *base_addr;
int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
#endif
@@ -2871,7 +2928,7 @@ cy_write_room(struct tty_struct *tty)
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
int ret;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
#endif
@@ -2897,7 +2954,7 @@ cy_chars_in_buffer(struct tty_struct *tty)
channel = (info->line) - (cy_card[card].first_line);
if (!IS_CYC_Z(cy_card[card])) {
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
info->line, info->xmit_cnt); /* */
#endif
@@ -2923,7 +2980,7 @@ cy_chars_in_buffer(struct tty_struct *tty)
char_count = tx_put - tx_get;
else
char_count = tx_put - tx_get + tx_bufsize;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_chars_in_buffer ttyC%d %d\n",
info->line, info->xmit_cnt + char_count); /* */
#endif
@@ -2951,6 +3008,7 @@ set_line_char(struct cyclades_port * info)
int card,chip,channel,index;
unsigned cflag, iflag;
unsigned short chip_number;
+ int baud;
int i;
@@ -2972,47 +3030,21 @@ set_line_char(struct cyclades_port * info)
index = cy_card[card].bus_index;
/* baud rate */
- i = cflag & CBAUD;
-
- if (i & CBAUDEX) {
- if (i == B57600)
- i = 16;
-#ifdef B76800
- else if(i == B76800)
- i = 17;
-#endif
- else if(i == B115200)
- i = 18;
- else if(i == B230400 && (info->chip_rev >= CD1400_REV_J)) {
- /* It is a CD1400 rev. J or later */
- i = 20;
+ baud = tty_get_baud_rate(info->tty);
+ if (baud > CD1400_MAX_SPEED) {
+ baud = CD1400_MAX_SPEED;
+ }
+ /* find the baud index */
+ for (i = 0; i < 20; i++) {
+ if (baud == baud_table[i]) {
+ break;
}
- else
- info->tty->termios->c_cflag &= ~CBAUDEX;
}
+ if (i == 20) {
+ i = 19; /* CD1400_MAX_SPEED */
+ }
+
- if (i == 15) {
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- i += 1;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- i += 3;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
- switch(info->baud) {
- case 57600:
- i += 1; break;
-#ifdef B76800
- case 76800:
- i += 2; break;
-#endif
- case 115200:
- i += 3; break;
- case 230400:
- i += 5; break;
- default:
- break;
- }
- }
- }
if(info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[i]; /* Tx BPR */
@@ -3026,7 +3058,7 @@ set_line_char(struct cyclades_port * info)
info->rco = baud_co_25[i]; /* Rx CO */
}
if (baud_table[i] == 134) {
- info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
+ info->timeout = (info->xmit_fifo_size*HZ*15/269) + 2;
/* get it right for 134.5 baud */
} else if (baud_table[i]) {
info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2;
@@ -3168,7 +3200,7 @@ set_line_char(struct cyclades_port * info)
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char dropping DTR\n");
printk(" status: 0x%x,
0x%x\n", cy_readb(base_addr+(CyMSVR1<<index)),
@@ -3180,7 +3212,7 @@ set_line_char(struct cyclades_port * info)
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -3214,49 +3246,17 @@ set_line_char(struct cyclades_port * info)
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
/* baud rate */
- switch(i = cflag & CBAUD){
- /*
- case B0: cy_writel(&ch_ctrl->comm_baud , 0); break;
- */
- case B50: cy_writel(&ch_ctrl->comm_baud , 50); break;
- case B75: cy_writel(&ch_ctrl->comm_baud , 75); break;
- case B110: cy_writel(&ch_ctrl->comm_baud , 110); break;
- case B134: cy_writel(&ch_ctrl->comm_baud , 134); break;
- case B150: cy_writel(&ch_ctrl->comm_baud , 150); break;
- case B200: cy_writel(&ch_ctrl->comm_baud , 200); break;
- case B300: cy_writel(&ch_ctrl->comm_baud , 300); break;
- case B600: cy_writel(&ch_ctrl->comm_baud , 600); break;
- case B1200: cy_writel(&ch_ctrl->comm_baud , 1200); break;
- case B1800: cy_writel(&ch_ctrl->comm_baud , 1800); break;
- case B2400: cy_writel(&ch_ctrl->comm_baud , 2400); break;
- case B4800: cy_writel(&ch_ctrl->comm_baud , 4800); break;
- case B9600: cy_writel(&ch_ctrl->comm_baud , 9600); break;
- case B19200: cy_writel(&ch_ctrl->comm_baud , 19200); break;
- case B38400:
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){
- cy_writel(&ch_ctrl->comm_baud , 57600);
- }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){
- cy_writel(&ch_ctrl->comm_baud , 115200);
- }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){
- cy_writel(&ch_ctrl->comm_baud , info->baud);
- }else{
- cy_writel(&ch_ctrl->comm_baud , 38400);
- }
- break;
- case B57600: cy_writel(&ch_ctrl->comm_baud , 57600); break;
-#ifdef B76800
- case B76800: cy_writel(&ch_ctrl->comm_baud , 76800); break;
-#endif
- case B115200: cy_writel(&ch_ctrl->comm_baud , 115200); break;
- case B230400: cy_writel(&ch_ctrl->comm_baud , 230400); break;
- case B460800: cy_writel(&ch_ctrl->comm_baud , 460800); break;
+ baud = tty_get_baud_rate(info->tty);
+ if (baud > CD1400_MAX_SPEED) {
+ baud = CD1400_MAX_SPEED;
}
+ cy_writel(&ch_ctrl->comm_baud , baud);
- if ((i = cy_readl(&ch_ctrl->comm_baud)) == 134) {
+ if (baud == 134) {
info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2;
/* get it right for 134.5 baud */
- } else if (i) {
- info->timeout = (info->xmit_fifo_size*HZ*15/i) + 2;
+ } else if (baud) {
+ info->timeout = (info->xmit_fifo_size*HZ*15/baud) + 2;
/* this needs to be propagated into the card info */
} else {
info->timeout = 0;
@@ -3318,16 +3318,16 @@ set_line_char(struct cyclades_port * info)
cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX);
}
- if(i == 0){ /* baud rate is zero, turn off line */
+ if(baud == 0){ /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char dropping Z DTR\n");
#endif
}else{
cy_writel(&ch_ctrl->rs_control,
cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_line_char raising Z DTR\n");
#endif
}
@@ -3343,6 +3343,21 @@ set_line_char(struct cyclades_port * info)
}
}
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ }
+
+
} /* set_line_char */
@@ -3377,12 +3392,11 @@ set_serial_info(struct cyclades_port * info,
struct serial_struct new_serial;
struct cyclades_port old_info;
- if (!new_info)
- return -EFAULT;
- copy_from_user(&new_serial,new_info,sizeof(new_serial));
+ if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ return -EFAULT;
old_info = *info;
- if (!suser()) {
+ if (!capable(CAP_SYS_ADMIN)) {
if ((new_serial.close_delay != info->close_delay) ||
(new_serial.baud_base != info->baud) ||
((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) !=
@@ -3405,7 +3419,6 @@ set_serial_info(struct cyclades_port * info,
(new_serial.flags & ASYNC_FLAGS));
info->close_delay = new_serial.close_delay * HZ/100;
info->closing_wait = new_serial.closing_wait * HZ/100;
-
check_and_exit:
if (info->flags & ASYNC_INITIALIZED){
@@ -3462,7 +3475,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
} else {
base_addr = (unsigned char*) (cy_card[card].base_addr);
- if (cy_card[card].num_chips != 1){
+ if (cy_card[card].num_chips != -1){
return -EINVAL;
}
@@ -3486,8 +3499,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value)
}
}
- cy_put_user(result,(unsigned long *) value);
- return 0;
+ return cy_put_user(result,(unsigned long *) value);
} /* get_modem_info */
@@ -3535,7 +3547,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -3564,7 +3576,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info dropping DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -3601,7 +3613,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
} else {
cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -3617,7 +3629,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
}
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info dropping DTR\n");
printk(" status: 0x%x, 0x%x\n",
cy_readb(base_addr+(CyMSVR1<<index)),
@@ -3649,7 +3661,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
if (arg & TIOCM_DTR){
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising Z DTR\n");
#endif
}
@@ -3662,7 +3674,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
if (arg & TIOCM_DTR){
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info clearing Z DTR\n");
#endif
}
@@ -3678,13 +3690,13 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
if (arg & TIOCM_DTR){
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info raising Z DTR\n");
#endif
}else{
cy_writel(&ch_ctrl[channel].rs_control,
cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
-#ifdef SERIAL_DEBUG_DTR
+#ifdef CY_DEBUG_DTR
printk("cyc:set_modem_info clearing Z DTR\n");
#endif
}
@@ -3705,7 +3717,6 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd,
return 0;
} /* set_modem_info */
-
static void
send_break( struct cyclades_port * info, int duration)
{
@@ -3737,7 +3748,6 @@ int retval;
}
} /* send_break */
-
static int
get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
{
@@ -3796,11 +3806,11 @@ get_threshold(struct cyclades_port * info, unsigned long *value)
+ (cy_chip_offset[chip]<<index));
tmp = cy_readb(base_addr+(CyCOR3<<index)) & CyREC_FIFO;
- cy_put_user(tmp,value);
+ return cy_put_user(tmp,value);
} else {
// Nothing to do!
+ return 0;
}
- return 0;
}/* get_threshold */
@@ -3815,8 +3825,7 @@ set_default_threshold(struct cyclades_port * info, unsigned long value)
static int
get_default_threshold(struct cyclades_port * info, unsigned long *value)
{
- cy_put_user(info->default_threshold,value);
- return 0;
+ return cy_put_user(info->default_threshold,value);
}/* get_default_threshold */
@@ -3862,11 +3871,11 @@ get_timeout(struct cyclades_port * info, unsigned long *value)
+ (cy_chip_offset[chip]<<index));
tmp = cy_readb(base_addr+(CyRTPR<<index));
- cy_put_user(tmp,value);
+ return cy_put_user(tmp,value);
} else {
// Nothing to do!
+ return 0;
}
- return 0;
}/* get_timeout */
@@ -3881,8 +3890,7 @@ set_default_timeout(struct cyclades_port * info, unsigned long value)
static int
get_default_timeout(struct cyclades_port * info, unsigned long *value)
{
- cy_put_user(info->default_timeout,value);
- return 0;
+ return cy_put_user(info->default_timeout,value);
}/* get_default_timeout */
/*
@@ -3894,68 +3902,40 @@ static int
cy_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
int ret_val = 0;
-#ifdef SERIAL_DEBUG_OTHER
+ if (serial_paranoia_check(info, tty->device, "cy_ioctl"))
+ return -ENODEV;
+
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
info->line, cmd, arg); /* */
#endif
switch (cmd) {
case CYGETMON:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(struct cyclades_monitor));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
break;
case CYGETTHRESH:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_threshold(info, (unsigned long *)arg);
break;
case CYSETTHRESH:
ret_val = set_threshold(info, (unsigned long)arg);
break;
case CYGETDEFTHRESH:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_default_threshold(info, (unsigned long *)arg);
break;
case CYSETDEFTHRESH:
ret_val = set_default_threshold(info, (unsigned long)arg);
break;
case CYGETTIMEOUT:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_timeout(info, (unsigned long *)arg);
break;
case CYSETTIMEOUT:
ret_val = set_timeout(info, (unsigned long)arg);
break;
case CYGETDEFTIMEOUT:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned long));
- if (error){
- ret_val = error;
- break;
- }
ret_val = get_default_timeout(info, (unsigned long *)arg);
break;
case CYSETDEFTIMEOUT:
@@ -3976,109 +3956,63 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
ret_val = info->rtsdtr_inv;
break;
case CYGETCARDINFO:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(struct cyclades_card));
- if (error){
- ret_val = error;
- break;
- }
- copy_to_user((void *)arg, (void *)&cy_card[info->card],
- sizeof (struct cyclades_card));
+ if (copy_to_user((void *)arg, (void *)&cy_card[info->card],
+ sizeof (struct cyclades_card))) {
+ ret_val = -EFAULT;
+ }
ret_val = 0;
break;
case CYGETCD1400VER:
ret_val = info->chip_rev;
break;
- case CYZPOLLCYCLE:
- cyz_polling_cycle = (HZ * arg) / 1000;
+ case CYZSETPOLLCYCLE:
+ cyz_polling_cycle = (arg * HZ) / 1000;
ret_val = 0;
break;
+ case CYZGETPOLLCYCLE:
+ ret_val = (cyz_polling_cycle * 1000) / HZ;
+ break;
case CYSETWAIT:
- info->closing_wait2 = (unsigned short)arg;
+ info->closing_wait = (unsigned short)arg * HZ/100;
ret_val = 0;
break;
case CYGETWAIT:
- ret_val = info->closing_wait2;
+ ret_val = info->closing_wait / (HZ/100);
break;
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
- tty_wait_until_sent(tty,0);
- if (!arg)
- send_break(info, HZ/4); /* 1/4 second */
- break;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- ret_val = tty_check_change(tty);
- if (ret_val)
- return ret_val;
- tty_wait_until_sent(tty,0);
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
+ tty_wait_until_sent(tty,0);
+ if (!arg)
+ send_break(info, HZ/4); /* 1/4 second */
+ break;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ ret_val = tty_check_change(tty);
+ if (ret_val)
+ return ret_val;
+ tty_wait_until_sent(tty,0);
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ break;
+ case TIOCMGET:
+ ret_val = get_modem_info(info, (unsigned int *) arg);
break;
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
ret_val = set_modem_info(info, cmd, (unsigned int *) arg);
break;
-
-/* The following commands are incompletely implemented!!! */
- case TIOCGSOFTCAR:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned int *));
- if (error){
- ret_val = error;
- break;
- }
- cy_put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- break;
- case TIOCSSOFTCAR:
- error = verify_area(VERIFY_READ, (void *) arg
- ,sizeof(unsigned long *));
- if (error) {
- ret_val = error;
- break;
- }
-
- arg = cy_get_user((unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- break;
- case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(unsigned int *));
- if (error){
- ret_val = error;
- break;
- }
- ret_val = get_modem_info(info, (unsigned int *) arg);
- break;
case TIOCGSERIAL:
- error = verify_area(VERIFY_WRITE, (void *) arg
- ,sizeof(struct serial_struct));
- if (error){
- ret_val = error;
- break;
- }
- ret_val = get_serial_info(info,
- (struct serial_struct *) arg);
+ ret_val = get_serial_info(info, (struct serial_struct *) arg);
break;
case TIOCSSERIAL:
- error = verify_area(VERIFY_READ, (void *) arg
- ,sizeof(struct serial_struct));
- if (error){
- ret_val = error;
- break;
- }
- ret_val = set_serial_info(info,
- (struct serial_struct *) arg);
+ ret_val = set_serial_info(info, (struct serial_struct *) arg);
break;
default:
ret_val = -ENOIOCTLCMD;
}
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk(" cyc:cy_ioctl done\n");
#endif
@@ -4097,7 +4031,7 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_set_termios ttyC%d\n", info->line);
#endif
@@ -4141,7 +4075,7 @@ cy_throttle(struct tty_struct * tty)
unsigned char *base_addr;
int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_THROTTLE
+#ifdef CY_DEBUG_THROTTLE
char buf[64];
printk("cyc:throttle %s: %d....ttyC%d\n",
@@ -4197,7 +4131,7 @@ cy_unthrottle(struct tty_struct * tty)
unsigned char *base_addr;
int card,chip,channel,index;
-#ifdef SERIAL_DEBUG_THROTTLE
+#ifdef CY_DEBUG_THROTTLE
char buf[64];
printk("cyc:unthrottle %s: %d....ttyC%d\n",
@@ -4255,7 +4189,7 @@ cy_stop(struct tty_struct *tty)
int chip,channel,index;
unsigned long flags;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_stop ttyC%d\n", info->line); /* */
#endif
@@ -4295,7 +4229,7 @@ cy_start(struct tty_struct *tty)
int chip,channel,index;
unsigned long flags;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_start ttyC%d\n", info->line); /* */
#endif
@@ -4333,7 +4267,7 @@ cy_flush_buffer(struct tty_struct *tty)
int card, channel;
unsigned long flags;
-#ifdef SERIAL_DEBUG_IO
+#ifdef CY_DEBUG_IO
printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
#endif
@@ -4377,7 +4311,7 @@ cy_hangup(struct tty_struct *tty)
{
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
-#ifdef SERIAL_DEBUG_OTHER
+#ifdef CY_DEBUG_OTHER
printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
#endif
@@ -4388,7 +4322,7 @@ cy_hangup(struct tty_struct *tty)
shutdown(info);
info->event = 0;
info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
#endif
info->tty = 0;
@@ -4422,7 +4356,7 @@ cyy_init_card(volatile ucchar *true_base_addr,int index))
for(chip_number=0; chip_number<CyMAX_CHIPS_PER_CARD; chip_number++){
base_addr = true_base_addr
+ (cy_chip_offset[chip_number]<<index);
- udelay(1000L);
+ mdelay(1);
if(cy_readb(base_addr+(CyCCR<<index)) != 0x00){
/*************
printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
@@ -4448,7 +4382,7 @@ cyy_init_card(volatile ucchar *true_base_addr,int index))
}
cy_writeb((u_long)base_addr+(CyCCR<<index), CyCHIP_RESET);
- udelay(1000L);
+ mdelay(1);
if(cy_readb(base_addr+(CyGFRCR<<index)) == 0x00){
/*
@@ -4593,88 +4527,45 @@ cy_detect_pci(void))
{
#ifdef CONFIG_PCI
-#ifdef NEW_PCI
struct pci_dev *pdev = NULL;
unsigned char cyy_rev_id;
-#else
- unsigned char cyy_bus, cyy_dev_fn, cyy_rev_id;
-#endif
unsigned long pci_intr_ctrl;
- unsigned char cy_pci_irq;
+ unsigned char cy_pci_irq = 0;
uclong cy_pci_addr0, cy_pci_addr1, cy_pci_addr2;
unsigned short i,j,cy_pci_nchan;
unsigned short device_id,dev_index = 0;
-#ifndef NEW_PCI
- unsigned short board_index = 0;
-#endif
uclong mailbox;
uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
-#ifdef NEW_PCI
if(pci_present() == 0) { /* PCI bus not present */
-#else
- if(pcibios_present() == 0) { /* PCI bus not present */
-#endif
return(0);
}
for (i = 0; i < NR_CARDS; i++) {
/* look for a Cyclades card by vendor and device id */
while((device_id = cy_pci_dev_id[dev_index]) != 0) {
-#ifdef NEW_PCI
if((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES,
device_id, pdev)) == NULL) {
dev_index++; /* try next device id */
} else {
break; /* found a board */
}
-#else
- if(pcibios_find_device(PCI_VENDOR_ID_CYCLADES,
- device_id,board_index,
- &cyy_bus, &cyy_dev_fn) != 0) {
- dev_index++; /* try next device id */
- board_index = 0;
- } else {
- board_index++;
- break; /* found a board */
- }
-#endif
}
if (device_id == 0)
break;
/* read PCI configuration area */
-#ifdef NEW_PCI
cy_pci_irq = pdev->irq;
cy_pci_addr0 = pdev->base_address[0];
cy_pci_addr1 = pdev->base_address[1];
cy_pci_addr2 = pdev->base_address[2];
pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
-#else
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_INTERRUPT_LINE, &cy_pci_irq);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_0,
- (unsigned int *) &cy_pci_addr0);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_1,
- (unsigned int *) &cy_pci_addr1);
- pcibios_read_config_dword(cyy_bus, cyy_dev_fn,
- PCI_BASE_ADDRESS_2,
- (unsigned int *) &cy_pci_addr2);
- pcibios_read_config_byte(cyy_bus, cyy_dev_fn,
- PCI_REVISION_ID, &cyy_rev_id);
-#endif
if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo)
|| (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){
#ifdef CY_PCI_DEBUG
printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n",
@@ -4686,11 +4577,7 @@ cy_detect_pci(void))
#if defined(__alpha__)
if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n",
@@ -4775,11 +4662,7 @@ cy_detect_pci(void))
}else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){
/* print message */
printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
@@ -4789,11 +4672,7 @@ cy_detect_pci(void))
}else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){
#ifdef CY_PCI_DEBUG
printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
-#ifdef NEW_PCI
pdev->bus->number, pdev->devfn);
-#else
- cyy_bus, cyy_dev_fn);
-#endif
printk("rev_id=%d) IRQ%d\n",
cyy_rev_id, (int)cy_pci_irq);
printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n",
@@ -4908,7 +4787,7 @@ cy_detect_pci(void))
cy_card[j].irq = (int) cy_pci_irq;
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = 1;
+ cy_card[j].num_chips = -1;
IRQ_cards[cy_pci_irq] = &cy_card[j];
/* print message */
@@ -4991,7 +4870,7 @@ cy_detect_pci(void))
cy_card[j].irq = (int) cy_pci_irq;
cy_card[j].bus_index = 1;
cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = 1;
+ cy_card[j].num_chips = -1;
IRQ_cards[cy_pci_irq] = &cy_card[j];
/* print message */
@@ -5041,6 +4920,65 @@ 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)
+{
+ struct cyclades_port *info;
+ int i;
+ int len=0;
+ off_t begin=0;
+ off_t pos=0;
+ int size;
+ __u32 cur_jifs = jiffies;
+
+ size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn IdleIn Overruns Ldisc\n");
+
+ pos += size;
+ len += size;
+
+ /* Output one line for each known port */
+ for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
+ info = &cy_port[i];
+
+ if (info->count)
+ size = sprintf(buf+len,
+ "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6d\n",
+ info->line,
+ JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ,
+ info->idle_stats.xmit_bytes,
+ JIFFIES_DIFF(info->idle_stats.xmit_idle, cur_jifs) / HZ,
+ info->idle_stats.recv_bytes,
+ JIFFIES_DIFF(info->idle_stats.recv_idle, cur_jifs) / HZ,
+ info->idle_stats.overruns,
+ (long) info->tty->ldisc.num);
+ else
+ size = sprintf(buf+len,
+ "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n",
+ info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto done;
+ }
+ *eof = 1;
+done:
+ *start = buf + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ if (len < 0)
+ len = 0;
+ return len;
+}
+#endif
+
/* The serial driver boot-time initialization code!
Hardware I/O ports are mapped to character special devices on a
@@ -5070,6 +5008,7 @@ cy_init(void))
unsigned long mailbox;
unsigned short chip_number;
int nports;
+ struct proc_dir_entry *ent;
show_version();
@@ -5077,6 +5016,7 @@ cy_init(void))
memset(&cy_serial_driver, 0, sizeof(struct tty_driver));
cy_serial_driver.magic = TTY_DRIVER_MAGIC;
+ cy_serial_driver.name = "cyclades";
cy_serial_driver.name = "ttyC";
cy_serial_driver.major = CYCLADES_MAJOR;
cy_serial_driver.minor_start = 0;
@@ -5106,6 +5046,7 @@ cy_init(void))
cy_serial_driver.stop = cy_stop;
cy_serial_driver.start = cy_start;
cy_serial_driver.hangup = cy_hangup;
+ cy_serial_driver.wait_until_sent = cy_wait_until_sent;
/*
* The callout device is just like normal device except for
@@ -5115,6 +5056,9 @@ cy_init(void))
cy_callout_driver.name = "cub";
cy_callout_driver.major = CYCLADESAUX_MAJOR;
cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ cy_callout_driver.read_proc = 0;
+ cy_callout_driver.proc_entry = 0;
+
if (tty_register_driver(&cy_serial_driver))
panic("Couldn't register Cyclades serial driver\n");
@@ -5123,7 +5067,7 @@ cy_init(void))
init_bh(CYCLADES_BH, do_cyclades_bh);
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < NR_IRQS; i++) {
IRQ_cards[i] = 0;
}
@@ -5167,7 +5111,7 @@ cy_init(void))
/* initialize per-port data structures for each valid board found */
for (board = 0 ; board < cy_nboard ; board++) {
cinfo = &cy_card[board];
- if (cinfo->num_chips == 1){ /* Cyclades-Z */
+ if (cinfo->num_chips == -1){ /* Cyclades-Z */
number_z_boards++;
mailbox = cy_readl(&((struct RUNTIME_9060 *)
cy_card[board].ctl_addr)->mail_box_0);
@@ -5199,11 +5143,10 @@ cy_init(void))
info->rco = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
- info->closing_wait2 = 0;
info->x_char = 0;
info->event = 0;
info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
// printk("cyc:cy_init(1) setting Z count to 0\n");
#endif
info->blocked_open = 0;
@@ -5250,7 +5193,6 @@ cy_init(void))
info->cor5 = 0;
info->close_delay = 5*HZ/10;
info->closing_wait = CLOSING_WAIT_DELAY;
- info->closing_wait2 = 0;
chip_number = (port - cinfo->first_line) / 4;
if ((info->chip_rev = cy_readb(cinfo->base_addr +
(cy_chip_offset[chip_number]<<index) +
@@ -5273,7 +5215,7 @@ cy_init(void))
info->x_char = 0;
info->event = 0;
info->count = 0;
-#ifdef SERIAL_DEBUG_COUNT
+#ifdef CY_DEBUG_COUNT
// printk("cyc:cy_init(2) setting Y count to 0\n");
#endif
info->blocked_open = 0;
@@ -5307,6 +5249,16 @@ 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;
} /* cy_init */
@@ -5349,6 +5301,10 @@ cleanup_module(void)
free_irq(cy_card[i].irq,NULL);
}
}
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("cyclades", 0);
+#endif
+
} /* cleanup_module */
#else
/* called by linux/init/main.c to parse command line options */
diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c
index 3dd385df1..a694d9346 100644
--- a/drivers/char/dn_keyb.c
+++ b/drivers/char/dn_keyb.c
@@ -573,13 +573,13 @@ __initfunc(int dn_keyb_init(void)) {
/* printk("dn_keyb_init\n"); */
- memcpy(plain_map, dnplain_map, sizeof(plain_map));
- memcpy(shift_map, dnshift_map, sizeof(shift_map));
- memcpy(altgr_map, dnaltgr_map, sizeof(altgr_map));
- memcpy(ctrl_map, dnctrl_map, sizeof(ctrl_map));
- memcpy(shift_ctrl_map, dnshift_ctrl_map, sizeof(shift_ctrl_map));
- memcpy(alt_map, dnalt_map, sizeof(alt_map));
- memcpy(ctrl_alt_map, dnctrl_alt_map, sizeof(ctrl_alt_map));
+ memcpy(key_maps[0], dnplain_map, sizeof(plain_map));
+ memcpy(key_maps[1], dnshift_map, sizeof(plain_map));
+ memcpy(key_maps[2], dnaltgr_map, sizeof(plain_map));
+ memcpy(key_maps[4], dnctrl_map, sizeof(plain_map));
+ memcpy(key_maps[5], dnshift_ctrl_map, sizeof(plain_map));
+ memcpy(key_maps[8], dnalt_map, sizeof(plain_map));
+ memcpy(key_maps[12], dnctrl_alt_map, sizeof(plain_map));
mouse_dx=0;
mouse_dy=0;
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index cac55b5ba..7818e8da3 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -401,9 +401,7 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
if (dsp56k_host_interface.isr & DSP56K_ISR_HF2) status |= 0x4;
if (dsp56k_host_interface.isr & DSP56K_ISR_HF3) status |= 0x8;
- if(put_user(status, &hf->status) < 0)
- return -EFAULT;
- break;
+ return put_user(status, &hf->status);
}
case DSP56K_HOST_CMD:
if (arg > 31 || arg < 0)
@@ -427,27 +425,19 @@ static int dsp56k_ioctl(struct inode *inode, struct file *file,
* Do I need this function at all???
*/
#if 0
-static int dsp56k_select(struct inode *inode, struct file *file, int sel_type,
- select_table *wait)
+static unsigned int dsp56k_poll(struct file *file, poll_table *wait)
{
- int dev = MINOR(inode->i_rdev) & 0x0f;
+ int dev = MINOR(file->f_dentry->d_inode->i_rdev) & 0x0f;
switch(dev)
{
case DSP56K_DEV_56001:
-
- switch(sel_type) {
- case SEL_IN: /* read */
- return 1;
- case SEL_OUT: /* write */
- return 1;
- default:
- return 1;
- }
+ /* poll_wait(file, ???, wait); */
+ return POLLIN | POLLRDNORM | POLLOUT;
default:
printk("DSP56k driver: Unknown minor device: %d\n", dev);
- return -ENXIO;
+ return 0;
}
}
#endif
@@ -530,22 +520,17 @@ static struct file_operations dsp56k_fops = {
/****** Init and module functions ******/
-static int init_error = 0;
-
-__initfunc(void dsp56k_init(void))
+__initfunc(int dsp56k_init(void))
{
- if(!ATARIHW_PRESENT(DSP56K)) {
- init_error = 1;
+ if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) {
printk("DSP56k driver: Hardware not present\n");
- return;
+ return -ENODEV;
}
-#ifndef MODULE
if(register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops)) {
printk("DSP56k driver: Unable to register driver\n");
- return;
+ return -ENODEV;
}
-#endif /* !MODULE */
dsp56k.in_use = 0;
@@ -555,20 +540,7 @@ __initfunc(void dsp56k_init(void))
#ifdef MODULE
int init_module(void)
{
- int r;
-
- init_error = 0;
- dsp56k_init();
- if(init_error)
- return -EPERM;
-
- r = register_chrdev(DSP56K_MAJOR, "dsp56k", &dsp56k_fops);
- if(r) {
- printk("DSP56k driver: Unable to register driver\n");
- return r;
- }
-
- return 0;
+ return dsp56k_init();
}
void cleanup_module(void)
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 6fee9da6d..9ddf7c33d 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -3956,7 +3956,7 @@ void epca_setup(char *str, int *ints)
translate (To an unsigned long obviously), the second argument
can be the address of any character variable or a NULL. If a
variable is given, the end pointer of the string will be stored
- in that variable; if a NULL is given the the end pointer will
+ in that variable; if a NULL is given the end pointer will
not be returned. The last argument is the base to use. If
a 0 is indicated, the routine will attempt to determine the
proper base by looking at the values prefix (A '0' for octal,
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 553bf273b..522569077 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -37,7 +37,6 @@
* int espserial_init(void);
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -65,7 +64,7 @@
#include <linux/malloc.h>
#include <asm/uaccess.h>
-#include "esp.h"
+#include <linux/hayesesp.h>
#define NR_PORTS 64 /* maximum number of ports */
#define NR_PRIMARY 8 /* maximum number of primary ports */
@@ -74,12 +73,13 @@
static int irq[NR_PRIMARY] = {0,0,0,0,0,0,0,0}; /* IRQ for each base port */
static unsigned int divisor[NR_PRIMARY] = {0,0,0,0,0,0,0,0};
/* custom divisor for each port */
-static unsigned int dma = CONFIG_ESPSERIAL_DMA_CHANNEL; /* DMA channel */
-static unsigned int rx_trigger = CONFIG_ESPSERIAL_RX_TRIGGER;
-static unsigned int tx_trigger = CONFIG_ESPSERIAL_TX_TRIGGER;
-static unsigned int flow_off = CONFIG_ESPSERIAL_FLOW_OFF;
-static unsigned int flow_on = CONFIG_ESPSERIAL_FLOW_ON;
-static unsigned int rx_timeout = CONFIG_ESPSERIAL_RX_TMOUT;
+static unsigned int dma = ESP_DMA_CHANNEL; /* DMA channel */
+static unsigned int rx_trigger = ESP_RX_TRIGGER;
+static unsigned int tx_trigger = ESP_TX_TRIGGER;
+static unsigned int flow_off = ESP_FLOW_OFF;
+static unsigned int flow_on = ESP_FLOW_ON;
+static unsigned int rx_timeout = ESP_RX_TMOUT;
+static unsigned int pio_threshold = ESP_PIO_THRESHOLD;
MODULE_PARM(irq, "1-8i");
MODULE_PARM(divisor, "1-8i");
@@ -89,6 +89,8 @@ MODULE_PARM(tx_trigger, "i");
MODULE_PARM(flow_off, "i");
MODULE_PARM(flow_on, "i");
MODULE_PARM(rx_timeout, "i");
+MODULE_PARM(pio_threshold, "i");
+
/* END */
static char *dma_buffer;
@@ -100,7 +102,7 @@ static struct esp_pio_buffer *free_pio_buf;
#define WAKEUP_CHARS 1024
static char *serial_name = "ESP serial driver";
-static char *serial_version = "2.0";
+static char *serial_version = "2.1";
static DECLARE_TASK_QUEUE(tq_esp);
@@ -696,7 +698,7 @@ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
if (num_bytes) {
if (dma_bytes ||
(info->stat_flags & ESP_STAT_USE_PIO) ||
- (num_bytes <= ESP_PIO_THRESHOLD))
+ (num_bytes <= info->config.pio_threshold))
receive_chars_pio(info, num_bytes);
else
receive_chars_dma(info, num_bytes);
@@ -723,7 +725,7 @@ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
if (num_bytes) {
if (dma_bytes ||
(info->stat_flags & ESP_STAT_USE_PIO) ||
- (num_bytes <= ESP_PIO_THRESHOLD))
+ (num_bytes <= info->config.pio_threshold))
transmit_chars_pio(info, num_bytes);
else
transmit_chars_dma(info, num_bytes);
@@ -853,10 +855,10 @@ static _INLINE_ void esp_basic_init(struct esp_struct * info)
/* set FIFO trigger levels */
serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
- serial_out(info, UART_ESI_CMD2, rx_trigger >> 8);
- serial_out(info, UART_ESI_CMD2, rx_trigger);
- serial_out(info, UART_ESI_CMD2, tx_trigger >> 8);
- serial_out(info, UART_ESI_CMD2, tx_trigger);
+ serial_out(info, UART_ESI_CMD2, info->config.rx_trigger >> 8);
+ serial_out(info, UART_ESI_CMD2, info->config.rx_trigger);
+ serial_out(info, UART_ESI_CMD2, info->config.tx_trigger >> 8);
+ serial_out(info, UART_ESI_CMD2, info->config.tx_trigger);
/* Set clock scaling and wait states */
serial_out(info, UART_ESI_CMD1, ESI_SET_PRESCALAR);
@@ -910,7 +912,7 @@ static int startup(struct esp_struct * info)
/* set receive character timeout */
serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
- serial_out(info, UART_ESI_CMD2, rx_timeout);
+ serial_out(info, UART_ESI_CMD2, info->config.rx_timeout);
/* clear all flags except the "never DMA" flag */
info->stat_flags &= ESP_STAT_NEVER_DMA;
@@ -1229,10 +1231,10 @@ static void change_speed(struct esp_struct *info)
/* Set high/low water */
serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL);
- serial_out(info, UART_ESI_CMD2, flow_off >> 8);
- serial_out(info, UART_ESI_CMD2, flow_off);
- serial_out(info, UART_ESI_CMD2, flow_on >> 8);
- serial_out(info, UART_ESI_CMD2, flow_on);
+ serial_out(info, UART_ESI_CMD2, info->config.flow_off >> 8);
+ serial_out(info, UART_ESI_CMD2, info->config.flow_off);
+ serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8);
+ serial_out(info, UART_ESI_CMD2, info->config.flow_on);
restore_flags(flags);
}
@@ -1283,10 +1285,10 @@ static void rs_flush_chars(struct tty_struct *tty)
static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
- int c, ret = 0;
+ int c, t, ret = 0;
struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->device, "rs_write"))
return 0;
@@ -1295,40 +1297,56 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (from_user)
down(&tmp_buf_sem);
- save_flags(flags);
+
while (1) {
- cli();
- c = MIN(count, MIN(ESP_XMIT_SIZE - info->xmit_cnt - 1,
- ESP_XMIT_SIZE - info->xmit_head));
+ /* Thanks to R. Wolff for suggesting how to do this with */
+ /* interrupts enabled */
+
+ c = count;
+ t = ESP_XMIT_SIZE - info->xmit_cnt - 1;
+
+ if (t < c)
+ c = t;
+
+ t = ESP_XMIT_SIZE - info->xmit_head;
+
+ if (t < c)
+ c = t;
+
if (c <= 0)
break;
if (from_user) {
c -= copy_from_user(tmp_buf, buf, c);
+
if (!c) {
if (!ret)
ret = -EFAULT;
break;
}
- c = MIN(c, MIN(ESP_XMIT_SIZE - info->xmit_cnt - 1,
- ESP_XMIT_SIZE - info->xmit_head));
+
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
} else
memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
info->xmit_head = (info->xmit_head + c) & (ESP_XMIT_SIZE-1);
info->xmit_cnt += c;
- restore_flags(flags);
buf += c;
count -= c;
ret += c;
}
+
if (from_user)
up(&tmp_buf_sem);
+
+ save_flags(flags); cli();
+
if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
}
+
restore_flags(flags);
return ret;
}
@@ -1418,7 +1436,7 @@ static void rs_unthrottle(struct tty_struct * tty)
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);
- serial_out(info, UART_ESI_CMD2, rx_timeout);
+ serial_out(info, UART_ESI_CMD2, info->config.rx_timeout);
sti();
}
@@ -1447,24 +1465,40 @@ static int get_serial_info(struct esp_struct * info,
tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = 0;
- tmp.reserved_char[0] = 'E';
- tmp.reserved_char[1] = rx_timeout;
- tmp.reserved[0] = rx_trigger;
- tmp.reserved[1] = tx_trigger;
- tmp.reserved[2] = flow_off;
- tmp.reserved[3] = flow_on;
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
}
+static int get_esp_config(struct esp_struct * info,
+ struct hayes_esp_config * retinfo)
+{
+ struct hayes_esp_config tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.rx_timeout = info->config.rx_timeout;
+ tmp.rx_trigger = info->config.rx_trigger;
+ tmp.tx_trigger = info->config.tx_trigger;
+ tmp.flow_off = info->config.flow_off;
+ tmp.flow_on = info->config.flow_on;
+ tmp.pio_threshold = info->config.pio_threshold;
+ tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma);
+
+ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
static int set_serial_info(struct esp_struct * info,
struct serial_struct * new_info)
{
struct serial_struct new_serial;
struct esp_struct old_info;
unsigned int change_irq;
- unsigned int change_flow;
int retval = 0;
struct esp_struct *current_async;
@@ -1480,21 +1514,10 @@ static int set_serial_info(struct esp_struct * info,
(new_serial.irq < 2) ||
(new_serial.irq == 6) ||
(new_serial.irq == 8) ||
- (new_serial.irq == 13) ||
- (new_serial.reserved[3] >= new_serial.reserved[2]) ||
- (new_serial.reserved[0] < 1) ||
- (new_serial.reserved[1] < 1) ||
- (new_serial.reserved[2] < 1) ||
- (new_serial.reserved[3] < 1) ||
- (new_serial.reserved[0] > 1023) ||
- (new_serial.reserved[1] > 1023) ||
- (new_serial.reserved[2] > 1023) ||
- (new_serial.reserved[3] > 1023))
+ (new_serial.irq == 13))
return -EINVAL;
change_irq = new_serial.irq != info->irq;
- change_flow = ((new_serial.reserved[2] != flow_off) ||
- (new_serial.reserved[3] != flow_on));
if (change_irq && (info->line % 8))
return -EINVAL;
@@ -1539,40 +1562,6 @@ static int set_serial_info(struct esp_struct * info,
info->custom_divisor = new_serial.custom_divisor;
info->close_delay = new_serial.close_delay * HZ/100;
info->closing_wait = new_serial.closing_wait * HZ/100;
- flow_off = new_serial.reserved[2];
- flow_on = new_serial.reserved[3];
-
- if ((new_serial.reserved[0] != rx_trigger) ||
- (new_serial.reserved[1] != tx_trigger)) {
- unsigned long flags;
-
- rx_trigger = new_serial.reserved[0];
- tx_trigger = new_serial.reserved[1];
- save_flags(flags); cli();
- serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
- serial_out(info, UART_ESI_CMD2, rx_trigger >> 8);
- serial_out(info, UART_ESI_CMD2, rx_trigger);
- serial_out(info, UART_ESI_CMD2, tx_trigger >> 8);
- serial_out(info, UART_ESI_CMD2, tx_trigger);
- restore_flags(flags);
- }
-
- if (((unsigned char)(new_serial.reserved_char[1]) !=
- rx_timeout)) {
- unsigned long flags;
-
- rx_timeout = (unsigned char)
- (new_serial.reserved_char[1]);
- save_flags(flags); cli();
-
- if (info->IER & UART_IER_RDI) {
- serial_out(info, UART_ESI_CMD1,
- ESI_SET_RX_TIMEOUT);
- serial_out(info, UART_ESI_CMD2, rx_timeout);
- }
-
- restore_flags(flags);
- }
if (change_irq) {
/*
@@ -1602,8 +1591,7 @@ static int set_serial_info(struct esp_struct * info,
if (info->flags & ASYNC_INITIALIZED) {
if (((old_info.flags & ASYNC_SPD_MASK) !=
(info->flags & ASYNC_SPD_MASK)) ||
- (old_info.custom_divisor != info->custom_divisor) ||
- change_flow) {
+ (old_info.custom_divisor != info->custom_divisor)) {
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
info->tty->alt_speed = 57600;
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
@@ -1620,6 +1608,141 @@ static int set_serial_info(struct esp_struct * info,
return retval;
}
+static int set_esp_config(struct esp_struct * info,
+ struct hayes_esp_config * new_info)
+{
+ struct hayes_esp_config new_config;
+ unsigned int change_dma;
+ int retval = 0;
+ struct esp_struct *current_async;
+
+ /* Perhaps a non-sysadmin user should be able to do some of these */
+ /* operations. I haven't decided yet. */
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&new_config, new_info, sizeof(new_config)))
+ return -EFAULT;
+
+ if ((new_config.flow_on >= new_config.flow_off) ||
+ (new_config.rx_trigger < 1) ||
+ (new_config.tx_trigger < 1) ||
+ (new_config.flow_off < 1) ||
+ (new_config.flow_on < 1) ||
+ (new_config.rx_trigger > 1023) ||
+ (new_config.tx_trigger > 1023) ||
+ (new_config.flow_off > 1023) ||
+ (new_config.flow_on > 1023) ||
+ (new_config.pio_threshold < 0) ||
+ (new_config.pio_threshold > 1024))
+ return -EINVAL;
+
+ if ((new_config.dma_channel != 1) && (new_config.dma_channel != 3))
+ new_config.dma_channel = 0;
+
+ if (info->stat_flags & ESP_STAT_NEVER_DMA)
+ change_dma = new_config.dma_channel;
+ else
+ change_dma = (new_config.dma_channel != dma);
+
+ if (change_dma) {
+ if (new_config.dma_channel) {
+ /* PIO mode to DMA mode transition OR */
+ /* change current DMA channel */
+
+ current_async = ports;
+
+ while (current_async) {
+ if (current_async == info) {
+ if (current_async->count > 1)
+ return -EBUSY;
+ } else if (current_async->count)
+ return -EBUSY;
+
+ current_async =
+ current_async->next_port;
+ }
+
+ shutdown(info);
+ dma = new_config.dma_channel;
+ info->stat_flags &= ~ESP_STAT_NEVER_DMA;
+
+ /* all ports must use the same DMA channel */
+
+ current_async = ports;
+
+ while (current_async) {
+ esp_basic_init(current_async);
+ current_async = current_async->next_port;
+ }
+ } else {
+ /* DMA mode to PIO mode only */
+
+ if (info->count > 1)
+ return -EBUSY;
+
+ shutdown(info);
+ info->stat_flags |= ESP_STAT_NEVER_DMA;
+ esp_basic_init(info);
+ }
+ }
+
+ info->config.pio_threshold = new_config.pio_threshold;
+
+ if ((new_config.flow_off != info->config.flow_off) ||
+ (new_config.flow_on != info->config.flow_on)) {
+ unsigned long flags;
+
+ info->config.flow_off = new_config.flow_off;
+ info->config.flow_on = new_config.flow_on;
+ save_flags(flags); cli();
+ serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL);
+ serial_out(info, UART_ESI_CMD2, new_config.flow_off >> 8);
+ serial_out(info, UART_ESI_CMD2, new_config.flow_off);
+ serial_out(info, UART_ESI_CMD2, new_config.flow_on >> 8);
+ serial_out(info, UART_ESI_CMD2, new_config.flow_on);
+ restore_flags(flags);
+ }
+
+ if ((new_config.rx_trigger != info->config.rx_trigger) ||
+ (new_config.tx_trigger != info->config.tx_trigger)) {
+ unsigned long flags;
+
+ info->config.rx_trigger = new_config.rx_trigger;
+ info->config.tx_trigger = new_config.tx_trigger;
+ save_flags(flags); cli();
+ serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER);
+ serial_out(info, UART_ESI_CMD2,
+ new_config.rx_trigger >> 8);
+ serial_out(info, UART_ESI_CMD2, new_config.rx_trigger);
+ serial_out(info, UART_ESI_CMD2,
+ new_config.tx_trigger >> 8);
+ serial_out(info, UART_ESI_CMD2, new_config.tx_trigger);
+ restore_flags(flags);
+ }
+
+ if (new_config.rx_timeout != info->config.rx_timeout) {
+ unsigned long flags;
+
+ info->config.rx_timeout = new_config.rx_timeout;
+ save_flags(flags); cli();
+
+ if (info->IER & UART_IER_RDI) {
+ serial_out(info, UART_ESI_CMD1,
+ ESI_SET_RX_TIMEOUT);
+ serial_out(info, UART_ESI_CMD2,
+ new_config.rx_timeout);
+ }
+
+ restore_flags(flags);
+ }
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ retval = startup(info);
+
+ return retval;
+}
/*
* get_lsr_info - get line status register info
@@ -1741,7 +1864,8 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
(cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&
- (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT) &&
+ (cmd != TIOCGHAYESESP) && (cmd != TIOCSHAYESESP)) {
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
@@ -1826,6 +1950,12 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return error;
return 0;
+ case TIOCGHAYESESP:
+ return (get_esp_config(info,
+ (struct hayes_esp_config *)arg));
+ case TIOCSHAYESESP:
+ return (set_esp_config(info,
+ (struct hayes_esp_config *)arg));
default:
return -ENOIOCTLCMD;
@@ -2381,13 +2511,15 @@ __initfunc(int espserial_init(void))
init_bh(ESP_BH, do_serial_bh);
- for (i = 0; i < NR_PRIMARY; i++)
- if (irq[i] != 0)
+ for (i = 0; i < NR_PRIMARY; i++) {
+ if (irq[i] != 0) {
if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
(irq[i] == 8) || (irq[i] == 13))
irq[i] = 0;
else if (irq[i] == 2)
irq[i] = 9;
+ }
+ }
if ((dma != 1) && (dma != 3))
dma = 0;
@@ -2511,6 +2643,12 @@ __initfunc(int espserial_init(void))
info->tqueue_hangup.data = info;
info->callout_termios = esp_callout_driver.init_termios;
info->normal_termios = esp_driver.init_termios;
+ info->config.rx_timeout = rx_timeout;
+ info->config.rx_trigger = rx_trigger;
+ info->config.tx_trigger = tx_trigger;
+ info->config.flow_on = flow_on;
+ info->config.flow_off = flow_off;
+ info->config.pio_threshold = pio_threshold;
info->next_port = ports;
ports = info;
printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ",
diff --git a/drivers/char/esp.h b/drivers/char/esp.h
deleted file mode 100644
index 8a207e12e..000000000
--- a/drivers/char/esp.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef ESP_H
-#define ESP_H
-
-#define ESP_IN_MAJOR 57 /* major dev # for dial in */
-#define ESP_OUT_MAJOR 58 /* major dev # for dial out */
-#define ESPC_SCALE 3
-#define UART_ESI_BASE 0x00
-#define UART_ESI_SID 0x01
-#define UART_ESI_RX 0x02
-#define UART_ESI_TX 0x02
-#define UART_ESI_CMD1 0x04
-#define UART_ESI_CMD2 0x05
-#define UART_ESI_STAT1 0x04
-#define UART_ESI_STAT2 0x05
-#define UART_ESI_RWS 0x07
-
-#define UART_IER_DMA_TMOUT 0x80
-#define UART_IER_DMA_TC 0x08
-
-#define ESI_SET_IRQ 0x04
-#define ESI_SET_DMA_TMOUT 0x05
-#define ESI_SET_SRV_MASK 0x06
-#define ESI_SET_ERR_MASK 0x07
-#define ESI_SET_FLOW_CNTL 0x08
-#define ESI_SET_FLOW_CHARS 0x09
-#define ESI_SET_FLOW_LVL 0x0a
-#define ESI_SET_TRIGGER 0x0b
-#define ESI_SET_RX_TIMEOUT 0x0c
-#define ESI_SET_FLOW_TMOUT 0x0d
-#define ESI_WRITE_UART 0x0e
-#define ESI_READ_UART 0x0f
-#define ESI_SET_MODE 0x10
-#define ESI_GET_ERR_STAT 0x12
-#define ESI_GET_UART_STAT 0x13
-#define ESI_GET_RX_AVAIL 0x14
-#define ESI_GET_TX_AVAIL 0x15
-#define ESI_START_DMA_RX 0x16
-#define ESI_START_DMA_TX 0x17
-#define ESI_ISSUE_BREAK 0x1a
-#define ESI_FLUSH_RX 0x1b
-#define ESI_FLUSH_TX 0x1c
-#define ESI_SET_BAUD 0x1d
-#define ESI_SET_ENH_IRQ 0x1f
-#define ESI_SET_REINTR 0x20
-#define ESI_SET_PRESCALAR 0x23
-#define ESI_NO_COMMAND 0xff
-
-#define ESP_STAT_RX_TIMEOUT 0x01
-#define ESP_STAT_DMA_RX 0x02
-#define ESP_STAT_DMA_TX 0x04
-#define ESP_STAT_NEVER_DMA 0x08
-#define ESP_STAT_USE_PIO 0x10
-
-/* Always use PIO for this number (or less) of bytes */
-#define ESP_PIO_THRESHOLD 32
-
-#define ESP_EVENT_WRITE_WAKEUP 0
-#define ESP_MAGIC 0x53ee
-#define ESP_XMIT_SIZE 4096
-
-struct esp_struct {
- int magic;
- int port;
- int irq;
- int flags; /* defined in tty.h */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int stat_flags;
- int custom_divisor;
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- int IER; /* Interrupt Enable Register */
- int MCR; /* Modem control register */
- unsigned long event;
- unsigned long last_active;
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- long session; /* Session of opening process */
- long pgrp; /* pgrp of opening process */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- struct tq_struct tqueue;
- struct tq_struct tqueue_hangup;
- struct termios normal_termios;
- struct termios callout_termios;
- struct wait_queue *open_wait;
- struct wait_queue *close_wait;
- struct wait_queue *delta_msr_wait;
- struct wait_queue *break_wait;
- struct async_icount icount; /* kernel counters for the 4 input interrupts */
- struct esp_struct *next_port; /* For the linked list */
-};
-
-struct esp_pio_buffer
-{
- unsigned char data[1024];
- struct esp_pio_buffer *next;
-};
-
-#endif /* ESP_H */
-
diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c
index fd2b28ec9..8f8612b35 100644
--- a/drivers/char/fbmem.c
+++ b/drivers/char/fbmem.c
@@ -8,6 +8,9 @@
* for more details.
*/
+#include <linux/config.h>
+#include <linux/module.h>
+
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -16,30 +19,153 @@
#include <linux/malloc.h>
#include <linux/mman.h>
#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/console_struct.h>
#include <linux/init.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+#ifdef __mc68000__
#include <asm/setup.h>
+#endif
+#ifdef __powerpc__
+#include <asm/io.h>
+#endif
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <linux/fb.h>
-#define FB_MAJOR 29
-#define FB_MODES_SHIFT 5 /* 32 modes per framebuffer */
-#define FB_NUM_MINORS 256 /* 256 Minors */
-#define FB_MAX (FB_NUM_MINORS / (1 << FB_MODES_SHIFT))
+ /*
+ * Frame buffer device initialization and setup routines
+ */
+
+extern unsigned long acornfb_init(void);
+extern void acornfb_setup(char *options, int *ints);
+extern void amifb_init(void);
+extern void amifb_setup(char *options, int *ints);
+extern void atafb_init(void);
+extern void atafb_setup(char *options, int *ints);
+extern void macfb_init(void);
+extern void macfb_setup(char *options, int *ints);
+extern void cyberfb_init(void);
+extern void cyberfb_setup(char *options, int *ints);
+extern void retz3fb_init(void);
+extern void retz3fb_setup(char *options, int *ints);
+extern void clgenfb_init(void);
+extern void clgenfb_setup(char *options, int *ints);
+extern void vfb_init(void);
+extern void vfb_setup(char *options, int *ints);
+extern void offb_init(void);
+extern void offb_setup(char *options, int *ints);
+extern void atyfb_init(void);
+extern void atyfb_setup(char *options, int *ints);
+extern void dnfb_init(void);
+extern void tgafb_init(void);
+extern void virgefb_init(void);
+extern void virgefb_setup(char *options, int *ints);
+extern void resolver_video_setup(char *options, int *ints);
+extern void s3triofb_init(void);
+extern void s3triofb_setup(char *options, int *ints);
+extern void vgafb_init(void);
+extern void vgafb_setup(char *options, int *ints);
+extern void vesafb_init(void);
+extern void vesafb_setup(char *options, int *ints);
+extern void mdafb_init(void);
+extern void mdafb_setup(char *options, int *ints);
+extern void hpfb_init(void);
+extern void hpfb_setup(char *options, int *ints);
+extern void sbusfb_init(void);
+extern void sbusfb_setup(char *options, int *ints);
+
+static struct {
+ const char *name;
+ void (*init)(void);
+ void (*setup)(char *options, int *ints);
+} fb_drivers[] __initdata = {
+#ifdef CONFIG_FB_RETINAZ3
+ { "retz3", retz3fb_init, retz3fb_setup },
+#endif
+#ifdef CONFIG_FB_ACORN
+ { "acorn", acornfb_init, acornfb_setup },
+#endif
+#ifdef CONFIG_FB_AMIGA
+ { "amifb", amifb_init, amifb_setup },
+#endif
+#ifdef CONFIG_FB_ATARI
+ { "atafb", atafb_init, atafb_setup },
+#endif
+#ifdef CONFIG_FB_MAC
+ { "macfb", macfb_init, macfb_setup },
+#endif
+#ifdef CONFIG_FB_CYBER
+ { "cyber", cyberfb_init, cyberfb_setup },
+#endif
+#ifdef CONFIG_FB_CLGEN
+ { "clgen", clgenfb_init, clgenfb_setup },
+#endif
+#ifdef CONFIG_FB_OF
+ { "offb", offb_init, offb_setup },
+#endif
+#ifdef CONFIG_FB_ATY
+ { "atyfb", atyfb_init, atyfb_setup },
+#endif
+#ifdef CONFIG_APOLLO
+ { "apollo", dnfb_init, NULL },
+#endif
+#ifdef CONFIG_FB_S3TRIO
+ { "s3trio", s3triofb_init, s3triofb_setup },
+#endif
+#ifdef CONFIG_FB_TGA
+ { "tga", tgafb_init, NULL },
+#endif
+#ifdef CONFIG_FB_VIRGE
+ { "virge", virgefb_init, virgefb_setup },
+#endif
+#ifdef CONFIG_FB_VGA
+ { "vga", vgafb_init, vgafb_setup },
+#endif
+#ifdef CONFIG_FB_VESA
+ { "vesa", vesafb_init, vesafb_setup },
+#endif
+#ifdef CONFIG_FB_MDA
+ { "mda", mdafb_init, mdafb_setup },
+#endif
+#ifdef CONFIG_FB_HP300
+ { "hpfb", hpfb_init, hpfb_setup },
+#endif
+#ifdef CONFIG_FB_SBUS
+ { "sbus", sbusfb_init, sbusfb_setup },
+#endif
+#ifdef CONFIG_GSP_RESOLVER
+ /* Not a real frame buffer device... */
+ { "resolver", NULL, resolver_video_setup },
+#endif
+#ifdef CONFIG_FB_VIRTUAL
+ /* Must be last to avoid that vfb becomes your primary display */
+ { "vfb", vfb_init, vfb_setup },
+#endif
+};
+
+#define NUM_FB_DRIVERS (sizeof(fb_drivers)/sizeof(*fb_drivers))
+
+static void (*pref_init_funcs[FB_MAX])(void);
+static int num_pref_init_funcs __initdata = 0;
+
#define GET_INODE(i) MKDEV(FB_MAJOR, (i) << FB_MODES_SHIFT)
-#define GET_FB_IDX(node) (MINOR(node) >> FB_MODES_SHIFT)
#define GET_FB_VAR_IDX(node) (MINOR(node) & ((1 << FB_MODES_SHIFT)-1))
-struct fb_ops *registered_fb[FB_MAX];
-struct fb_var_screeninfo *registered_fb_var[FB_MAX];
-int registered_fb_var_num[FB_MAX];
-int fb_curr_open[FB_MAX];
-int fb_open_count[FB_MAX];
+struct fb_info *registered_fb[FB_MAX];
+int num_registered_fb = 0;
+
+char con2fb_map[MAX_NR_CONSOLES];
static inline int PROC_CONSOLE(void)
{
@@ -56,167 +182,250 @@ static inline int PROC_CONSOLE(void)
return MINOR(current->tty->device) - 1;
}
-static long
-fb_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
+#ifdef CONFIG_PROC_FS
+static int fbmem_read_proc(char *buf, char **start, off_t offset,
+ int len, int *eof, void *private)
+{
+ struct fb_info **fi;
+
+ len = 0;
+ for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
+ if (*fi)
+ len += sprintf(buf + len, "%d %s\n",
+ GET_FB_IDX((*fi)->node),
+ (*fi)->modename);
+ *start = buf + offset;
+ return len > offset ? len - offset : 0;
+}
+#endif
+
+static ssize_t
+fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
- unsigned long p = file->f_pos;
- struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+ unsigned long p = *ppos;
+ struct inode *inode = file->f_dentry->d_inode;
+ int fbidx = GET_FB_IDX(inode->i_rdev);
+ struct fb_info *info = registered_fb[fbidx];
+ struct fb_ops *fb = info->fbops;
struct fb_fix_screeninfo fix;
char *base_addr;
- int copy_size;
+ ssize_t copy_size;
- if (! fb)
+ if (! fb || ! info->disp)
return -ENODEV;
- fb->fb_get_fix(&fix,PROC_CONSOLE());
- base_addr=(char *) fix.smem_start;
+ fb->fb_get_fix(&fix,PROC_CONSOLE(), info);
+ base_addr=info->disp->screen_base;
copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
- copy_to_user(buf, base_addr+p, copy_size);
- file->f_pos += copy_size;
+ if (copy_to_user(buf, base_addr+p, copy_size))
+ return -EFAULT;
+ *ppos += copy_size;
return copy_size;
}
-static long
-fb_write(struct inode *inode, struct file *file, const char *buf,
- unsigned long count)
+static ssize_t
+fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- unsigned long p = file->f_pos;
- struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+ unsigned long p = *ppos;
+ struct inode *inode = file->f_dentry->d_inode;
+ int fbidx = GET_FB_IDX(inode->i_rdev);
+ struct fb_info *info = registered_fb[fbidx];
+ struct fb_ops *fb = info->fbops;
struct fb_fix_screeninfo fix;
char *base_addr;
- int copy_size;
+ ssize_t copy_size;
- if (! fb)
+ if (! fb || ! info->disp)
return -ENODEV;
- fb->fb_get_fix(&fix, PROC_CONSOLE());
- base_addr=(char *) fix.smem_start;
+
+ fb->fb_get_fix(&fix, PROC_CONSOLE(), info);
+ base_addr=info->disp->screen_base;
copy_size=(count + p <= fix.smem_len ? count : fix.smem_len - p);
- copy_from_user(base_addr+p, buf, copy_size);
+ if (copy_from_user(base_addr+p, buf, copy_size))
+ return -EFAULT;
file->f_pos += copy_size;
return copy_size;
}
+static void set_con2fb_map(int unit, int newidx)
+{
+ int oldidx = con2fb_map[unit];
+ struct fb_info *oldfb, *newfb;
+ struct vc_data *conp;
+
+ if (newidx != con2fb_map[unit]) {
+ oldfb = registered_fb[oldidx];
+ newfb = registered_fb[newidx];
+ if (newfb->fbops->fb_open(newfb,0))
+ return;
+ oldfb->fbops->fb_release(oldfb,0);
+ conp = fb_display[unit].conp;
+ con2fb_map[unit] = newidx;
+ fb_display[unit] = *(newfb->disp);
+ fb_display[unit].conp = conp;
+ fb_display[unit].fb_info = newfb;
+ if (!newfb->changevar)
+ newfb->changevar = oldfb->changevar;
+ /* tell console var has changed */
+ if (newfb->changevar)
+ newfb->changevar(unit);
+ }
+}
+
+#ifdef CONFIG_KMOD
+static void try_to_load(int fb)
+{
+ char modname[16];
+
+ sprintf(modname, "fb%d", fb);
+ request_module(modname);
+}
+#endif /* CONFIG_KMOD */
+
static int
fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- struct fb_ops *fb = registered_fb[GET_FB_IDX(inode->i_rdev)];
+ int fbidx = GET_FB_IDX(inode->i_rdev);
+ struct fb_info *info = registered_fb[fbidx];
+ struct fb_ops *fb = info->fbops;
struct fb_cmap cmap;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
-
- int i,fbidx,vidx;
+ struct fb_con2fbmap con2fb;
+ int i;
if (! fb)
return -ENODEV;
switch (cmd) {
case FBIOGET_VSCREENINFO:
- i = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct fb_var_screeninfo));
- if (i) return i;
- fbidx=GET_FB_IDX(inode->i_rdev);
- vidx=GET_FB_VAR_IDX(inode->i_rdev);
- if (! vidx) /* ask device driver for current */
- i=fb->fb_get_var(&var, PROC_CONSOLE());
- else
- var=registered_fb_var[fbidx][vidx-1];
- copy_to_user((void *) arg, &var, sizeof(var));
- return i;
+ if ((i = fb->fb_get_var(&var, PROC_CONSOLE(), info)))
+ return i;
+ return copy_to_user((void *) arg, &var,
+ sizeof(var)) ? -EFAULT : 0;
case FBIOPUT_VSCREENINFO:
- i = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct fb_var_screeninfo));
- if (i) return i;
- copy_from_user(&var, (void *) arg, sizeof(var));
- i=fb->fb_set_var(&var, PROC_CONSOLE());
- copy_to_user((void *) arg, &var, sizeof(var));
- fbidx=GET_FB_IDX(inode->i_rdev);
- vidx=GET_FB_VAR_IDX(inode->i_rdev);
- if (! i && vidx)
- registered_fb_var[fbidx][vidx-1]=var;
- return i;
+ if (copy_from_user(&var, (void *) arg, sizeof(var)))
+ return -EFAULT;
+ if ((i = fb->fb_set_var(&var, PROC_CONSOLE(), info)))
+ return i;
+ if (copy_to_user((void *) arg, &var, sizeof(var)))
+ return -EFAULT;
+ return 0;
case FBIOGET_FSCREENINFO:
- i = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct fb_fix_screeninfo));
- if (i) return i;
- i=fb->fb_get_fix(&fix, PROC_CONSOLE());
- copy_to_user((void *) arg, &fix, sizeof(fix));
- return i;
+ if ((i = fb->fb_get_fix(&fix, PROC_CONSOLE(), info)))
+ return i;
+ return copy_to_user((void *) arg, &fix, sizeof(fix)) ?
+ -EFAULT : 0;
case FBIOPUTCMAP:
- i = verify_area(VERIFY_READ, (void *) arg,
- sizeof(struct fb_cmap));
- if (i) return i;
- copy_from_user(&cmap, (void *) arg, sizeof(cmap));
- i = verify_area(VERIFY_READ, (void *) cmap.red,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- i = verify_area(VERIFY_READ, (void *) cmap.green,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- i = verify_area(VERIFY_READ, (void *) cmap.blue,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- if (cmap.transp) {
- i = verify_area(VERIFY_READ, (void *) cmap.transp,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- }
- return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE()));
+ if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
+ return -EFAULT;
+ return (fb->fb_set_cmap(&cmap, 0, PROC_CONSOLE(), info));
case FBIOGETCMAP:
- i = verify_area(VERIFY_READ, (void *) arg,
- sizeof(struct fb_cmap));
- if (i) return i;
- copy_from_user(&cmap, (void *) arg, sizeof(cmap));
- i = verify_area(VERIFY_WRITE, (void *) cmap.red,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- i = verify_area(VERIFY_WRITE, (void *) cmap.green,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- i = verify_area(VERIFY_WRITE, (void *) cmap.blue,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- if (cmap.transp) {
- i = verify_area(VERIFY_WRITE, (void *) cmap.transp,
- cmap.len * sizeof(unsigned short));
- if (i) return i;
- }
- return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
+ if (copy_from_user(&cmap, (void *) arg, sizeof(cmap)))
+ return -EFAULT;
+ return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE(), info));
case FBIOPAN_DISPLAY:
- i = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct fb_var_screeninfo));
- if (i) return i;
- copy_from_user(&var, (void *) arg, sizeof(var));
- i=fb->fb_pan_display(&var, PROC_CONSOLE());
- copy_to_user((void *) arg, &var, sizeof(var));
- fbidx=GET_FB_IDX(inode->i_rdev);
- vidx=GET_FB_VAR_IDX(inode->i_rdev);
- if (! i && vidx)
- registered_fb_var[fbidx][vidx-1]=var;
+ if (copy_from_user(&var, (void *) arg, sizeof(var)))
+ return -EFAULT;
+ if ((i=fb->fb_pan_display(&var, PROC_CONSOLE(), info)))
+ return i;
+ if (copy_to_user((void *) arg, &var, sizeof(var)))
+ return -EFAULT;
return i;
+ case FBIOGET_CON2FBMAP:
+ if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
+ return -EFAULT;
+ if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
+ return -EINVAL;
+ con2fb.framebuffer = con2fb_map[con2fb.console-1];
+ return copy_to_user((void *)arg, &con2fb,
+ sizeof(con2fb)) ? -EFAULT : 0;
+ case FBIOPUT_CON2FBMAP:
+ if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
+ return - EFAULT;
+ if (con2fb.console < 0 || con2fb.console > MAX_NR_CONSOLES)
+ return -EINVAL;
+ if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
+ return -EINVAL;
+#ifdef CONFIG_KMOD
+ if (!registered_fb[con2fb.framebuffer])
+ try_to_load(con2fb.framebuffer);
+#endif /* CONFIG_KMOD */
+ if (!registered_fb[con2fb.framebuffer])
+ return -EINVAL;
+ if (con2fb.console != 0)
+ set_con2fb_map(con2fb.console-1, con2fb.framebuffer);
+ else
+ /* set them all */
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ set_con2fb_map(i, con2fb.framebuffer);
+ return 0;
default:
- return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
+ return fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE(),
+ info);
}
}
-static int fb_mmap(struct file *file, struct vm_area_struct * vma)
+static int
+fb_mmap(struct file *file, struct vm_area_struct * vma)
{
- struct fb_ops *fb = registered_fb[GET_FB_IDX(file->f_dentry->d_inode->i_rdev)];
+ int fbidx = GET_FB_IDX(file->f_dentry->d_inode->i_rdev);
+ struct fb_info *info = registered_fb[fbidx];
+ struct fb_ops *fb = info->fbops;
struct fb_fix_screeninfo fix;
+ struct fb_var_screeninfo var;
+ unsigned long start;
+ u32 len;
- if (! fb)
+ if (!fb)
return -ENODEV;
- fb->fb_get_fix(&fix, PROC_CONSOLE());
- if ((vma->vm_end - vma->vm_start + vma->vm_offset) > fix.smem_len)
+ if (fb->fb_mmap)
+ return fb->fb_mmap(info, file, vma);
+ fb->fb_get_fix(&fix, PROC_CONSOLE(), info);
+
+ /* frame buffer memory */
+ start = (unsigned long)fix.smem_start;
+ len = (start & ~PAGE_MASK)+fix.smem_len;
+ start &= PAGE_MASK;
+ len = (len+~PAGE_MASK) & PAGE_MASK;
+ if (vma->vm_offset >= len) {
+ /* memory mapped io */
+ vma->vm_offset -= len;
+ fb->fb_get_var(&var, PROC_CONSOLE(), info);
+ if (var.accel_flags)
+ return -EINVAL;
+ start = (unsigned long)fix.mmio_start;
+ len = (start & ~PAGE_MASK)+fix.mmio_len;
+ start &= PAGE_MASK;
+ len = (len+~PAGE_MASK) & PAGE_MASK;
+ }
+ if ((vma->vm_end - vma->vm_start + vma->vm_offset) > len)
return -EINVAL;
- vma->vm_offset += __pa(fix.smem_start);
+ vma->vm_offset += start;
if (vma->vm_offset & ~PAGE_MASK)
return -ENXIO;
+#if defined(__mc68000__)
+ if (CPU_IS_020_OR_030)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
if (CPU_IS_040_OR_060) {
pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
- /* Use write-through cache mode */
+ /* Use no-cache mode, serialized */
pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
}
+#elif defined(__powerpc__)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED;
+#elif defined(__alpha__)
+ /* Caching is off in the I/O space quadrant by design. */
+#elif defined(__sparc__)
+ /* Should never get here, all fb drivers should have their own
+ mmap routines */
+#elif defined(__i386__)
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#else
+#warning What do we have to do here??
+#endif
if (remap_page_range(vma->vm_start, vma->vm_offset,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
@@ -228,34 +437,25 @@ static int fb_mmap(struct file *file, struct vm_area_struct * vma)
static int
fb_open(struct inode *inode, struct file *file)
{
- int fbidx=GET_FB_IDX(inode->i_rdev);
- int vidx=GET_FB_VAR_IDX(inode->i_rdev);
- struct fb_ops *fb = registered_fb[fbidx];
- int err;
-
- if (! vidx) /* fb?current always succeeds */
- return 0;
- if (vidx > registered_fb_var_num[fbidx])
- return -EINVAL;
- if (fb_curr_open[fbidx] && fb_curr_open[fbidx] != vidx)
- return -EBUSY;
- if (file->f_mode & 2) /* only set parameters if opened writeable */
- if ((err=fb->fb_set_var(registered_fb_var[fbidx] + vidx-1, PROC_CONSOLE())))
- return err;
- fb_curr_open[fbidx] = vidx;
- fb_open_count[fbidx]++;
- return 0;
+ int fbidx = GET_FB_IDX(inode->i_rdev);
+ struct fb_info *info;
+
+#ifdef CONFIG_KMOD
+ if (!(info = registered_fb[fbidx]))
+ try_to_load(fbidx);
+#endif /* CONFIG_KMOD */
+ if (!(info = registered_fb[fbidx]))
+ return -ENODEV;
+ return info->fbops->fb_open(info,1);
}
static int
fb_release(struct inode *inode, struct file *file)
{
- int fbidx=GET_FB_IDX(inode->i_rdev);
- int vidx=GET_FB_VAR_IDX(inode->i_rdev);
- if (! vidx)
- return 0;
- if (! (--fb_open_count[fbidx]))
- fb_curr_open[fbidx]=0;
+ int fbidx = GET_FB_IDX(inode->i_rdev);
+ struct fb_info *info = registered_fb[fbidx];
+
+ info->fbops->fb_release(info,1);
return 0;
}
@@ -273,37 +473,181 @@ static struct file_operations fb_fops = {
};
int
-register_framebuffer(char *id, int *node, struct fb_ops *fbops, int fbvar_num,
- struct fb_var_screeninfo *fbvar)
+register_framebuffer(struct fb_info *fb_info)
{
- int i;
+ int i, j;
+ static int fb_ever_opened[FB_MAX];
+ static int first = 1;
+
+ if (num_registered_fb == FB_MAX)
+ return -ENXIO;
+ num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
- if (! registered_fb[i])
+ if (!registered_fb[i])
break;
- if (i == FB_MAX)
- return -ENXIO;
- registered_fb[i]=fbops;
- registered_fb_var[i]=fbvar;
- registered_fb_var_num[i]=fbvar_num;
- *node=GET_INODE(i);
+ fb_info->node=GET_INODE(i);
+ registered_fb[i] = fb_info;
+ if (!fb_ever_opened[i]) {
+ /*
+ * We assume initial frame buffer devices can be opened this
+ * many times
+ */
+ for (j = 0; j < MAX_NR_CONSOLES; j++)
+ if (con2fb_map[j] == i)
+ fb_info->fbops->fb_open(fb_info,0);
+ fb_ever_opened[i] = 1;
+ }
+
+ if (first) {
+ first = 0;
+ take_over_console(&fb_con, 0, MAX_NR_CONSOLES-1, 1);
+ }
+
return 0;
}
int
-unregister_framebuffer(int node)
+unregister_framebuffer(const struct fb_info *fb_info)
{
- int i=GET_FB_IDX(node);
- if (! registered_fb[i])
+ int i, j;
+
+ i = GET_FB_IDX(fb_info->node);
+ for (j = 0; j < MAX_NR_CONSOLES; j++)
+ if (con2fb_map[j] == i)
+ return -EBUSY;
+ if (!registered_fb[i])
return -EINVAL;
registered_fb[i]=NULL;
- registered_fb_var[i]=NULL;
+ num_registered_fb--;
return 0;
}
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_fbmem;
+#endif
+
__initfunc(void
fbmem_init(void))
{
+ int i;
+
+#ifdef CONFIG_PROC_FS
+ proc_fbmem = create_proc_entry("fb", 0, 0);
+ if (proc_fbmem)
+ proc_fbmem->read_proc = fbmem_read_proc;
+#endif
+
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
+
+ /*
+ * Probe for all builtin frame buffer devices
+ */
+ for (i = 0; i < num_pref_init_funcs; i++)
+ pref_init_funcs[i]();
+
+ for (i = 0; i < NUM_FB_DRIVERS; i++)
+ if (fb_drivers[i].init)
+ fb_drivers[i].init();
+}
+
+
+int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal,
+ const struct fb_info *fb_info)
+{
+#if 0
+ /*
+ * long long divisions .... $#%%#$
+ */
+ unsigned long long hpicos, vpicos;
+ const unsigned long long _1e12 = 1000000000000ULL;
+ const struct fb_monspecs *monspecs = &fb_info->monspecs;
+
+ hpicos = (unsigned long long)htotal*(unsigned long long)pixclock;
+ vpicos = (unsigned long long)vtotal*(unsigned long long)hpicos;
+ if (!vpicos)
+ return 0;
+
+ if (monspecs->hfmin == 0)
+ return 1;
+
+ if (hpicos*monspecs->hfmin > _1e12 || hpicos*monspecs->hfmax < _1e12 ||
+ vpicos*monspecs->vfmin > _1e12 || vpicos*monspecs->vfmax < _1e12)
+ return 0;
+#endif
+ return 1;
}
+int fbmon_dpms(const struct fb_info *fb_info)
+{
+ return fb_info->monspecs.dpms;
+}
+
+
+ /*
+ * Command line options
+ */
+
+__initfunc(void video_setup(char *options, int *ints))
+{
+ int i, j;
+
+ if (!options || !*options)
+ return;
+
+ if (!strncmp(options, "map:", 4)) {
+ options += 4;
+ if (*options)
+ for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!options[j])
+ j = 0;
+ con2fb_map[i] = (options[j++]-'0') % FB_MAX;
+ }
+ return;
+ }
+
+ if (num_pref_init_funcs == FB_MAX)
+ return;
+
+ for (i = 0; i < NUM_FB_DRIVERS; i++) {
+ j = strlen(fb_drivers[i].name);
+ if (!strncmp(options, fb_drivers[i].name, j) &&
+ options[j] == ':') {
+ if (!strcmp(options+j+1, "off"))
+ fb_drivers[i].init = NULL;
+ else {
+ if (fb_drivers[i].init) {
+ pref_init_funcs[num_pref_init_funcs++] =
+ fb_drivers[i].init;
+ fb_drivers[i].init = NULL;
+ }
+ if (fb_drivers[i].setup)
+ fb_drivers[i].setup(options+j+1, ints);
+ }
+ return;
+ }
+ }
+ /*
+ * If we get here no fb was specified and we default to pass the
+ * options to the first frame buffer that has an init and a setup
+ * function.
+ */
+ for (i = 0; i < NUM_FB_DRIVERS; i++) {
+ if (fb_drivers[i].init && fb_drivers[i].setup) {
+ pref_init_funcs[num_pref_init_funcs++] =
+ fb_drivers[i].init;
+ fb_drivers[i].init = NULL;
+
+ fb_drivers[i].setup(options, ints);
+ return;
+ }
+ }
+}
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(register_framebuffer);
+EXPORT_SYMBOL(unregister_framebuffer);
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index bc00c4e86..5441daee9 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -214,7 +214,7 @@ int fdc_command(const __u8 * cmd_data, int cmd_len)
* sending the step pulses to the drive. Therefore the
* non-interrupt level driver has no chance to tell
* whether the isr() just has issued a seek. Therefore
- * we HAVE TO have a look at the the ft_hide_interrupt
+ * we HAVE TO have a look at the ft_hide_interrupt
* flag: it signals the non-interrupt level part of
* the driver that it has to wait for the fdc until it
* has completet seeking.
diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c
index dce372118..332de841c 100644
--- a/drivers/char/ftape/lowlevel/ftape_syms.c
+++ b/drivers/char/ftape/lowlevel/ftape_syms.c
@@ -20,7 +20,7 @@
* $Revision: 1.4 $
* $Date: 1997/10/17 00:03:51 $
*
- * This file contains the the symbols that the ftape low level
+ * This file contains the symbols that the ftape low level
* part of the QIC-40/80/3010/3020 floppy-tape driver "ftape"
* exports to it's high level clients
*/
diff --git a/drivers/char/ftape/zftape/zftape_syms.c b/drivers/char/ftape/zftape/zftape_syms.c
index 09e77bf10..139b19cf1 100644
--- a/drivers/char/ftape/zftape/zftape_syms.c
+++ b/drivers/char/ftape/zftape/zftape_syms.c
@@ -20,7 +20,7 @@
* $Revision: 1.3 $
* $Date: 1997/10/05 19:19:14 $
*
- * This file contains the the symbols that the zftape frontend to
+ * This file contains the symbols that the zftape frontend to
* the ftape floppy tape driver exports
*/
diff --git a/drivers/char/h8.c b/drivers/char/h8.c
index 73941a059..287698298 100644
--- a/drivers/char/h8.c
+++ b/drivers/char/h8.c
@@ -1,6 +1,4 @@
/*
- */
-/*
* Hitachi H8/337 Microcontroller driver
*
* The H8 is used to deal with the power and thermal environment
@@ -27,6 +25,7 @@
#include <linux/miscdevice.h>
#include <linux/lists.h>
#include <linux/ioport.h>
+#include <linux/poll.h>
#define __KERNEL_SYSCALLS__
#include <asm/unistd.h>
@@ -55,12 +54,6 @@ int h8_init(void);
int h8_display_blank(void);
int h8_display_unblank(void);
-static int h8_open(struct inode *, struct file *);
-static void h8_release(struct inode *, struct file *);
-static long h8_read(struct inode *, struct file *, char *, u_long);
-static int h8_select(struct inode *, struct file *, int, select_table *);
-static int h8_ioctl(struct inode *, struct file *, u_int, u_long);
-
static void h8_intr(int irq, void *dev_id, struct pt_regs *regs);
#ifdef CONFIG_PROC_FS
@@ -113,14 +106,14 @@ static char driver_version[] = "X0.0";/* no spaces */
static struct file_operations h8_fops = {
NULL, /* lseek */
- h8_read,
+ NULL,
NULL, /* write */
NULL, /* readdir */
- h8_select,
- h8_ioctl,
+ NULL,
+ NULL,
NULL, /* mmap */
- h8_open,
- h8_release,
+ NULL,
+ NULL,
NULL, /* fsync */
NULL /* fasync */
};
@@ -328,7 +321,7 @@ int init_module(void)
request_region(h8_base, 8, "h8");
#ifdef CONFIG_PROC_FS
- proc_register_dynamic(&proc_root, &h8_proc_entry);
+ proc_register(&proc_root, &h8_proc_entry);
#endif
QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
@@ -362,7 +355,7 @@ int h8_init(void)
printk("H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
#ifdef CONFIG_PROC_FS
- proc_register_dynamic(&proc_root, &h8_proc_entry);
+ proc_register(&proc_root, &h8_proc_entry);
#endif
misc_register(&h8_device);
@@ -439,38 +432,6 @@ int h8_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
}
#endif
-static long h8_read(struct inode *inode, struct file *fp, char *buf,
- u_long count)
-{
- printk("h8_read: IMPDEL\n");
- return 0;
-}
-
-static int h8_select(struct inode *inode, struct file *fp, int sel_type,
- select_table * wait)
-{
- printk("h8_select: IMPDEL\n");
- return 0;
-}
-
-static int h8_ioctl(struct inode * inode, struct file *filp,
- u_int cmd, u_long arg)
-{
- printk("h8_ioctl: IMPDEL\n");
- return 0;
-}
-
-static void h8_release(struct inode * inode, struct file * filp)
-{
- printk("h8_release: IMPDEL\n");
-}
-
-static int h8_open(struct inode * inode, struct file * filp)
-{
- printk("h8_open: IMPDEL\n");
- return 0;
-}
-
/* Called from console driver -- must make sure h8_enabled. */
int h8_display_blank(void)
{
@@ -775,7 +736,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
case H8_RD_SN:
case H8_RD_ENET_ADDR:
- printk("H8: Read ethernet addr - command done - address: %x - %x - %x - %x - %x - %x \n",
+ printk("H8: read Ethernet address: command done - address: %x - %x - %x - %x - %x - %x \n",
qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
@@ -908,7 +869,7 @@ h8_cmd_done(h8_cmd_q_t *qp)
}
/*
- * Retrieve the current cpu temperature and case temperature. Provides
+ * Retrieve the current CPU temperature and case temperature. Provides
* the feedback for the thermal control algorithm. Synchcronized via
* sleep() for priority so that no other actions in the process will take
* place before the data becomes available.
@@ -954,7 +915,7 @@ h8_get_max_temp(void)
/*
* Assigns an upper limit to the value of the H8 thermal interrupt.
* As an example setting a value of 115 F here will cause the
- * interrupt to trigger when the cpu temperature reaches 115 F.
+ * interrupt to trigger when the CPU temperature reaches 115 F.
*/
static void
h8_set_upper_therm_thold(int thold)
@@ -1072,7 +1033,7 @@ h8_monitor_thread(void * unused)
/*
* If an external DC supply is removed or added make
- * appropriate cpu speed adjustments.
+ * appropriate CPU speed adjustments.
*/
if (h8_event_mask & H8_MANAGE_BATTERY) {
h8_run_level_3_manage(H8_RUN);
@@ -1106,7 +1067,7 @@ h8_manage_therm(void)
h8_set_cpu_speed(h8_udamp);
h8_clear_event_mask(H8_MANAGE_UTHERM);
h8_set_event_mask(H8_MANAGE_LTHERM);
- /* Check again in 30 seconds for cpu temperature */
+ /* Check again in 30 seconds for CPU temperature */
h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
} else if (h8_event_mask & H8_MANAGE_LTHERM) {
/* See how cool the system has become as a result
@@ -1116,7 +1077,7 @@ h8_manage_therm(void)
if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
{
/* System cooling has progressed to a point
- that the cpu may be speeded up. */
+ that the CPU may be sped up. */
h8_set_upper_therm_thold(h8_uthermal_threshold);
h8_set_cpu_speed(h8_ldamp); /* adjustable */
if(h8_debug & 0x10)
@@ -1144,7 +1105,7 @@ h8_set_cpu_speed(int speed_divisor)
/*
* global_rpb_counter is consumed by alpha_delay() in determining just
* how much time to delay. It is necessary that the number of microseconds
- * in DELAY(n) be kept consistent over a variety of cpu clock speeds.
+ * in DELAY(n) be kept consistent over a variety of CPU clock speeds.
* To that end global_rpb_counter is here adjusted.
*/
@@ -1183,7 +1144,7 @@ h8_set_cpu_speed(int speed_divisor)
}
/*
- * Gets value stored in rpb representing cpu clock speed and adjusts this
+ * Gets value stored in rpb representing CPU clock speed and adjusts this
* value based on the current clock speed divisor.
*/
u_long
diff --git a/drivers/char/h8.h b/drivers/char/h8.h
index 533c4ece1..b59aadea8 100644
--- a/drivers/char/h8.h
+++ b/drivers/char/h8.h
@@ -183,7 +183,7 @@
#define H8_SYSTEM_DELAY_TEST 0x100000
#define H8_POWER_SWITCH_TEST 0x200000
-/* cpu speeds and clock divisor values */
+/* CPU speeds and clock divisor values */
#define MHZ_14 5
#define MHZ_28 4
#define MHZ_57 3
diff --git a/drivers/char/hfmodem/Makefile b/drivers/char/hfmodem/Makefile
index 42629693b..2219cd52e 100644
--- a/drivers/char/hfmodem/Makefile
+++ b/drivers/char/hfmodem/Makefile
@@ -25,7 +25,7 @@ all: all_targets
.PHONY: all
gentbl: gentbl.c
- $(HOSTCC) -Wall $< -o $@ -lm
+ $(HOSTCC) $(HOSTCFLAGS) $< -o $@ -lm
TBLHDR := tables.h
diff --git a/drivers/char/hfmodem/refclock.c b/drivers/char/hfmodem/refclock.c
index 6617673ca..2ca829fbf 100644
--- a/drivers/char/hfmodem/refclock.c
+++ b/drivers/char/hfmodem/refclock.c
@@ -30,6 +30,7 @@
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/hfmodem.h>
+#include <asm/processor.h>
/* --------------------------------------------------------------------- */
@@ -65,49 +66,13 @@ static int rdtsc_ok = 1;
/* --------------------------------------------------------------------- */
#ifdef __i386__
-
__initfunc(static void i386_capability(void))
{
- unsigned long flags;
- unsigned long fl1;
- union {
- struct {
- unsigned int ebx, edx, ecx;
- } r;
- unsigned char s[13];
- } id;
- unsigned int eax;
- unsigned int x86_capability;
-
- save_flags(flags);
- flags |= 0x200000;
- restore_flags(flags);
- save_flags(flags);
- fl1 = flags;
- flags &= ~0x200000;
- restore_flags(flags);
- save_flags(flags);
- if (!(fl1 & 0x200000) || (flags & 0x200000)) {
- printk(KERN_WARNING "%s: cpu does not support CPUID\n", hfmodem_drvname);
- return;
- }
- __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) :
- "0" (0));
- id.s[12] = 0;
- if (eax < 1) {
- printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability "
- "list\n", hfmodem_drvname, id.s);
- return;
- }
- printk(KERN_INFO "%s: cpu: vendor string %s ", hfmodem_drvname, id.s);
- __asm__ ("cpuid" : "=a" (eax), "=d" (x86_capability) : "0" (1) : "ebx", "ecx");
- printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15, eax & 15,
- x86_capability);
- if (x86_capability & 0x10)
+ if (boot_cpu_data.x86_capability & X86_FEATURE_TSC)
rdtsc_ok = 1;
else
printk(KERN_INFO "%s: cpu does not support the rdtsc instruction\n", hfmodem_drvname);
-}
+}
#endif /* __i386__ */
/* --------------------------------------------------------------------- */
diff --git a/drivers/char/i2c.c b/drivers/char/i2c.c
index 5507d94ba..9741f4be4 100644
--- a/drivers/char/i2c.c
+++ b/drivers/char/i2c.c
@@ -5,6 +5,7 @@
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -14,8 +15,7 @@
#include <linux/locks.h>
#include <linux/sched.h>
#include <linux/malloc.h>
-
-#include "i2c.h"
+#include <linux/i2c.h>
#define REGPRINT(x) if (verbose) (x)
#define I2C_DEBUG(x) if (i2c_debug) (x)
@@ -34,11 +34,18 @@ static struct i2c_bus *busses[I2C_BUS_MAX];
static struct i2c_driver *drivers[I2C_DRIVER_MAX];
static int bus_count = 0, driver_count = 0;
+extern int i2c_tuner_init(void);
+extern int msp3400c_init(void);
+
int i2c_init(void)
{
printk(KERN_INFO "i2c: initialized%s\n",
scan ? " (i2c bus scan enabled)" : "");
/* anything to do here ? */
+#ifdef CONFIG_VIDEO_BT848
+ i2c_tuner_init();
+ msp3400c_init();
+#endif
return 0;
}
diff --git a/drivers/char/i2c.h b/drivers/char/i2c.h
deleted file mode 100644
index 66aef224c..000000000
--- a/drivers/char/i2c.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef I2C_H
-#define I2C_H
-
-/*
- * linux i2c interface. Works a little bit like the scsi subsystem.
- * There are:
- *
- * i2c the basic control module (like scsi_mod)
- * bus driver a driver with a i2c bus (hostadapter driver)
- * chip driver a driver for a chip connected
- * to a i2c bus (cdrom/hd driver)
- *
- * A device will be attached to one bus and one chip driver. Every chip
- * driver gets a unique ID.
- *
- * A chip driver can provide a ioctl-like callback for the
- * communication with other parts of the kernel (not every i2c chip is
- * useful without other devices, a TV card tuner for example).
- *
- * "i2c internal" parts of the structs: only the i2c module is allowed to
- * write to them, for others they are read-only.
- *
- */
-
-#define I2C_BUS_MAX 4 /* max # of bus drivers */
-#define I2C_DRIVER_MAX 8 /* max # of chip drivers */
-#define I2C_DEVICE_MAX 8 /* max # if devices per bus/driver */
-
-struct i2c_bus;
-struct i2c_driver;
-struct i2c_device;
-
-#define I2C_DRIVERID_MSP3400 1
-#define I2C_DRIVERID_TUNER 2
-#define I2C_DRIVERID_VIDEOTEXT 3
-
-#define I2C_BUSID_BT848 1 /* I2C bus on a BT848 */
-
-/*
- * struct for a driver for a i2c chip (tuner, soundprocessor,
- * videotext, ... ).
- *
- * a driver will register within the i2c module. The i2c module will
- * callback the driver (i2c_attach) for every device it finds on a i2c
- * bus at the specified address. If the driver decides to "accept"
- * the, device, it must return a struct i2c_device, and NULL
- * otherwise.
- *
- * i2c_detach = i2c_attach ** -1
- *
- * i2c_command will be used to pass commands to the driver in a
- * ioctl-line manner.
- *
- */
-
-struct i2c_driver
-{
- char name[32]; /* some useful label */
- int id; /* device type ID */
- unsigned char addr_l, addr_h; /* address range of the chip */
-
- int (*attach)(struct i2c_device *device);
- int (*detach)(struct i2c_device *device);
- int (*command)(struct i2c_device *device,unsigned int cmd, void *arg);
-
- /* i2c internal */
- struct i2c_device *devices[I2C_DEVICE_MAX];
- int devcount;
-};
-
-
-/*
- * this holds the informations about a i2c bus available in the system.
- *
- * a chip with a i2c bus interface (like bt848) registers the bus within
- * the i2c module. This struct provides functions to access the i2c bus.
- *
- * One must hold the spinlock to access the i2c bus (XXX: is the irqsave
- * required? Maybe better use a semaphore?).
- * [-AC-] having a spinlock_irqsave is only needed if we have drivers wishing
- * to bang their i2c bus from an interrupt.
- *
- * attach/detach_inform is a callback to inform the bus driver about
- * attached chip drivers.
- *
- */
-
-/* needed: unsigned long flags */
-
-#define LOCK_I2C_BUS(bus) spin_lock_irqsave(&(bus->bus_lock),flags);
-#define UNLOCK_I2C_BUS(bus) spin_unlock_irqrestore(&(bus->bus_lock),flags);
-
-struct i2c_bus
-{
- char name[32]; /* some useful label */
- int id;
- void *data; /* free for use by the bus driver */
-
- spinlock_t bus_lock;
-
- /* attach/detach inform callbacks */
- void (*attach_inform)(struct i2c_bus *bus, int id);
- void (*detach_inform)(struct i2c_bus *bus, int id);
-
- /* Software I2C */
- void (*i2c_setlines)(struct i2c_bus *bus, int ctrl, int data);
- int (*i2c_getdataline)(struct i2c_bus *bus);
-
- /* Hardware I2C */
- int (*i2c_read)(struct i2c_bus *bus, unsigned char addr);
- int (*i2c_write)(struct i2c_bus *bus, unsigned char addr,
- unsigned char b1, unsigned char b2, int both);
-
- /* internal data for i2c module */
- struct i2c_device *devices[I2C_DEVICE_MAX];
- int devcount;
-};
-
-
-/*
- * This holds per-device data for a i2c device
- */
-
-struct i2c_device
-{
- char name[32]; /* some useful label */
- void *data; /* free for use by the chip driver */
- unsigned char addr; /* chip addr */
-
- /* i2c internal */
- struct i2c_bus *bus;
- struct i2c_driver *driver;
-};
-
-
-/* ------------------------------------------------------------------- */
-/* i2c module functions */
-
-/* register/unregister a i2c bus */
-int i2c_register_bus(struct i2c_bus *bus);
-int i2c_unregister_bus(struct i2c_bus *bus);
-
-/* register/unregister a chip driver */
-int i2c_register_driver(struct i2c_driver *driver);
-int i2c_unregister_driver(struct i2c_driver *driver);
-
-/* send a command to a chip using the ioctl-like callback interface */
-int i2c_control_device(struct i2c_bus *bus, int id,
- unsigned int cmd, void *arg);
-
-/* i2c bus access functions */
-void i2c_start(struct i2c_bus *bus);
-void i2c_stop(struct i2c_bus *bus);
-void i2c_one(struct i2c_bus *bus);
-void i2c_zero(struct i2c_bus *bus);
-int i2c_ack(struct i2c_bus *bus);
-
-int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack);
-unsigned char i2c_readbyte(struct i2c_bus *bus,int last);
-
-/* i2c (maybe) hardware functions */
-int i2c_read(struct i2c_bus *bus, unsigned char addr);
-int i2c_write(struct i2c_bus *bus, unsigned char addr,
- unsigned char b1, unsigned char b2, int both);
-
-#endif /* I2C_H */
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 404f9c88c..b41dd0690 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -170,7 +170,7 @@ static int stli_nrbrds = sizeof(stli_brdconf) / sizeof(stlconf_t);
*/
static char *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver";
static char *stli_drvname = "istallion";
-static char *stli_drvversion = "5.4.5";
+static char *stli_drvversion = "5.4.6";
static char *stli_serialname = "ttyE";
static char *stli_calloutname = "cue";
@@ -1425,12 +1425,12 @@ static int stli_write(struct tty_struct *tty, int from_user, const unsigned char
(tail - head - 1);
count = MIN(len, count);
EBRDDISABLE(brdp);
+ restore_flags(flags);
down(&stli_tmpwritesem);
copy_from_user(stli_tmpwritebuf, chbuf, count);
up(&stli_tmpwritesem);
chbuf = &stli_tmpwritebuf[0];
- restore_flags(flags);
}
/*
@@ -3361,7 +3361,6 @@ static void stli_ecpmcreset(stlibrd_t *brdp)
static void stli_onbinit(stlibrd_t *brdp)
{
unsigned long memconf;
- int i;
#if DEBUG
printk("stli_onbinit(brdp=%d)\n", (int) brdp);
@@ -3370,13 +3369,12 @@ static void stli_onbinit(stlibrd_t *brdp)
outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
udelay(10);
outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
memconf = (brdp->memaddr & ONB_ATADDRMASK) >> ONB_ATADDRSHFT;
outb(memconf, (brdp->iobase + ONB_ATMEMAR));
outb(0x1, brdp->iobase);
- udelay(1000);
+ mdelay(1);
}
/*****************************************************************************/
@@ -3425,7 +3423,6 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_onbreset(stlibrd_t *brdp)
{
- int i;
#if DEBUG
printk("stli_onbreset(brdp=%x)\n", (int) brdp);
@@ -3434,8 +3431,7 @@ static void stli_onbreset(stlibrd_t *brdp)
outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
udelay(10);
outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
}
/*****************************************************************************/
@@ -3447,7 +3443,6 @@ static void stli_onbreset(stlibrd_t *brdp)
static void stli_onbeinit(stlibrd_t *brdp)
{
unsigned long memconf;
- int i;
#if DEBUG
printk("stli_onbeinit(brdp=%d)\n", (int) brdp);
@@ -3457,15 +3452,14 @@ static void stli_onbeinit(stlibrd_t *brdp)
outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
udelay(10);
outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
memconf = (brdp->memaddr & ONB_EIADDRMASKL) >> ONB_EIADDRSHFTL;
outb(memconf, (brdp->iobase + ONB_EIMEMARL));
memconf = (brdp->memaddr & ONB_EIADDRMASKH) >> ONB_EIADDRSHFTH;
outb(memconf, (brdp->iobase + ONB_EIMEMARH));
outb(0x1, brdp->iobase);
- udelay(1000);
+ mdelay(1);
}
/*****************************************************************************/
@@ -3521,7 +3515,6 @@ static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_onbereset(stlibrd_t *brdp)
{
- int i;
#if DEBUG
printk("stli_onbereset(brdp=%x)\n", (int) brdp);
@@ -3530,8 +3523,7 @@ static void stli_onbereset(stlibrd_t *brdp)
outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
udelay(10);
outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
}
/*****************************************************************************/
@@ -3542,7 +3534,6 @@ static void stli_onbereset(stlibrd_t *brdp)
static void stli_bbyinit(stlibrd_t *brdp)
{
- int i;
#if DEBUG
printk("stli_bbyinit(brdp=%d)\n", (int) brdp);
@@ -3551,10 +3542,9 @@ static void stli_bbyinit(stlibrd_t *brdp)
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
outb(0, (brdp->iobase + BBY_ATCONFR));
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
outb(0x1, brdp->iobase);
- udelay(1000);
+ mdelay(1);
}
/*****************************************************************************/
@@ -3587,7 +3577,6 @@ static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_bbyreset(stlibrd_t *brdp)
{
- int i;
#if DEBUG
printk("stli_bbyreset(brdp=%x)\n", (int) brdp);
@@ -3596,8 +3585,7 @@ static void stli_bbyreset(stlibrd_t *brdp)
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
outb(0, (brdp->iobase + BBY_ATCONFR));
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
}
/*****************************************************************************/
@@ -3608,15 +3596,13 @@ static void stli_bbyreset(stlibrd_t *brdp)
static void stli_stalinit(stlibrd_t *brdp)
{
- int i;
#if DEBUG
printk("stli_stalinit(brdp=%d)\n", (int) brdp);
#endif
outb(0x1, brdp->iobase);
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
}
/*****************************************************************************/
@@ -3646,7 +3632,6 @@ static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_stalreset(stlibrd_t *brdp)
{
volatile unsigned long *vecp;
- int i;
#if DEBUG
printk("stli_stalreset(brdp=%x)\n", (int) brdp);
@@ -3655,8 +3640,7 @@ static void stli_stalreset(stlibrd_t *brdp)
vecp = (volatile unsigned long *) (brdp->membase + 0x30);
*vecp = 0xffff0000;
outb(0, brdp->iobase);
- for (i = 0; (i < 1000); i++)
- udelay(1000);
+ mdelay(1000);
}
/*****************************************************************************/
@@ -4167,10 +4151,9 @@ static inline int stli_eisamemprobe(stlibrd_t *brdp)
outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
udelay(10);
outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
- for (i = 0; (i < 100); i++)
- udelay(1000);
+ mdelay(100);
outb(0x1, brdp->iobase);
- udelay(1000);
+ mdelay(1);
stli_onbeenable(brdp);
} else {
return(-ENODEV);
diff --git a/drivers/char/joystick.c b/drivers/char/joystick.c
index 4994dabb4..25a7c2b47 100644
--- a/drivers/char/joystick.c
+++ b/drivers/char/joystick.c
@@ -1,13 +1,12 @@
/*
- * $Id: joystick.c,v 1.3 1997/12/16 05:35:12 ralf Exp $
- *
- * Copyright (C) 1997 Vojtech Pavlik
+ * linux/drivers/char/joystick.c Version 1.0.9
+ * Copyright (C) 1996-1998 Vojtech Pavlik
*/
/*
- * This is joystick driver for Linux. It supports up to two analog joysticks
- * on a PC compatible machine. See Documentation/joystick.txt for changelog
- * and credits.
+ * This is joystick driver for Linux. It supports up to two analog joysticks
+ * on a PC compatible machine. See Documentation/joystick.txt for changelog
+ * and credits.
*/
#include <linux/init.h>
@@ -15,30 +14,25 @@
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/mm.h>
-#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
#include <linux/poll.h>
#include <linux/major.h>
#include <linux/joystick.h>
-
#include <asm/io.h>
-#include <asm/ptrace.h>
-#include <asm/uaccess.h>
-#include <asm/param.h>
#define PIT_HZ 1193180L /* PIT clock is 1.19318 MHz */
#define JS_MAXTIME PIT_HZ/250 /* timeout for read (4 ms) */
-#define JS_BUTTON_PERIOD HZ/50 /* button valid time (20 ms) */
-#define JS_AXIS_MIN_PERIOD HZ/25 /* axis min valid time (40 ms) */
-#define JS_AXIS_MAX_PERIOD HZ/25*2 /* axis max valid time (80 ms) */
+#define JS_TIMER_PERIOD HZ/50 /* button valid time (20 ms) */
+#define JS_BH_MIN_PERIOD HZ/25 /* axis min valid time (40 ms) */
+#define JS_BH_MAX_PERIOD HZ/25*2 /* axis max valid time (80 ms) */
-#define JS_FIFO_SIZE 16 /* number of FIFO entries */
+#define JS_FIFO_SIZE 16 /* number of FIFO entries */
#define JS_BUFF_SIZE 32 /* output buffer size */
-#define JS_RETRIES 4 /* number of retries */
-#define JS_DEF_PREC 8 /* initial precision for all axes */
+#define JS_RETRIES 4 /* number of retries */
+#define JS_DEF_PREC 16 /* initial precision for all axes */
#define JS_NUM 2 /* number of joysticks */
@@ -49,7 +43,7 @@
#define PIT_DATA 0x40 /* timer 0 data port */
#define JS_PORT 0x201 /* joystick port */
-#define JS_TRIGGER 0xff /* triggers one-shots */
+#define JS_TRIGGER 0xff /* triggers one-shots */
#define PIT_READ_TIMER 0x00 /* to read timer 0 */
#define DELTA(X,Y,Z) ((X)-(Y)+(((X)>=(Y))?0:Z)) /* cyclic delta */
@@ -95,7 +89,7 @@ static unsigned char js_fifo_tail = JS_FIFO_SIZE - 1; /* tail of the fifo */
static struct js_fifo js_fifo[JS_FIFO_SIZE]; /* the fifo */
static unsigned char js_last_buttons = 0; /* last read button state */
-static unsigned long js_axis_time = 0; /* last read axis time */
+static unsigned long js_bh_time = 0; /* last read axis time */
static unsigned long js_mark_time = 0;
static unsigned char js_axes_exist; /* all axes that exist */
@@ -106,7 +100,7 @@ static unsigned int js_buttons = 0;
MODULE_AUTHOR("Vojtech Pavlik <vojtech@atrey.karlin.mff.cuni.cz>");
MODULE_SUPPORTED_DEVICE("js");
-MODULE_PARM(js, "0-1b");
+MODULE_PARM(js, "1-2b");
static char js[] = {0, 0};
@@ -118,7 +112,7 @@ static char js[] = {0, 0};
static inline int get_pit(void)
{
int t, flags;
-
+
save_flags(flags);
cli();
outb(PIT_READ_TIMER, PIT_MODE);
@@ -132,12 +126,14 @@ static inline int get_pit(void)
* count_bits() counts set bits in a byte.
*/
-static int count_bits(unsigned char c)
+static int count_bits(unsigned int c)
{
- int i, t = 0;
- for (i = 0; i < 8; i++)
- if (c & (1 << i)) t++;
- return t;
+ int i = 0;
+ while (c) {
+ i += c & 1;
+ c >>= 1;
+ }
+ return i;
}
/*
@@ -149,36 +145,34 @@ static int js_correct(int value, struct js_corr *corr)
int t;
if (corr->type == JS_CORR_NONE) return value;
- t = value > corr->coef[0] ? (value < corr->coef[1] ? corr->coef[0] : value - corr->coef[1] + corr->coef[0]) : value;
- if (t == corr->coef[0]) return 32768;
+ t = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : value - corr->coef[1]) : value - corr->coef[0];
switch (corr->type) {
case JS_CORR_BROKEN:
- t = t < corr->coef[0] ? ((corr->coef[2] * t) >> 14) + corr->coef[3] :
- ((corr->coef[4] * t) >> 14) + corr->coef[5];
+ t = t < 0 ? ((corr->coef[2] * t) >> 14) : ((corr->coef[3] * t) >> 14);
break;
- default:
+ default:
return 0;
}
- if (t < 0) return 0;
- if (t > 65535) return 65535;
+ if (t < -32767) return -32767;
+ if (t > 32767) return 32767;
- return t;
+ return t;
}
/*
- * js_compare() compares two close axis values and decides
+ * js_compare() compares two close axis values and decides
* whether they are "same".
*/
static int js_compare(int x, int y, int prec)
{
- return (x < y + prec) && (y < x + prec);
+ return (x < y + prec) && (y < x + prec);
}
/*
- * js_probe() probes for joysticks
+ * js_probe() probes for joysticks
*/
inline int js_probe(void)
@@ -196,10 +190,10 @@ inline int js_probe(void)
} else
switch (t & JS_AXES) {
case 0x0c: jsd[0].exist = 0x33; jsd[1].exist = 0x00; break; /* joystick 0 connected */
- case 0x03: jsd[0].exist = 0x00; jsd[1].exist = 0xcc; break; /* joystick 1 connected */
+ case 0x03: jsd[0].exist = 0xcc; jsd[1].exist = 0x00; break; /* joystick 1 connected */
case 0x04: jsd[0].exist = 0xfb; jsd[1].exist = 0x00; break; /* 3-axis joystick connected */
case 0x00: jsd[0].exist = 0x33; jsd[1].exist = 0xcc; break; /* joysticks 0 and 1 connected */
- default: jsd[0].exist = 0x00; jsd[1].exist = 0x00; return -1; /* no joysticks */
+ default: jsd[0].exist = 0x00; jsd[1].exist = 0x00; return -1; /* no joysticks */
}
js_axes_exist = (jsd[0].exist | jsd[1].exist) & JS_AXES;
@@ -208,7 +202,7 @@ inline int js_probe(void)
return 0;
}
-/*
+/*
* js_do_timer() controls the action by adding entries to the event
* fifo each time a button changes its state or axis valid time
* expires.
@@ -226,16 +220,61 @@ static void js_do_timer(unsigned long data)
js_mark_time = jiffies;
mark_bh(JS_BH);
}
- }
+ }
else
- if ((jiffies > js_axis_time + JS_AXIS_MAX_PERIOD) && !js_mark_time) {
+ if ((jiffies > js_bh_time + JS_BH_MAX_PERIOD) && !js_mark_time) {
js_mark_time = jiffies;
mark_bh(JS_BH);
}
- js_timer.expires = jiffies + JS_BUTTON_PERIOD;
+ js_timer.expires = jiffies + JS_TIMER_PERIOD;
add_timer(&js_timer);
}
+
+/*
+ * Put an event in the buffer. This requires additional queue processing
+ * done by js_sync_buff, otherwise the buffer will be corrupted.
+ */
+
+static void js_add_event(int i, __u32 time, __u8 type, __u8 number, __u16 value)
+{
+ int ahead = jsd[i].ahead++;
+ jsd[i].buff[ahead].time = time;
+ jsd[i].buff[ahead].type = type;
+ jsd[i].buff[ahead].number = number;
+ jsd[i].buff[ahead].value = value;
+ if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead=0;
+}
+
+/*
+ * This checks for all owerflows caused by recent additions to the buffer.
+ * It does anything only if some processes are reading the data too slowly.
+ */
+
+static void js_sync_buff(void)
+{
+ int i;
+
+ for (i = 0; i < JS_NUM; i++)
+ if (jsd[i].list)
+ if (jsd[i].bhead != jsd[i].ahead) {
+ if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) {
+ struct js_list *curl;
+ curl = jsd[i].list;
+ while (curl) {
+ if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) {
+ curl->tail = jsd[i].ahead;
+ curl->startup = jsd[i].exist;
+ }
+ curl = curl->next;
+ }
+ jsd[i].tail = jsd[i].ahead;
+ }
+ jsd[i].bhead = jsd[i].ahead;
+ wake_up_interruptible(&jsd[i].wait);
+ }
+}
+
/*
* js_do_bh() does the main processing and adds events to output buffers.
*/
@@ -246,7 +285,7 @@ static void js_do_bh(void)
int i, j, k;
unsigned int t;
- if (jiffies > js_axis_time + JS_AXIS_MIN_PERIOD) {
+ if (jiffies > js_bh_time + JS_BH_MIN_PERIOD) {
unsigned int old_axis[4];
unsigned int t_low, t_high;
@@ -274,8 +313,8 @@ static void js_do_bh(void)
cli(); /* no interrupts */
outb(JS_TRIGGER, JS_PORT); /* trigger one-shots */
outb(PIT_READ_TIMER, PIT_MODE); /* read timer */
- t = (t1l = inb(PIT_DATA)) |
- (t1h = inb(PIT_DATA)) << 8;
+ t = (t1l = inb(PIT_DATA)) |
+ (t1h = inb(PIT_DATA)) << 8;
restore_flags(flags);
do {
@@ -286,7 +325,7 @@ static void js_do_bh(void)
joy_state = (joy_state << 8) | jss;
i++;
}
-
+
cli();
outb(PIT_READ_TIMER, PIT_MODE);
t1l = inb(PIT_DATA);
@@ -299,15 +338,15 @@ static void js_do_bh(void)
* Process the gathered axis data in joy_state.
*/
- joy_state ^= ((joy_state >> 8) | 0xff000000L); /* More magic */
+ joy_state ^= ((joy_state >> 8) | 0xff000000L); /* More magic */
for (; i > 0; i--) {
for (j = 0; j < 4; j++)
if (joy_state & js_axes_exist & (1 << j)) {
- jsm = js_correct(DELTA_TX(t, t_low, t_high), &js_axis[j].corr);
+ jsm = DELTA_TX(t, t_low, t_high);
if (!js_compare(jsm, js_axis[j].value, js_axis[j].corr.prec)) {
if (jsm < js_axis[j].value || !retries)
- js_axis[j].value = jsm;
+ js_axis[j].value = jsm;
again = 1;
}
}
@@ -316,7 +355,7 @@ static void js_do_bh(void)
t_high = t_high >> 8;
}
- } while (retries++ < JS_RETRIES && again);
+ } while (retries++ < JS_RETRIES && again);
/*
* Check if joystick lost.
@@ -348,18 +387,13 @@ static void js_do_bh(void)
k = 0;
for (j = 0; j < 4; j++)
if ((1 << j) & jsd[i].exist) {
- if (!js_compare(js_axis[j].value, old_axis[j], js_axis[j].corr.prec)) {
- jsd[i].buff[jsd[i].ahead].time = js_mark_time;
- jsd[i].buff[jsd[i].ahead].type = JS_EVENT_AXIS;
- jsd[i].buff[jsd[i].ahead].number = k;
- jsd[i].buff[jsd[i].ahead].value = js_axis[j].value;
- jsd[i].ahead++;
- if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0;
- }
+ if ((t = js_correct(js_axis[j].value, &js_axis[j].corr)) !=
+ js_correct(old_axis[j], &js_axis[j].corr))
+ js_add_event(i, js_mark_time, JS_EVENT_AXIS, k, t);
k++;
}
}
- js_axis_time = jiffies;
+ js_bh_time = jiffies;
}
js_mark_time = 0;
@@ -373,14 +407,8 @@ static void js_do_bh(void)
k = 0;
for (j = 4; j < 8; j++)
if ((1 << j) & jsd[i].exist) {
- if ((1 << j) & (js_buttons ^ js_fifo[t].event)) {
- jsd[i].buff[jsd[i].ahead].time = js_fifo[t].time;
- jsd[i].buff[jsd[i].ahead].type = JS_EVENT_BUTTON;
- jsd[i].buff[jsd[i].ahead].number = k;
- jsd[i].buff[jsd[i].ahead].value = (js_fifo[t].event >> j) & 1;
- jsd[i].ahead++;
- if (jsd[i].ahead == JS_BUFF_SIZE) jsd[i].ahead = 0;
- }
+ if ((1 << j) & (js_buttons ^ js_fifo[t].event))
+ js_add_event(i, js_fifo[t].time, JS_EVENT_BUTTON, k, (js_fifo[t].event >> j) & 1);
k++;
}
}
@@ -388,27 +416,10 @@ static void js_do_bh(void)
}
/*
- * Sync ahead with bhead and cut too long tails.
+ * Synchronize the buffer.
*/
-
- for (i = 0; i < JS_NUM; i++)
- if (jsd[i].list)
- if (jsd[i].bhead != jsd[i].ahead) {
- if (ROT(jsd[i].bhead, jsd[i].tail, jsd[i].ahead) || (jsd[i].tail == jsd[i].bhead)) {
- struct js_list *curl;
- curl = jsd[i].list;
- while (curl) {
- if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) {
- curl->tail = jsd[i].ahead;
- curl->startup = jsd[i].exist;
- }
- curl = curl->next;
- }
- jsd[i].tail = jsd[i].ahead;
- }
- jsd[i].bhead = jsd[i].ahead;
- wake_up_interruptible(&jsd[i].wait);
- }
+
+ js_sync_buff();
}
@@ -435,7 +446,7 @@ static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
unsigned long blocks = count / sizeof(struct js_event);
unsigned long i = 0, j;
int t, u = curl->tail;
- int retval = 0;
+ int retval = 0;
/*
* Check user data.
@@ -459,38 +470,46 @@ static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
* Handle (non)blocking i/o.
*/
- if (count != sizeof(struct JS_DATA_TYPE)) {
- if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) {
- add_wait_queue(&jsd[minor].wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
- while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup) || (curl->startup && !js_axis_time)) {
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- if (!jsd[minor].exist) {
- retval = -ENODEV;
- break;
- }
+ if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE))
+ || (curl->startup && !js_bh_time)) {
+
+ add_wait_queue(&jsd[minor].wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE))
+ || (curl->startup && !js_bh_time)) {
+
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ if (!jsd[minor].exist) {
+ retval = -ENODEV;
+ break;
}
- current->state = TASK_RUNNING;
- remove_wait_queue(&jsd[minor].wait, &wait);
}
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&jsd[minor].wait, &wait);
+ }
+
+ if (retval) return retval;
- if (retval) return retval;
-
/*
* Do the i/o.
*/
+ if (count != sizeof(struct JS_DATA_TYPE)) {
if (curl->startup) {
struct js_event tmpevent;
+/*
+ * Initial button state.
+ */
t = 0;
for (j = 0; j < 4 && (i < blocks) && !retval; j++)
@@ -498,17 +517,21 @@ static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
if (curl->startup & (1 << j)) {
tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT;
tmpevent.number = t;
- tmpevent.value = js_axis[j].value;
- if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event)))
+ tmpevent.value = js_correct(js_axis[j].value, &js_axis[j].corr);
+ if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event)))
retval = -EFAULT;
if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time))
retval = -EFAULT;
curl->startup &= ~(1 << j);
i++;
}
- t++;
+ t++;
}
+/*
+ * Initial axis state.
+ */
+
t = 0;
for (j = 4; j < 8 && (i < blocks) && !retval; j++)
if (jsd[minor].exist & (1 << j)) {
@@ -516,17 +539,20 @@ static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
tmpevent.number = t;
tmpevent.value = (js_buttons >> j) & 1;
- if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event)))
+ if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event)))
retval = -EFAULT;
if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time))
retval = -EFAULT;
curl->startup &= ~(1 << j);
i++;
}
- t++;
+ t++;
}
}
+/*
+ * Buffer data.
+ */
while ((jsd[minor].ahead != (t = GOF(curl->tail))) && (i < blocks) && !retval) {
if (copy_to_user(&buff[i], &jsd[minor].buff[t], sizeof(struct js_event)))
@@ -536,7 +562,7 @@ static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
curl->tail = t;
i++;
}
-
+
}
else
@@ -562,6 +588,7 @@ static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
buttons |= (!!(js_last_buttons & (1 << j))) << (i++);
copy_to_user(&bufo->buttons, &buttons, sizeof(int));
+ curl->startup = 0;
curl->tail = GOB(jsd[minor].ahead);
retval = sizeof(struct JS_DATA_TYPE);
}
@@ -580,7 +607,7 @@ static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
}
if (!curl) jsd[minor].tail = t;
}
-
+
return retval ? retval : i*sizeof(struct js_event);
}
@@ -595,19 +622,16 @@ static unsigned int js_poll(struct file *file, poll_table *wait)
curl = file->private_data;
poll_wait(file, &jsd[minor].wait, wait);
- if (GOF(curl->tail) != jsd[minor].ahead)
+ if (GOF(curl->tail) != jsd[minor].ahead)
return POLLIN | POLLRDNORM;
- return 0;
+ return 0;
}
/*
* js_ioctl handles misc ioctl calls.
*/
-static int js_ioctl(struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
+static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned int minor = MINOR(inode->i_rdev);
int i, j;
@@ -637,13 +661,13 @@ static int js_ioctl(struct inode *inode,
sizeof(struct js_corr))) return -EFAULT;
j++;
}
- js_axis_time = 0;
+ js_bh_time = 0;
break;
case JSIOCGCORR:
j = 0;
for (i = 0; i < 4; i++)
if ((1 << i) & jsd[minor].exist) {
- if (copy_to_user((void *) arg + j * sizeof(struct js_corr), &js_axis[i].corr,
+ if (copy_to_user((void *) arg + j * sizeof(struct js_corr), &js_axis[i].corr,
sizeof(struct js_corr))) return -EFAULT;
j++;
}
@@ -651,7 +675,7 @@ static int js_ioctl(struct inode *inode,
default:
return -EINVAL;
}
-
+
return 0;
}
@@ -672,15 +696,15 @@ static int js_open(struct inode *inode, struct file *file)
return -ENODEV;
if (!jsd[minor].exist) {
js_probe();
- if (jsd[minor].exist) printk(KERN_INFO "js%d: %d-axis joystick at %#x\n",
- minor, count_bits(jsd[minor].exist & JS_AXES), JS_PORT);
+ if (jsd[minor].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n",
+ minor, count_bits(jsd[minor].exist & JS_AXES), count_bits(jsd[minor].exist & JS_BUTTONS), JS_PORT);
else return -ENODEV;
}
MOD_INC_USE_COUNT;
- if (!jsd[0].list && !jsd[1].list) {
- js_timer.expires = jiffies + JS_BUTTON_PERIOD;
+ if (!jsd[0].list && !jsd[1].list) {
+ js_timer.expires = jiffies + JS_TIMER_PERIOD;
add_timer(&js_timer);
}
@@ -760,7 +784,7 @@ __initfunc(void js_setup(char *str, int *ints))
{
js[0] = ((ints[0] > 0) ? ints[1] : 0 );
- js[1] = ((ints[0] > 1) ? ints[2] : 0 );
+ js[1] = ((ints[0] > 1) ? ints[2] : 0 );
}
#endif
@@ -770,7 +794,7 @@ __initfunc(void js_setup(char *str, int *ints))
*/
#ifdef MODULE
-int init_module(void)
+int init_module(void)
#else
__initfunc(int js_init(void))
#endif
@@ -793,8 +817,8 @@ __initfunc(int js_init(void))
}
for (i = 0; i < JS_NUM; i++) {
- if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis joystick at %#x\n",
- i, count_bits(jsd[i].exist & JS_AXES), JS_PORT);
+ if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n",
+ i, count_bits(jsd[i].exist & JS_AXES), count_bits(jsd[i].exist & JS_BUTTONS), JS_PORT);
jsd[i].ahead = jsd[i].bhead = 0;
jsd[i].tail = JS_BUFF_SIZE - 1;
jsd[i].list = NULL;
@@ -803,7 +827,7 @@ __initfunc(int js_init(void))
}
for (i = 0; i < 4; i++) {
- js_axis[i].corr.type = JS_CORR_NONE;
+ js_axis[i].corr.type = JS_CORR_NONE;
js_axis[i].corr.prec = JS_DEF_PREC;
}
@@ -812,7 +836,7 @@ __initfunc(int js_init(void))
enable_bh(JS_BH);
init_timer(&js_timer);
js_timer.function = js_do_timer;
-
+
return 0;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index d2aa0509e..8804df949 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -12,6 +12,7 @@
* Added decr/incr_console, dynamic keymaps, Unicode support,
* dynamic function/string keys, led setting, Sept 1994
* `Sticky' modifier keys, 951006.
+ *
* 11-11-96: SAK should now work in the raw mode (Martin Mares)
*
* Modified to provide 'generic' keyboard support by Hamish Macdonald
@@ -19,6 +20,7 @@
* parts by Geert Uytterhoeven, May 1997
*
* 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
+ * 30-07-98: Dead keys redone, aeb@cwi.nl.
*/
#include <linux/config.h>
@@ -58,9 +60,6 @@
#endif
extern void ctrl_alt_del(void);
-extern void reset_vc(unsigned int new_console);
-extern void scrollback(int);
-extern void scrollfront(int);
struct wait_queue * keypress_wait = NULL;
struct console;
@@ -104,12 +103,13 @@ typedef void (k_handfn)(unsigned char value, char up_flag);
static k_handfn
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_ignore;
+ do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
+ do_ignore;
static k_hand key_handler[16] = {
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock, do_lowercase, do_slock,
- do_ignore, do_ignore, do_ignore
+ do_meta, do_ascii, do_lock, do_lowercase, do_slock, do_dead2,
+ do_ignore, do_ignore
};
/* Key types processed even in raw modes */
@@ -138,12 +138,13 @@ const int max_vals[] = {
255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1,
NR_DEAD - 1, 255, 3, NR_SHIFT - 1,
255, NR_ASCII - 1, NR_LOCK - 1, 255,
- NR_LOCK - 1
+ NR_LOCK - 1, 255
};
const int NR_TYPES = SIZE(max_vals);
-static void put_queue(int);
+/* N.B. drivers/macintosh/mac_keyb.c needs to call put_queue */
+void put_queue(int);
static unsigned char handle_diacr(unsigned char);
/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
@@ -199,7 +200,7 @@ void handle_scancode(unsigned char scancode)
mark_bh(CONSOLE_BH);
add_keyboard_randomness(scancode);
- tty = ttytab[fg_console];
+ tty = ttytab? ttytab[fg_console]: NULL;
kbd = kbd_table + fg_console;
if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
put_queue(scancode);
@@ -315,7 +316,7 @@ void handle_scancode(unsigned char scancode)
#ifdef CONFIG_FORWARD_KEYBOARD
extern int forward_chars;
-static void put_queue(int ch)
+void put_queue(int ch)
{
if (forward_chars == fg_console+1){
kbd_forward_char (ch);
@@ -323,17 +324,17 @@ static void put_queue(int ch)
wake_up(&keypress_wait);
if (tty) {
tty_insert_flip_char(tty, ch, 0);
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
}
}
#else
-static void put_queue(int ch)
+void put_queue(int ch)
{
wake_up(&keypress_wait);
if (tty) {
tty_insert_flip_char(tty, ch, 0);
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
}
#endif
@@ -348,7 +349,7 @@ static void puts_queue(char *cp)
tty_insert_flip_char(tty, *cp, 0);
cp++;
}
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
static void applkey(int key, char mode)
@@ -362,6 +363,10 @@ static void applkey(int key, char mode)
static void enter(void)
{
+ if (diacr) {
+ put_queue(diacr);
+ diacr = 0;
+ }
put_queue(13);
if (vc_kbd_mode(kbd,VC_CRLF))
put_queue(10);
@@ -460,7 +465,7 @@ static void send_intr(void)
if (!tty)
return;
tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
+ con_schedule_flip(tty);
}
static void scroll_forw(void)
@@ -558,41 +563,49 @@ static void do_self(unsigned char value, char up_flag)
static unsigned char ret_diacr[NR_DEAD] =
{A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER, A_CEDIL };
-/* If a dead key pressed twice, output a character corresponding to it, */
-/* otherwise just remember the dead key. */
-
+/* Obsolete - for backwards compatibility only */
static void do_dead(unsigned char value, char up_flag)
{
+ value = ret_diacr[value];
+ do_dead2(value,up_flag);
+}
+
+/*
+ * Handle dead key. Note that we now may have several
+ * dead keys modifying the same character. Very useful
+ * for Vietnamese.
+ */
+static void do_dead2(unsigned char value, char up_flag)
+{
if (up_flag)
return;
- value = ret_diacr[value];
- if (diacr == value) { /* pressed twice */
- diacr = 0;
- put_queue(value);
- return;
- }
- diacr = value;
+ diacr = (diacr ? handle_diacr(value) : value);
}
-/* If space is pressed, return the character corresponding the pending */
-/* dead key, otherwise try to combine the two. */
-
+/*
+ * We have a combining character DIACR here, followed by the character CH.
+ * If the combination occurs in the table, return the corresponding value.
+ * Otherwise, if CH is a space or equals DIACR, return DIACR.
+ * Otherwise, conclude that DIACR was not combining after all,
+ * queue it and return CH.
+ */
unsigned char handle_diacr(unsigned char ch)
{
int d = diacr;
int i;
diacr = 0;
- if (ch == ' ')
- return d;
for (i = 0; i < accent_table_size; i++) {
if (accent_table[i].diacr == d && accent_table[i].base == ch)
return accent_table[i].result;
}
+ if (ch == ' ' || ch == d)
+ return d;
+
put_queue(d);
return ch;
}
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 7df3eb655..1036f1046 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -16,6 +16,8 @@
* Parport sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
* Fixed kernel_(to/from)_user memory copy to check for errors
* by Riccardo Facchetti <fizban@tin.it>
+ * Interrupt handling workaround for printers with buggy handshake
+ * by Andrea Arcangeli, 11 May 98
*/
/* This driver should, in theory, work with any parallel port that has an
@@ -62,6 +64,23 @@
* can force it using the parameters described above.
*/
+/*
+ * The new interrupt handling code take care of the buggy handshake
+ * of some HP and Epson printer:
+ * ___
+ * ACK _______________ ___________
+ * |__|
+ * ____
+ * BUSY _________ _______
+ * |____________|
+ *
+ * I discovered this using the printer scanner that you can find at:
+ *
+ * ftp://e-mind.com/pub/linux/pscan/
+ *
+ * 11 May 98, Andrea Arcangeli
+ */
+
#include <linux/module.h>
#include <linux/init.h>
@@ -93,7 +112,7 @@ struct lp_struct lp_table[LP_NO] =
#ifdef LP_STATS
0, 0, {0},
#endif
- NULL, 0}
+ NULL, 0, 0, 0}
};
/* Test if printer is ready (and optionally has no error conditions) */
@@ -135,8 +154,12 @@ static int lp_preempt(void *handle)
static __inline__ void lp_yield (int minor)
{
- if (!parport_yield_blocking (lp_table[minor].dev) && need_resched)
- schedule ();
+ if (!parport_yield_blocking (lp_table[minor].dev))
+ {
+ if (current->need_resched)
+ schedule ();
+ } else
+ lp_table[minor].irq_missed = 1;
}
static __inline__ void lp_schedule(int minor)
@@ -145,6 +168,7 @@ static __inline__ void lp_schedule(int minor)
register unsigned long int timeslip = (jiffies - dev->time);
if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) {
lp_parport_release(minor);
+ lp_table[minor].irq_missed = 1;
schedule ();
lp_parport_claim(minor);
} else
@@ -165,7 +189,6 @@ static int lp_reset(int minor)
static inline int lp_char(char lpchar, int minor)
{
- unsigned char status;
unsigned int wait = 0;
unsigned long count = 0;
#ifdef LP_STATS
@@ -175,12 +198,10 @@ static inline int lp_char(char lpchar, int minor)
for (;;)
{
lp_yield(minor);
- status = r_str (minor);
- if (LP_READY(minor, status))
+ if (LP_READY(minor, r_str(minor)))
break;
- if (!LP_POLLED(minor) || ++count == LP_CHAR(minor) ||
- signal_pending(current))
- return 0;
+ if (++count == LP_CHAR(minor) || signal_pending(current))
+ return 0;
}
w_dtr(minor, lpchar);
@@ -205,7 +226,15 @@ static inline int lp_char(char lpchar, int minor)
udelay(1);
#endif
/* take strobe low */
- w_ctr(minor, LP_PSELECP | LP_PINITP);
+ if (LP_POLLED(minor))
+ /* take strobe low */
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ else
+ {
+ lp_table[minor].irq_detected = 0;
+ lp_table[minor].irq_missed = 0;
+ w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
+ }
#ifdef LP_STATS
/* update waittime statistics */
@@ -231,6 +260,9 @@ static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (waitqueue_active (&lp_dev->wait_q))
wake_up_interruptible(&lp_dev->wait_q);
+
+ lp_dev->irq_detected = 1;
+ lp_dev->irq_missed = 0;
}
static void lp_error(int minor)
@@ -241,10 +273,12 @@ static void lp_error(int minor)
lp_parport_release(minor);
schedule();
lp_parport_claim(minor);
+ lp_table[minor].irq_missed = 1;
}
}
-static int lp_check_status(int minor) {
+static int lp_check_status(int minor)
+{
unsigned int last = lp_table[minor].last_error;
unsigned char status = r_str(minor);
if ((status & LP_POUTPA)) {
@@ -282,7 +316,6 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count)
unsigned long total_bytes_written = 0;
unsigned long bytes_written;
struct lp_struct *lp = &lp_table[minor];
- unsigned char status;
if (minor >= LP_NO)
return -ENXIO;
@@ -290,13 +323,20 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count)
return -ENXIO;
lp_table[minor].last_error = 0;
+ lp_table[minor].irq_detected = 0;
+ lp_table[minor].irq_missed = 1;
+
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
do {
bytes_written = 0;
copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
if (copy_from_user(lp->lp_buffer, buf, copy_size))
+ {
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
return -EFAULT;
+ }
while (copy_size) {
if (lp_char(lp->lp_buffer[bytes_written], minor)) {
@@ -314,7 +354,9 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count)
LP_STAT(minor).sleeps++;
#endif
- if (signal_pending(current)) {
+ if (signal_pending(current))
+ {
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
if (total_bytes_written + bytes_written)
return total_bytes_written + bytes_written;
else
@@ -325,9 +367,15 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count)
lp->runchars = 0;
#endif
- if (LP_POLLED(minor)) {
- if (lp_check_status(minor))
- return rc ? rc : -EIO;
+ if (lp_check_status(minor))
+ {
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
+ return rc ? rc : -EIO;
+ }
+
+ if (LP_POLLED(minor) ||
+ lp_table[minor].irq_missed)
+ {
lp_polling:
#if defined(LP_DEBUG) && defined(LP_STATS)
printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor));
@@ -342,28 +390,19 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count)
/*
* We can' t sleep on the interrupt
* since another pardevice need the port.
+ * We must check this in a cli() protected
+ * envinroment to avoid parport sharing
+ * starvation.
*/
sti();
goto lp_polling;
}
- w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
- status = r_str(minor);
- if (!(status & LP_PACK) || (status & LP_PBUSY))
+ if (!lp_table[minor].irq_detected)
{
- /*
- * The interrupt is happened in the
- * meantime so don' t wait for it.
- */
- w_ctr(minor, LP_PSELECP | LP_PINITP);
- sti();
- continue;
+ current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
+ interruptible_sleep_on(&lp->wait_q);
}
- current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
- interruptible_sleep_on(&lp->wait_q);
- w_ctr(minor, LP_PSELECP | LP_PINITP);
sti();
- if (lp_check_status(minor))
- return rc ? rc : -EIO;
}
}
}
@@ -374,6 +413,7 @@ static int lp_write_buf(unsigned int minor, const char *buf, int count)
} while (count > 0);
+ w_ctr(minor, LP_PSELECP | LP_PINITP);
return total_bytes_written;
}
@@ -459,7 +499,7 @@ static ssize_t lp_read(struct file * file, char * buf,
status = (r_str(minor) & 0x40);
udelay(50);
counter++;
- if (need_resched)
+ if (current->need_resched)
schedule ();
} while ((status == 0x40) && (counter < 20));
if (counter == 20) {
@@ -479,7 +519,7 @@ static ssize_t lp_read(struct file * file, char * buf,
status=(r_str(minor) & 0x40);
udelay(20);
counter++;
- if (need_resched)
+ if (current->need_resched)
schedule ();
} while ( (status == 0) && (counter < 20) );
if (counter == 20) { /* Timeout */
@@ -524,7 +564,7 @@ static int lp_open(struct inode * inode, struct file * file)
return -ENXIO;
if ((LP_F(minor) & LP_EXIST) == 0)
return -ENXIO;
- if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor)) & LP_BUSY)
+ if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor)))
return -EBUSY;
MOD_INC_USE_COUNT;
diff --git a/drivers/char/lp_intern.c b/drivers/char/lp_intern.c
index 7bb4ec634..45f2a289b 100644
--- a/drivers/char/lp_intern.c
+++ b/drivers/char/lp_intern.c
@@ -32,9 +32,16 @@
#include <asm/atarihw.h>
#include <asm/atariints.h>
#endif
+#ifdef CONFIG_MVME16x
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef CONFIG_BVME6000
+#include<asm/bvme6000hw.h>
+#endif
#include <linux/lp_intern.h>
static int minor = -1;
+MODULE_PARM(minor,"i");
static void lp_int_out(int, int);
static int lp_int_busy(int);
@@ -70,6 +77,25 @@ lp_int_out (int c, int dev)
break;
}
#endif
+#ifdef CONFIG_MVME16x
+ case MACH_MVME16x:
+ {
+ int wait = 0;
+ while (wait != lp_table[dev]->wait) wait++;
+ mvmelp.data = c;
+ break;
+ }
+#endif
+#ifdef CONFIG_BVME6000
+ case MACH_BVME6000:
+ {
+ int wait = 0;
+ while (wait != lp_table[dev]->wait) wait++;
+ bvmepit.padr = c;
+ bvmepit.pacr |= 0x02;
+ break;
+ }
+#endif
}
}
@@ -86,6 +112,14 @@ lp_int_busy (int dev)
case MACH_ATARI:
return mfp.par_dt_reg & 1;
#endif
+#ifdef CONFIG_MVME16x
+ case MACH_MVME16x:
+ return mvmelp.isr & 1;
+#endif
+#ifdef CONFIG_BVME6000
+ case MACH_BVME6000:
+ return 0 /* !(bvmepit.psr & 0x40) */ ;
+#endif
default:
return 0;
}
@@ -102,6 +136,15 @@ lp_int_pout (int dev)
#endif
#ifdef CONFIG_ATARI
case MACH_ATARI:
+ return 0;
+#endif
+#ifdef CONFIG_MVME16x
+ case MACH_MVME16x:
+ return mvmelp.isr & 2;
+#endif
+#ifdef CONFIG_BVME6000
+ case MACH_BVME6000:
+ return 0;
#endif
default:
return 0;
@@ -121,6 +164,14 @@ lp_int_online (int dev)
case MACH_ATARI:
return !(mfp.par_dt_reg & 1);
#endif
+#ifdef CONFIG_MVME16x
+ case MACH_MVME16x:
+ return mvmelp.isr & 4;
+#endif
+#ifdef CONFIG_BVME6000
+ case MACH_BVME6000:
+ return 1;
+#endif
default:
return 0;
}
@@ -128,6 +179,14 @@ lp_int_online (int dev)
static void lp_int_interrupt(int irq, void *data, struct pt_regs *fp)
{
+#ifdef CONFIG_MVME16x
+ if (MACH_IS_MVME16x)
+ mvmelp.ack_icr |= 0x08;
+#endif
+#ifdef CONFIG_BVME6000
+ if (MACH_IS_BVME6000)
+ bvmepit.pacr &= ~0x02;
+#endif
lp_interrupt(minor);
}
@@ -192,6 +251,62 @@ __initfunc(int lp_internal_init(void))
tab.type = LP_ATARI;
}
#endif
+#ifdef CONFIG_MAC
+ if (MACH_IS_MAC)
+ return -ENODEV;
+#endif
+#ifdef CONFIG_MVME16x
+ if (MACH_IS_MVME16x)
+ {
+ unsigned long flags;
+
+ if (!(mvme16x_config & MVME16x_CONFIG_GOT_LP))
+ return -ENODEV;
+
+ save_flags(flags);
+ cli();
+ mvmelp.ack_icr = 0x08;
+ mvmelp.flt_icr = 0x08;
+ mvmelp.sel_icr = 0x08;
+ mvmelp.pe_icr = 0x08;
+ mvmelp.bsy_icr = 0x08;
+ mvmelp.cr = 0x10;
+ mvmelp.ack_icr = 0xd9; /* Int on trailing edge of ACK */
+ restore_flags(flags);
+
+ if (lp_irq)
+ tab.irq = request_irq(MVME167_IRQ_PRN, lp_int_interrupt,
+ 0, "builtin printer port", lp_int_interrupt);
+ tab.base = (void *)&mvmelp; /* dummy, not used */
+ tab.type = LP_MVME167;
+ }
+#endif
+#ifdef CONFIG_BVME6000
+ if (MACH_IS_BVME6000)
+ {
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ bvmepit.pgcr = 0x0f;
+ bvmepit.psrr = 0x18;
+ bvmepit.paddr = 0xff;
+ bvmepit.pcdr = (bvmepit.pcdr & 0xfc) | 0x02;
+ bvmepit.pcddr |= 0x03;
+ bvmepit.pacr = 0x78;
+ bvmepit.pbcr = 0x00;
+ bvmepit.pivr = BVME_IRQ_PRN;
+ bvmepit.pgcr = 0x1f;
+ restore_flags(flags);
+
+ if (lp_irq)
+ tab.irq = request_irq(BVME_IRQ_PRN, lp_int_interrupt,
+ 0, "builtin printer port", lp_int_interrupt);
+ tab.base = (void *)&bvmepit; /* dummy, not used */
+ tab.type = LP_BVME6000;
+ }
+#endif
+
if ((minor = register_parallel(&tab, minor)) < 0) {
printk("builtin lp init: cant get a minor\n");
@@ -204,6 +319,14 @@ __initfunc(int lp_internal_init(void))
if (MACH_IS_ATARI)
free_irq(IRQ_MFP_BUSY, lp_int_interrupt);
#endif
+#ifdef CONFIG_MVME16x
+ if (MACH_IS_MVME16x)
+ free_irq(MVME167_IRQ_PRN, lp_int_interrupt);
+#endif
+#ifdef CONFIG_BVME6000
+ if (MACH_IS_BVME6000)
+ free_irq(BVME_IRQ_PRN, lp_int_interrupt);
+#endif
}
return -ENODEV;
}
@@ -228,6 +351,14 @@ if (lp_irq) {
if (MACH_IS_ATARI)
free_irq(IRQ_MFP_BUSY, lp_int_interrupt);
#endif
+#ifdef CONFIG_MVME16x
+ if (MACH_IS_MVME16x)
+ free_irq(MVME167_IRQ_PRN, lp_int_interrupt);
+#endif
+#ifdef CONFIG_BVME6000
+ if (MACH_IS_BVME6000)
+ free_irq(BVME_IRQ_PRN, lp_int_interrupt);
+#endif
}
unregister_parallel(minor);
}
diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c
index 4a000e9aa..5079b2e62 100644
--- a/drivers/char/lp_m68k.c
+++ b/drivers/char/lp_m68k.c
@@ -102,7 +102,7 @@ static int lp_char_polled(char lpchar, int dev)
do {
count ++;
- if(need_resched)
+ if (current->need_resched)
schedule();
} while (lp_table[dev]->lp_is_busy(dev) && count < lp_table[dev]->chars);
@@ -173,13 +173,14 @@ void lp_interrupt(int dev)
}
#if WHICH_DRIVER == FORCE_INTERRUPT
-static long lp_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t lp_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
#else
-static long lp_write_interrupt(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t lp_write_interrupt(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
#endif
{
+ struct inode *inode = file->f_dentry->d_inode;
unsigned long total_bytes_written = 0;
unsigned int flags;
int rc;
@@ -190,7 +191,9 @@ static long lp_write_interrupt(struct inode *inode, struct file *file,
lp_table[dev]->bytes_written = 0; /* init buffer read-pointer */
lp_error = 0;
lp_table[dev]->copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
- copy_from_user(lp_table[dev]->lp_buffer, buf, lp_table[dev]->copy_size);
+ if (copy_from_user(lp_table[dev]->lp_buffer, buf,
+ lp_table[dev]->copy_size))
+ return -EFAULT;
while (lp_table[dev]->copy_size) {
save_flags(flags);
cli(); /* no interrupts now */
@@ -223,10 +226,9 @@ static long lp_write_interrupt(struct inode *inode, struct file *file,
rc = total_bytes_written + lp_table[dev]->bytes_written;
if (signal_pending(current)) {
- if (rc)
- return rc;
- else
- return -EINTR;
+ if (rc == 0)
+ rc = -EINTR;
+ return rc;
}
if (lp_error) {
@@ -267,13 +269,14 @@ void (*lp_interrupt)() = NULL;
#if WHICH_DRIVER != FORCE_INTERRUPT
#if WHICH_DRIVER == FORCE_POLLING
-static long lp_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t lp_write(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
#else
-static long lp_write_polled(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t lp_write_polled(struct file *file, const char *buf,
+ size_t count, loff_t *ppos)
#endif
{
+ struct inode *inode = file->f_dentry->d_inode;
char *temp = buf;
int dev = MINOR(inode->i_rdev);
@@ -287,52 +290,53 @@ static long lp_write_polled(struct inode *inode, struct file *file,
temp = buf;
while (count > 0) {
- if (lp_char_polled(get_user(temp), dev)) {
+ int c;
+ if (get_user(c, temp))
+ return -EFAULT;
+ if (lp_char_polled(c, dev)) {
/* only update counting vars if character was printed */
count--; temp++;
#ifdef LP_DEBUG
lp_total_chars++;
#endif
} else { /* if printer timed out */
+ unsigned long timeout = LP_TIMEOUT_POLLED;
+ int error = 0;
if (lp_table[dev]->lp_has_pout(dev)) {
printk(KERN_NOTICE "lp%d: out of paper\n",dev);
if (lp_table[dev]->flags & LP_ABORT)
- return temp - buf ? temp-buf : -ENOSPC;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + LP_TIMEOUT_POLLED;
- schedule();
+ error = -ENOSPC;
} else if (!lp_table[dev]->lp_is_online(dev)) {
printk(KERN_NOTICE "lp%d: off-line\n",dev);
if (lp_table[dev]->flags & LP_ABORT)
- return temp - buf ? temp-buf : -EIO;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + LP_TIMEOUT_POLLED;
- schedule();
+ error = -EIO;
} else
/* not offline or out of paper. on fire? */
if (lp_table[dev]->lp_is_busy(dev)) {
printk(KERN_NOTICE "lp%d: on fire\n",dev);
if (lp_table[dev]->flags & LP_ABORT)
- return temp - buf ? temp-buf : -EFAULT;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + LP_TIMEOUT_POLLED;
- schedule();
+ error = -EIO;
}
+ else
+ timeout = lp_table[dev]->time;
/* check for signals before going to sleep */
- if (signal_pending(current)) {
+ if (error == 0 && signal_pending(current))
+ error = -EINTR;
+ if (error) {
if (temp != buf)
return temp-buf;
else
- return -EINTR;
+ return error;
}
+
#ifdef LP_DEBUG
printk("lp sleeping at %d characters for %d jiffies\n",
- lp_total_chars, lp_table[dev]->time);
+ lp_total_chars, timeout);
lp_total_chars = 0;
#endif
current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + lp_table[dev]->time;
+ current->timeout = jiffies + timeout;
schedule();
}
}
@@ -343,13 +347,13 @@ static long lp_write_polled(struct inode *inode, struct file *file,
unsigned int lp_irq = 0;
#if WHICH_DRIVER == PREFER_INTERRUPT
-static long lp_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t lp_write(struct file *file, const char *buf, size_t count,
+ loff_t *ppos)
{
if (lp_irq)
- return lp_write_interrupt(inode, file, buf, count);
+ return lp_write_interrupt(file, buf, count, ppos);
else
- return lp_write_polled(inode, file, buf, count);
+ return lp_write_polled(file, buf, count, ppos);
}
#endif
@@ -363,8 +367,12 @@ static int lp_open(struct inode *inode, struct file *file)
int dev = MINOR(inode->i_rdev);
int ret;
+ MOD_INC_USE_COUNT;
+
+ ret = -ENODEV;
if (dev >= MAX_LP)
- return -ENODEV;
+ goto out_err;
+
#ifdef CONFIG_KMOD
if (!lp_table[dev]) {
char modname[30];
@@ -374,22 +382,25 @@ static int lp_open(struct inode *inode, struct file *file)
}
#endif
if (!lp_table[dev])
- return -ENODEV;
+ goto out_err;
if (!(lp_table[dev]->flags & LP_EXIST))
- return -ENODEV;
+ goto out_err;
+ ret = -EBUSY;
if (lp_table[dev]->flags & LP_BUSY)
- return -EBUSY;
+ goto out_err;
lp_table[dev]->flags |= LP_BUSY;
ret = lp_table[dev]->lp_open(dev);
if (ret != 0) {
lp_table[dev]->flags &= ~LP_BUSY;
- }
- else {
- MOD_INC_USE_COUNT;
+ goto out_err;
}
return ret;
+
+out_err:
+ MOD_DEC_USE_COUNT;
+ return ret;
}
static int lp_release(struct inode *inode, struct file *file)
@@ -407,15 +418,16 @@ static int lp_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
unsigned int minor = MINOR(inode->i_rdev);
- int retval = 0;
+ int retval = -ENODEV;
#ifdef LP_DEBUG
printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
#endif
if (minor >= max_lp)
- return -ENODEV;
+ goto out;
if (!(lp_table[minor]->flags & LP_EXIST))
- return -ENODEV;
+ goto out;
+ retval = 0;
switch (cmd) {
case LPTIME:
lp_table[minor]->time = arg;
@@ -437,11 +449,11 @@ static int lp_ioctl(struct inode *inode, struct file *file,
retval = lp_irq;
break;
default:
+ retval = -EINVAL;
if (lp_table[minor]->lp_ioctl)
retval = lp_table[minor]->lp_ioctl(minor, cmd, arg);
- else
- retval = -EINVAL;
}
+out:
return retval;
}
diff --git a/drivers/char/mac_SCC.c b/drivers/char/mac_SCC.c
new file mode 100644
index 000000000..0295ab4b4
--- /dev/null
+++ b/drivers/char/mac_SCC.c
@@ -0,0 +1,1543 @@
+/*
+ * mac_SCC.c: m68k version of
+ *
+ * macserial.c: Serial port driver for Power Macintoshes.
+ * Extended for the 68K mac by Alan Cox.
+ * Rewritten to m68k serial design by Michael Schmitz
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ * Design note for the m68k rewrite:
+ * The structure of the m68k serial code requires separation of the low-level
+ * functions that talk directly to the hardware from the Linux serial driver
+ * code interfacing to the tty layer. The reason for this separation is simply
+ * the fact that the m68k serial hardware is, unlike the i386, based on a
+ * variety of chips, and the rs_* serial routines need to be shared.
+ *
+ * I've tried to make consistent use of the async_struct info populated in the
+ * midlevel code, and introduced an async_private struct to hold the Macintosh
+ * SCC internals (this was added to the async_struct for the PowerMac driver).
+ * Exception: the console and kgdb hooks still use the zs_soft[] data, and this
+ * is still filled in by the probe_sccs() routine, which provides some data
+ * for mac_SCC_init as well. Interrupts are registered in mac_SCC_init, so
+ * the console/kgdb stuff probably won't work before proper serial init, and
+ * I have to rely on keeping info and zs_soft consistent at least for the
+ * console/kgdb port.
+ *
+ * Update (16-11-97): The SCC interrupt handling was suffering from the problem
+ * that the autovector SCC interrupt was registered only once, hence only one
+ * async_struct was passed to the interrupt function and only interrupts from
+ * the corresponding channel could be handled (yes, major design flaw).
+ * The autovector interrupt is now registered by the main interrupt initfunc,
+ * and uses a handler that will call the registered SCC specific interrupts in
+ * turn. The SCC init has to register these as machspec interrupts now, as is
+ * done for the VIA interrupts elsewhere.
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/macints.h>
+#ifndef CONFIG_MAC
+#include <asm/prom.h>
+#endif
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "mac_SCC.h"
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL 2 /* Max number of ZS chips supported */
+#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
+
+#ifdef CONFIG_MAC
+/*
+ * All the Macintosh 68K boxes that have an MMU also have hardware
+ * recovery delays.
+ */
+#define RECOVERY_DELAY
+#else
+/* On PowerMacs, the hardware takes care of the SCC recovery time,
+ but we need the eieio to make sure that the accesses occur
+ in the order we want. */
+#define RECOVERY_DELAY eieio()
+#endif
+
+struct mac_zschannel *zs_kgdbchan;
+struct mac_zschannel zs_channels[NUM_CHANNELS];
+
+struct m68k_async_struct zs_soft[NUM_CHANNELS];
+struct m68k_async_private zs_soft_private[NUM_CHANNELS];
+int zs_channels_found;
+struct m68k_async_struct *zs_chain; /* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chanout = 0;
+static int zs_cons_chanin = 0;
+struct m68k_async_struct *zs_consinfo = 0;
+struct mac_zschannel *zs_conschan;
+
+static unsigned char kgdb_regs[16] = {
+ 0, 0, 0, /* write 0, 1, 2 */
+ (Rx8 | RxENABLE), /* write 3 */
+ (X16CLK | SB1 | PAR_EVEN), /* write 4 */
+ (Tx8 | TxENAB), /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ (NV), /* write 9 */
+ (NRZ), /* write 10 */
+ (TCBR | RCBR), /* write 11 */
+ 1, 0, /* 38400 baud divisor, write 12 + 13 */
+ (BRENABL), /* write 14 */
+ (DCDIE) /* write 15 */
+};
+
+#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/***************************** Prototypes *****************************/
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel );
+#if 0
+#ifdef MODULE
+static void SCC_deinit_port( struct m68k_async_struct *info, int channel );
+#endif
+#endif
+
+/* FIXME !!! Currently, only autovector interrupt used! */
+#if 0
+static void SCC_rx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_spcond_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_tx_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_stat_int (int irq, void *data, struct pt_regs *fp);
+static void SCC_ri_int (int irq, void *data, struct pt_regs *fp);
+#endif
+
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct
+ *tty, struct file *file );
+static void SCC_init( struct m68k_async_struct *info );
+static void SCC_deinit( struct m68k_async_struct *info, int leave_dtr );
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag );
+static int SCC_check_custom_divisor( struct m68k_async_struct *info, int baud_base,
+ int divisor );
+static void SCC_change_speed( struct m68k_async_struct *info );
+#if 0
+static int SCC_clocksrc( unsigned baud_base, unsigned channel );
+#endif
+static void SCC_throttle( struct m68k_async_struct *info, int status );
+static void SCC_set_break( struct m68k_async_struct *info, int break_flag );
+static void SCC_get_serial_info( struct m68k_async_struct *info, struct
+ serial_struct *retinfo );
+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 );
+static int SCC_ioctl( struct tty_struct *tty, struct file *file, struct
+ m68k_async_struct *info, unsigned int cmd, unsigned long arg );
+static void SCC_stop_receive (struct m68k_async_struct *info);
+static int SCC_trans_empty (struct m68k_async_struct *info);
+
+/************************* End of Prototypes **************************/
+
+
+static SERIALSWITCH SCC_switch = {
+ SCC_init, SCC_deinit, SCC_enab_tx_int,
+ SCC_check_custom_divisor, SCC_change_speed,
+ SCC_throttle, SCC_set_break,
+ SCC_get_serial_info, SCC_get_modem_info,
+ SCC_set_modem_info, SCC_ioctl, SCC_stop_receive, SCC_trans_empty,
+ SCC_check_open
+};
+
+/*
+ * 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[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+ 9600, 19200, 38400, 57600, 115200, 0 };
+
+/*
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct mac_zschannel *channel,
+ unsigned char reg)
+{
+ unsigned char retval;
+
+ if (reg != 0) {
+ *channel->control = reg;
+ RECOVERY_DELAY;
+ }
+ retval = *channel->control;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsreg(struct mac_zschannel *channel,
+ unsigned char reg, unsigned char value)
+{
+ if (reg != 0) {
+ *channel->control = reg;
+ RECOVERY_DELAY;
+ }
+ *channel->control = value;
+ RECOVERY_DELAY;
+ return;
+}
+
+static inline unsigned char read_zsdata(struct mac_zschannel *channel)
+{
+ unsigned char retval;
+
+ retval = *channel->data;
+ RECOVERY_DELAY;
+ return retval;
+}
+
+static inline void write_zsdata(struct mac_zschannel *channel,
+ unsigned char value)
+{
+ *channel->data = value;
+ RECOVERY_DELAY;
+ return;
+}
+
+static inline void load_zsregs(struct mac_zschannel *channel,
+ unsigned char *regs)
+{
+ ZS_CLEARERR(channel);
+ ZS_CLEARFIFO(channel);
+ /* Load 'em up */
+ write_zsreg(channel, R4, regs[R4]);
+ write_zsreg(channel, R10, regs[R10]);
+ write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+ write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+ write_zsreg(channel, R1, regs[R1]);
+ write_zsreg(channel, R9, regs[R9]);
+ write_zsreg(channel, R11, regs[R11]);
+ write_zsreg(channel, R12, regs[R12]);
+ write_zsreg(channel, R13, regs[R13]);
+ write_zsreg(channel, R14, regs[R14]);
+ write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R3, regs[R3]);
+ write_zsreg(channel, R5, regs[R5]);
+ return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct m68k_async_struct *ss, int set)
+{
+ if (set)
+ ss->private->curregs[5] |= (RTS | DTR);
+ else
+ ss->private->curregs[5] &= ~(RTS | DTR);
+ write_zsreg(ss->private->zs_channel, 5, ss->private->curregs[5]);
+ return;
+}
+
+static inline void kgdb_chaninit(struct m68k_async_struct *ss, int intson, int bps)
+{
+ int brg;
+
+ if (intson) {
+ kgdb_regs[R1] = INT_ALL_Rx;
+ kgdb_regs[R9] |= MIE;
+ } else {
+ kgdb_regs[R1] = 0;
+ kgdb_regs[R9] &= ~MIE;
+ }
+ brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+ kgdb_regs[R12] = brg;
+ kgdb_regs[R13] = brg >> 8;
+ load_zsregs(ss->private->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct m68k_async_struct *ss)
+{
+ struct mac_zschannel *channel = ss->private->zs_channel;
+ int brg;
+
+ /* The baud rate is split up between two 8-bit registers in
+ * what is termed 'BRG time constant' format in my docs for
+ * the chip, it is a function of the clk rate the chip is
+ * receiving which happens to be constant.
+ */
+ brg = (read_zsreg(channel, 13) << 8);
+ brg |= read_zsreg(channel, 12);
+ return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->private->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void SCC_recv_clear(struct mac_zschannel *zsc)
+{
+ write_zsreg(zsc, 0, ERR_RES);
+ write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+extern void breakpoint(void); /* For the KGDB frame character */
+
+static /*_INLINE_*/ void receive_chars(struct m68k_async_struct *info,
+ struct pt_regs *regs)
+{
+ struct tty_struct *tty = info->tty;
+ unsigned char ch, stat, flag;
+
+ while ((read_zsreg(info->private->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+ stat = read_zsreg(info->private->zs_channel, R1);
+ ch = read_zsdata(info->private->zs_channel);
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: receive_chars stat=%X char=%X \n", stat, ch);
+#endif
+
+#if 0 /* KGDB not yet supported */
+ /* Look for kgdb 'stop' character, consult the gdb documentation
+ * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+ * to see how all this works.
+ */
+ if ((info->kgdb_channel) && (ch =='\003')) {
+ breakpoint();
+ continue;
+ }
+#endif
+
+ if (!tty)
+ continue;
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ tty_flip_buffer_push(tty);
+
+ if (stat & Rx_OVR) {
+ flag = TTY_OVERRUN;
+ /* reset the error indication */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ } else if (stat & FRM_ERR) {
+ /* this error is not sticky */
+ flag = TTY_FRAME;
+ } else if (stat & PAR_ERR) {
+ flag = TTY_PARITY;
+ /* reset the error indication */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ } else
+ flag = 0;
+
+ if (tty->flip.buf_num
+ && tty->flip.count >= TTY_FLIPBUF_SIZE) {
+#ifdef SCC_DEBUG_OVERRUN
+ printk("mac_SCC: flip buffer overrun!\n");
+#endif
+ return;
+ }
+
+ if (!tty->flip.buf_num
+ && tty->flip.count >= 2*TTY_FLIPBUF_SIZE) {
+ printk("mac_SCC: double flip buffer overrun!\n");
+ return;
+ }
+
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = flag;
+ *tty->flip.char_buf_ptr++ = ch;
+ info->icount.rx++;
+ tty_flip_buffer_push(tty);
+ }
+#if 0
+clear_and_exit:
+ SCC_recv_clear(info->private->zs_channel);
+#endif
+}
+
+/* that's SCC_enable_tx_int, basically */
+
+static void transmit_chars(struct m68k_async_struct *info)
+{
+ if ((read_zsreg(info->private->zs_channel, 0) & Tx_BUF_EMP) == 0)
+ return;
+ info->private->tx_active = 0;
+
+ if (info->x_char) {
+ /* Send next char */
+ write_zsdata(info->private->zs_channel, info->x_char);
+ info->x_char = 0;
+ info->private->tx_active = 1;
+ return;
+ }
+
+ if ((info->xmit_cnt <= 0) || info->tty->stopped
+ || info->private->tx_stopped) {
+ write_zsreg(info->private->zs_channel, 0, RES_Tx_P);
+ return;
+ }
+
+ /* Send char */
+ write_zsdata(info->private->zs_channel, info->xmit_buf[info->xmit_tail++]);
+ info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+ info->icount.tx++;
+ info->xmit_cnt--;
+ info->private->tx_active = 1;
+
+ if (info->xmit_cnt < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static /*_INLINE_*/ void status_handle(struct m68k_async_struct *info)
+{
+ unsigned char status;
+
+ /* Get status from Read Register 0 */
+ status = read_zsreg(info->private->zs_channel, 0);
+
+ /* Check for DCD transitions */
+ if (((status ^ info->private->read_reg_zero) & DCD) != 0
+ && info->tty && C_CLOCAL(info->tty)) {
+ if (status & DCD) {
+ wake_up_interruptible(&info->open_wait);
+ } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+ if (info->tty)
+ tty_hangup(info->tty);
+ }
+ }
+
+ /* Check for CTS transitions */
+ if (info->tty && C_CRTSCTS(info->tty)) {
+ /*
+ * For some reason, on the Power Macintosh,
+ * it seems that the CTS bit is 1 when CTS is
+ * *negated* and 0 when it is asserted.
+ * The DCD bit doesn't seem to be inverted
+ * like this.
+ */
+ if ((status & CTS) == 0) {
+ if (info->private->tx_stopped) {
+ info->private->tx_stopped = 0;
+ if (!info->private->tx_active)
+ transmit_chars(info);
+ }
+ } else {
+ info->private->tx_stopped = 1;
+ }
+ }
+
+ /* Clear status condition... */
+ write_zsreg(info->private->zs_channel, 0, RES_EXT_INT);
+ info->private->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void mac_SCC_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct m68k_async_struct *info = (struct m68k_async_struct *) dev_id;
+ unsigned char zs_intreg;
+ int shift;
+
+ /* NOTE: The read register 3, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the A
+ * channel and is only valid when read from channel A.
+ * Yes... broken hardware...
+ */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: interrupt; port: %lx channel: %lx \n",
+ info->port, info->private->zs_channel);
+#endif
+
+ if (info->private->zs_chan_a == info->private->zs_channel)
+ shift = 3; /* Channel A */
+ else
+ shift = 0; /* Channel B */
+
+ for (;;) {
+ zs_intreg = read_zsreg(info->private->zs_chan_a, 3);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: status %x shift %d shifted %x \n",
+ zs_intreg, shift, zs_intreg >> shift);
+#endif
+ zs_intreg = zs_intreg >> shift;
+ if ((zs_intreg & CHAN_IRQMASK) == 0)
+ break;
+
+ if (zs_intreg & CHBRxIP)
+ receive_chars(info, regs);
+ if (zs_intreg & CHBTxIP)
+ transmit_chars(info);
+ if (zs_intreg & CHBEXT)
+ status_handle(info);
+ }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+
+static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag )
+{
+ unsigned long flags;
+
+ if (enab_flag) {
+#if 0
+ save_flags(flags); cli();
+ if (info->private->curregs[5] & TxENAB) {
+ info->private->curregs[5] &= ~TxENAB;
+ info->private->pendregs[5] &= ~TxENAB;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+ restore_flags(flags);
+#endif
+ /* FIXME: should call transmit_chars here ??? */
+ transmit_chars(info);
+ } else {
+ save_flags(flags); cli();
+#if 0
+ if ( info->xmit_cnt && info->xmit_buf &&
+ !(info->private->curregs[5] & TxENAB)) {
+ info->private->curregs[5] |= TxENAB;
+ info->private->pendregs[5] = info->private->curregs[5];
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+#else
+ if ( info->xmit_cnt && info->xmit_buf &&
+ !info->private->tx_active) {
+ transmit_chars(info);
+ }
+#endif
+ restore_flags(flags);
+ }
+
+}
+
+#if 0
+/*
+ * leftover from original driver ...
+ */
+static int SCC_startup(struct m68k_async_struct * info)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+ /*
+ * Clear the receive FIFO.
+ */
+ ZS_CLEARFIFO(info->private->zs_channel);
+ info->xmit_fifo_size = 1;
+
+ /*
+ * Clear the interrupt registers.
+ */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+ /*
+ * Turn on RTS and DTR.
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing and interrupts
+ */
+ info->private->curregs[1] = (info->private->curregs[1] & ~0x18)
+ | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+ info->private->pendregs[1] = info->private->curregs[1];
+ info->private->curregs[3] |= (RxENABLE | Rx8);
+ info->private->pendregs[3] = info->private->curregs[3];
+ info->private->curregs[5] |= (TxENAB | Tx8);
+ info->private->pendregs[5] = info->private->curregs[5];
+ info->private->curregs[9] |= (NV | MIE);
+ info->private->pendregs[9] = info->private->curregs[9];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+ /*
+ * Set the speed of the serial port
+ */
+ SCC_change_speed(info);
+
+ /* Save the current value of RR0 */
+ info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+ restore_flags(flags);
+ return 0;
+}
+#endif
+
+/* FIXME: are these required ?? */
+static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty,
+ struct file *file )
+{
+ /* check on the basis of info->whatever ?? */
+ if (info->private->kgdb_channel || info->private->is_cons)
+ return -EBUSY;
+ return( 0 );
+}
+
+static void SCC_init( struct m68k_async_struct *info )
+{
+ /* FIXME: init currently done in probe_sccs() */
+
+ /* BUT: startup part needs to be done here! */
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: init, info %lx, info->port %lx \n", info, info->port);
+#endif
+ /*
+ * Clear the receive FIFO.
+ */
+ ZS_CLEARFIFO(info->private->zs_channel);
+ info->xmit_fifo_size = 1;
+
+ /*
+ * Clear the interrupt registers.
+ */
+ write_zsreg(info->private->zs_channel, 0, ERR_RES);
+ write_zsreg(info->private->zs_channel, 0, RES_H_IUS);
+
+ /*
+ * Turn on RTS and DTR.
+ */
+ zs_rtsdtr(info, 1);
+
+ /*
+ * Finally, enable sequencing and interrupts
+ */
+ info->private->curregs[1] = (info->private->curregs[1] & ~0x18)
+ | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+ info->private->pendregs[1] = info->private->curregs[1];
+ info->private->curregs[3] |= (RxENABLE | Rx8);
+ info->private->pendregs[3] = info->private->curregs[3];
+ info->private->curregs[5] |= (TxENAB | Tx8);
+ info->private->pendregs[5] = info->private->curregs[5];
+ info->private->curregs[9] |= (NV | MIE);
+ info->private->pendregs[9] = info->private->curregs[9];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);
+
+ /*
+ * Set the speed of the serial port - done in startup() !!
+ */
+#if 0
+ SCC_change_speed(info);
+#endif
+
+ /* Save the current value of RR0 */
+ info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);
+
+}
+
+static void SCC_init_port( struct m68k_async_struct *info, int type, int channel )
+{
+ static int got_autovector = 0;
+
+#ifdef SCC_DEBUG
+ printk("mac_SCC: init_port, info %x \n", info);
+#endif
+ info->sw = &SCC_switch;
+ info->private = &zs_soft_private[channel];
+ info->private->zs_channel = &zs_channels[channel];
+ info->irq = IRQ4;
+ info->private->clk_divisor = 16;
+ info->private->zs_baud = get_zsbaud(info);
+ info->port = (int) info->private->zs_channel->control;
+
+ /*
+ * MSch: Extended interrupt scheme:
+ * The generic m68k interrupt code can't use multiple handlers for
+ * the same interrupt source (no chained interrupts).
+ * We have to plug in a 'master' interrupt handler instead, calling
+ * mac_SCC_interrupt with the proper arguments ...
+ */
+
+ if (!got_autovector) {
+ if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info))
+ panic("macserial: can't get irq %d", IRQ4);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n",
+ IRQ4, channel, info);
+#endif
+ got_autovector = 1;
+ }
+
+ if (info->private->zs_chan_a == info->private->zs_channel) {
+ /* Channel A */
+ if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info))
+ panic("mac_SCC: can't get irq %d", IRQ_SCCA);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n",
+ IRQ_SCCA, channel, info);
+#endif
+ } else {
+ /* Channel B */
+ if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info))
+ panic("mac_SCC: can't get irq %d", IRQ_SCCB);
+#ifdef SCC_DEBUG
+ printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n",
+ IRQ_SCCB, channel, info);
+#endif
+ }
+
+ /* If console serial line, then enable interrupts. */
+ if (info->private->is_cons) {
+ printk("mac_SCC: console line %lx; enabling interrupt!\n", info);
+ write_zsreg(info->private->zs_channel, R1,
+ (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+ write_zsreg(info->private->zs_channel, R9, (NV | MIE));
+ write_zsreg(info->private->zs_channel, R10, (NRZ));
+ write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE));
+ write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB));
+ }
+ /* If this is the kgdb line, enable interrupts because we
+ * now want to receive the 'control-c' character from the
+ * client attached to us asynchronously.
+ */
+ if (info->private->kgdb_channel) {
+ printk("mac_SCC: kgdb line %lx; enabling interrupt!\n", info);
+ kgdb_chaninit(info, 1, info->private->zs_baud);
+ }
+ /* Report settings (in m68kserial.c) */
+#ifndef CONFIG_MAC
+ printk("ttyS%d at 0x%08x (irq = %d)", info->line,
+ info->port, info->irq);
+ printk(" is a Z8530 SCC\n");
+#endif
+
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ info->private->pendregs[1] = info->private->curregs[1] = 0;
+ write_zsreg(info->private->zs_channel, 1, 0); /* no interrupts */
+
+ info->private->curregs[3] &= ~RxENABLE;
+ info->private->pendregs[3] = info->private->curregs[3];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+
+ info->private->curregs[5] &= ~TxENAB;
+
+ if (!leave_dtr)
+ info->private->curregs[5] &= ~(DTR | RTS);
+ else
+ info->private->curregs[5] &= ~(RTS);
+
+ info->private->pendregs[5] = info->private->curregs[5];
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+
+ restore_flags(flags);
+}
+
+/* FIXME !!! */
+static int SCC_check_custom_divisor( struct m68k_async_struct *info,
+ int baud_base, int divisor )
+{
+ return 0;
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void SCC_change_speed(struct m68k_async_struct *info)
+{
+ unsigned short port;
+ unsigned cflag;
+ int i;
+ int brg;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+ cflag = info->tty->termios->c_cflag;
+ if (!(port = info->port))
+ return;
+ i = cflag & CBAUD;
+
+ if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) {
+ /* speed == 0 -> drop DTR */
+ save_flags(flags);
+ cli();
+ info->private->curregs[5] &= ~(DTR | RTS);
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ restore_flags(flags);
+ return;
+ }
+
+
+ if (i & CBAUDEX) {
+ /* XXX CBAUDEX is not obeyed.
+ * It is impossible at a 32bits PPC. XXX??
+ * But we have to report this to user ... someday.
+ */
+ i = B9600;
+ }
+
+ save_flags(flags); cli();
+ info->private->zs_baud = baud_table[i];
+ info->private->clk_divisor = 16;
+
+ info->private->curregs[4] = X16CLK;
+ info->private->curregs[11] = TCBR | RCBR;
+ brg = BPS_TO_BRG(info->private->zs_baud,
+ ZS_CLOCK/info->private->clk_divisor);
+ info->private->curregs[12] = (brg & 255);
+ info->private->curregs[13] = ((brg >> 8) & 255);
+ info->private->curregs[14] = BRENABL;
+
+ /* byte size and parity */
+ info->private->curregs[3] &= ~RxNBITS_MASK;
+ info->private->curregs[5] &= ~TxNBITS_MASK;
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->private->curregs[3] |= Rx5;
+ info->private->curregs[5] |= Tx5;
+ break;
+ case CS6:
+ info->private->curregs[3] |= Rx6;
+ info->private->curregs[5] |= Tx6;
+ break;
+ case CS7:
+ info->private->curregs[3] |= Rx7;
+ info->private->curregs[5] |= Tx7;
+ break;
+ case CS8:
+ default: /* defaults to 8 bits */
+ info->private->curregs[3] |= Rx8;
+ info->private->curregs[5] |= Tx8;
+ break;
+ }
+ info->private->pendregs[3] = info->private->curregs[3];
+ info->private->pendregs[5] = info->private->curregs[5];
+
+ info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+ if (cflag & CSTOPB) {
+ info->private->curregs[4] |= SB2;
+ } else {
+ info->private->curregs[4] |= SB1;
+ }
+ if (cflag & PARENB) {
+ info->private->curregs[4] |= PAR_ENA;
+ }
+ if (!(cflag & PARODD)) {
+ info->private->curregs[4] |= PAR_EVEN;
+ }
+ info->private->pendregs[4] = info->private->curregs[4];
+
+ info->private->curregs[15] &= ~(DCDIE | CTSIE);
+ if (!(cflag & CLOCAL)) {
+ info->private->curregs[15] |= DCDIE;
+ }
+ if (cflag & CRTSCTS) {
+ info->private->curregs[15] |= CTSIE;
+ if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0)
+ info->private->tx_stopped = 1;
+ } else
+ info->private->tx_stopped = 0;
+ info->private->pendregs[15] = info->private->curregs[15];
+
+ /* Load up the new values */
+ load_zsregs(info->private->zs_channel, info->private->curregs);
+
+ restore_flags(flags);
+}
+
+/* This is for console output over ttya/ttyb */
+static void SCC_put_char(char ch)
+{
+ struct mac_zschannel *chan = zs_conschan;
+ int loops = 0;
+ unsigned long flags;
+
+ if(!chan)
+ return;
+
+ save_flags(flags); cli();
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) {
+ loops++;
+ udelay(5);
+ }
+ write_zsdata(chan, ch);
+ restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+
+ while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(chan, kgdb_char);
+}
+
+char getDebugChar(void)
+{
+ struct mac_zschannel *chan = zs_kgdbchan;
+
+ while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+ udelay(5);
+ return read_zsdata(chan);
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void SCC_fair_output(void)
+{
+ int left; /* Output no more than that */
+ unsigned long flags;
+ struct m68k_async_struct *info = zs_consinfo;
+ char c;
+
+ if (info == 0) return;
+ if (info->xmit_buf == 0) return;
+
+ save_flags(flags); cli();
+ left = info->xmit_cnt;
+ while (left != 0) {
+ c = info->xmit_buf[info->xmit_tail];
+ info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt--;
+ restore_flags(flags);
+
+ SCC_put_char(c);
+
+ save_flags(flags); cli();
+ left = MIN(info->xmit_cnt, left-1);
+ }
+
+ restore_flags(flags);
+ return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+ char c;
+
+ while ((c = *(p++)) != 0) {
+ if (c == '\n')
+ SCC_put_char('\r');
+ SCC_put_char(c);
+ }
+
+ /* Comment this if you want to have a strict interrupt-driven output */
+ SCC_fair_output();
+}
+
+/* FIXME: check with SCC_enab_tx_int!! */
+#if 0
+static void rs_flush_chars(struct tty_struct *tty)
+{
+ struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+ return;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || info->private->tx_stopped ||
+ !info->xmit_buf)
+ return;
+
+ /* Enable transmitter */
+ save_flags(flags); cli();
+ transmit_chars(info);
+ restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, total = 0;
+ struct m68k_async_struct *info = (struct m68k_async_struct *)tty->driver_data;
+ unsigned long flags;
+
+ if (serial_paranoia_check(info, tty->device, "rs_write"))
+ return 0;
+
+ if (!tty || !info->xmit_buf)
+ return 0;
+
+ save_flags(flags);
+ while (1) {
+ cli();
+ c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+ if (from_user) {
+ down(&tmp_buf_sem);
+ memcpy_fromfs(tmp_buf, buf, c);
+ c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ up(&tmp_buf_sem);
+ } else
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+ && !info->tx_active)
+ transmit_chars(info);
+ restore_flags(flags);
+ return total;
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void SCC_throttle(struct m68k_async_struct *info, int status)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (status) {
+ /*
+ * Here we want to turn off the RTS line. On Macintoshes,
+ * we only get the DTR line, which goes to both DTR and
+ * RTS on the modem. RTS doesn't go out to the serial
+ * port socket. So you should make sure your modem is
+ * set to ignore DTR if you're using CRTSCTS.
+ */
+ info->private->curregs[5] &= ~(DTR | RTS);
+ info->private->pendregs[5] &= ~(DTR | RTS);
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ } else {
+ /* Assert RTS and DTR lines */
+ info->private->curregs[5] |= DTR | RTS;
+ info->private->pendregs[5] |= DTR | RTS;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+
+ restore_flags(flags);
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+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;
+}
+
+/* FIXME: set_serial_info needs check_custom_divisor !!! */
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int SCC_get_lsr_info(struct m68k_async_struct * info, unsigned int *value)
+{
+ unsigned char status;
+
+ cli();
+ status = read_zsreg(info->private->zs_channel, 0);
+ sti();
+ return status;
+}
+
+static unsigned int SCC_get_modem_info(struct m68k_async_struct *info)
+{
+ unsigned char control, status;
+ unsigned int result;
+
+ cli();
+ control = info->private->curregs[5];
+ status = read_zsreg(info->private->zs_channel, 0);
+ sti();
+ result = ((control & RTS) ? TIOCM_RTS: 0)
+ | ((control & DTR) ? TIOCM_DTR: 0)
+ | ((status & DCD) ? TIOCM_CAR: 0)
+ | ((status & CTS) ? 0: TIOCM_CTS);
+ return result;
+}
+
+/* FIXME: zs_setdtr was used in rs_open ... */
+
+static int SCC_set_modem_info(struct m68k_async_struct *info,
+ int new_dtr, int new_rts)
+{
+ int error;
+ unsigned int arg, bits;
+
+ bits = (new_rts ? RTS: 0) + (new_dtr ? DTR: 0);
+ info->private->curregs[5] = (info->private->curregs[5] & ~(DTR | RTS)) | bits;
+ info->private->pendregs[5] = info->private->curregs[5];
+ write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);
+ sti();
+ return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void SCC_set_break(struct m68k_async_struct * info, int break_flag)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ if (break_flag) {
+ info->private->curregs[5] |= SND_BRK;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ } else {
+ info->private->curregs[5] &= ~SND_BRK;
+ write_zsreg(info->private->zs_channel, 5,
+ info->private->curregs[5]);
+ }
+
+ restore_flags(flags);
+}
+
+/* FIXME: these have to be enabled in rs_ioctl !! */
+
+static int SCC_ioctl(struct tty_struct *tty, struct file * file,
+ struct m68k_async_struct * info, unsigned int cmd,
+ unsigned long arg)
+{
+ int error;
+ int retval;
+
+ switch (cmd) {
+ case TIOCSERGETLSR: /* Get line status register */
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
+ if (error)
+ return error;
+ else
+ return SCC_get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct m68k_async_struct));
+ if (error)
+ return error;
+ copy_to_user((struct m68k_async_struct *) arg,
+ info, sizeof(struct m68k_async_struct));
+ return 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void SCC_stop_receive (struct m68k_async_struct *info)
+{
+ /* disable Rx */
+ info->private->curregs[3] &= ~RxENABLE;
+ info->private->pendregs[3] = info->private->curregs[3];
+ write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);
+ /* disable Rx interrupts */
+ info->private->curregs[1] &= ~(0x18); /* disable any rx ints */
+ info->private->pendregs[1] = info->private->curregs[1];
+ write_zsreg(info->private->zs_channel, 1, info->private->curregs[1]);
+ ZS_CLEARFIFO(info->private->zs_channel);
+}
+
+static int SCC_trans_empty (struct m68k_async_struct *info)
+{
+ return (read_zsreg(info->private->zs_channel, 1) & ALL_SNT) != 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+#ifdef CONFIG_MAC
+
+/*
+ * Mac: use boot_info data; assume 2 channels
+ */
+
+static void probe_sccs(void)
+{
+ int n;
+
+#define ZS_CONTROL 0x50F04000
+#define ZS_DATA (ZS_CONTROL+4)
+#define ZS_IRQ 5
+#define ZS_MOVE -2
+#define ZS_DATA_MOVE 4
+#define ZS_CH_A_FIRST 2
+
+ /* last-ditch fixup for NetBSD booter case */
+ if (mac_bi_data.sccbase == 0)
+ mac_bi_data.sccbase = ZS_CONTROL;
+
+ /* testing: fix up broken 24 bit addresses (ClassicII) */
+ if ((mac_bi_data.sccbase & 0x00FFFFFF) == mac_bi_data.sccbase)
+ mac_bi_data.sccbase |= 0x50000000;
+
+ for(n=0;n<2;n++)
+ {
+#if 0
+ zs_channels[n].control = (volatile unsigned char *)
+ 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 *)
+ (mac_bi_data.sccbase+ZS_CH_A_FIRST)+ZS_MOVE*n;
+ zs_channels[n].data = (volatile unsigned char *)
+ (mac_bi_data.sccbase+ZS_CH_A_FIRST+ZS_DATA_MOVE)+ZS_MOVE*n;
+#endif
+ zs_soft[n].private = &zs_soft_private[n];
+ zs_soft[n].private->zs_channel = &zs_channels[n];
+ zs_soft[n].irq = IRQ4;
+#if 0
+ if (request_irq(ch->intrs[0], rs_interrupt, 0,
+ "SCC", &zs_soft[n]))
+ panic("macserial: can't get irq %d",
+ ch->intrs[0]);
+#endif
+ if (n & 1)
+ zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+ else
+ zs_soft[n].private->zs_chan_a = &zs_channels[n];
+ }
+
+ zs_channels_found=2;
+}
+
+#else
+
+/*
+ * PowerMAC - query the PROM
+ */
+
+static void show_serial_version(void)
+{
+ printk("PowerMac Z8530 serial driver version 1.00\n");
+}
+
+/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
+static void
+probe_sccs()
+{
+ struct device_node *dev, *ch;
+ struct m68k_async_struct **pp;
+ int n;
+
+ n = 0;
+ pp = &zs_chain;
+ for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+ if (n >= NUM_CHANNELS) {
+ printk("Sorry, can't use %s: no more channels\n",
+ dev->full_name);
+ continue;
+ }
+ for (ch = dev->child; ch != 0; ch = ch->sibling) {
+ if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+ printk("Can't use %s: %d addrs %d intrs\n",
+ ch->full_name, ch->n_addrs, ch->n_intrs);
+ continue;
+ }
+ zs_channels[n].control = (volatile unsigned char *)
+ ch->addrs[0].address;
+ zs_channels[n].data = zs_channels[n].control
+ + ch->addrs[0].size / 2;
+ zs_soft[n].private = &zs_soft_private[n];
+ zs_soft[n].private->zs_channel = &zs_channels[n];
+ zs_soft[n].irq = ch->intrs[0];
+ if (request_irq(ch->intrs[0], mac_SCC_interrupt, 0,
+ "SCC", &zs_soft[n]))
+ panic("macserial: can't get irq %d",
+ ch->intrs[0]);
+ /* XXX this assumes the prom puts chan A before B */
+ if (n & 1)
+ zs_soft[n].private->zs_chan_a = &zs_channels[n-1];
+ else
+ zs_soft[n].private->zs_chan_a = &zs_channels[n];
+
+ *pp = &zs_soft[n];
+ pp = &zs_soft[n].private->zs_next;
+ ++n;
+ }
+ }
+ *pp = 0;
+ zs_channels_found = n;
+}
+
+#endif
+
+extern void register_console(void (*proc)(const char *));
+
+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;
+
+ i = o = io = 0;
+
+ /* Is this one of the serial console lines? */
+ if ((zs_cons_chanout != channel) &&
+ (zs_cons_chanin != channel))
+ return;
+ zs_conschan = ss->private->zs_channel;
+ zs_consinfo = ss;
+
+ /* Register the console output putchar, if necessary */
+ if (zs_cons_chanout == channel) {
+ o = 1;
+ /* double whee.. */
+ if (!consout_registered) {
+ register_console(zs_console_print);
+ consout_registered = 1;
+ }
+ }
+
+ if (zs_cons_chanin == channel) {
+ i = 1;
+ }
+ if (o && i)
+ io = 1;
+ if (ss->private->zs_baud != 9600)
+ panic("Console baud rate weirdness");
+
+ /* Set flag variable for this port so that it cannot be
+ * opened for other uses by accident.
+ */
+ ss->private->is_cons = 1;
+
+ if (io) {
+ if(!msg_printed) {
+ printk("zs%d: console I/O\n", ((channel>>1)&1));
+ msg_printed = 1;
+ }
+ } else {
+ printk("zs%d: console %s\n", ((channel>>1)&1),
+ (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
+ }
+
+ /* FIXME : register interrupt here??? */
+}
+
+volatile int test_done;
+
+/* rs_init inits the driver */
+int mac_SCC_init(void)
+{
+ int channel, line, nr = 0, i;
+ unsigned long flags;
+ struct serial_struct req;
+ struct m68k_async_struct *info;
+
+ printk("Mac68K Z8530 serial driver version 1.01\n");
+
+ /* SCC present at all? */
+ if (MACH_IS_ATARI || MACH_IS_AMIGA
+#if 0
+ || !(MACHW_PRESENT(SCC) || MACHW_PRESENT(ST_ESCC))
+#endif
+ )
+ return( -ENODEV );
+
+ if (zs_chain == 0)
+ probe_sccs();
+
+ save_flags(flags);
+ cli();
+
+ /*
+ * FIXME: init of rs_table entry and register_serial now done,
+ * but possible clash of zs_soft[channel] and rs_table[channel]!!
+ * zs_soft initialized in probe_sccs(), some settings copied to
+ * info = &rs_table[channel], which is used by the mid-level code.
+ * The info->private part is shared among both!
+ */
+
+ 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;
+
+ if ((line = register_serial( &req )) >= 0) {
+ SCC_init_port( &rs_table[line], req.type, line );
+ ++nr;
+ }
+ else
+ printk(KERN_WARNING "Cannot allocate ttyS%d for SCC channel A\n", req.line );
+ }
+
+ restore_flags(flags);
+
+ return( nr > 0 ? 0 : -ENODEV );
+}
+
+/* Hooks for running a serial console. con_init() calls this if the
+ * console is being run over one of the serial ports.
+ * 'channel' is decoded as 0=modem 1=printer, 'chip' is ignored.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+ if (zs_chain == 0)
+ probe_sccs();
+ zs_soft[channel].private->clk_divisor = 16;
+ zs_soft[channel].private->zs_baud = get_zsbaud(&zs_soft[channel]);
+ rs_cons_check(&zs_soft[channel], channel);
+ if (out)
+ zs_cons_chanout = channel;
+ else
+ zs_cons_chanin = channel;
+
+ /* FIXME : register interrupt here??? */
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line. The 'tty_num' argument is 0 for /dev/ttyS0 and 1
+ * for /dev/ttyS1 which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+ if (zs_chain == 0)
+ probe_sccs();
+ zs_kgdbchan = zs_soft[tty_num].private->zs_channel;
+ zs_soft[tty_num].private->clk_divisor = 16;
+ zs_soft[tty_num].private->zs_baud = get_zsbaud(&zs_soft[tty_num]);
+ zs_soft[tty_num].private->kgdb_channel = 1; /* This runs kgdb */
+ zs_soft[tty_num ^ 1].private->kgdb_channel = 0; /* This does not */
+ /* Turn on transmitter/receiver at 8-bits/char */
+ kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+ ZS_CLEARERR(zs_kgdbchan);
+ ZS_CLEARFIFO(zs_kgdbchan);
+
+ /* FIXME : register interrupt here??? */
+}
+
diff --git a/drivers/char/mac_SCC.h b/drivers/char/mac_SCC.h
new file mode 100644
index 000000000..5e903e1db
--- /dev/null
+++ b/drivers/char/mac_SCC.h
@@ -0,0 +1,321 @@
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _MAC_SCC_H
+#define _MAC_SCC_H
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output. 65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF 0
+#define ZILOG_CLOSING_WAIT_NONE 65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
+ on the callout port */
+#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK 0x0030
+#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+/* MSch: gone to <asm/serial.h> */
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define FLAG 0x7e
+
+/* Write Register 0 */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
+#define INT_ERR_Rx 0x18 /* Int on error only */
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+#define RxNBITS_MASK 0xc0
+
+/* Write Register 4 */
+
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+#define SB_MASK 0xc
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xC0 /* x64 clock mode */
+#define XCLK_MASK 0xC0
+
+/* Write Register 5 */
+
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define TxNBITS_MASK 0x60
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define FRM_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10 (misc status bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ garbage = read_zsdata(channel); \
+ } while(0)
+
+#endif /* !(_MAC_SCC_H) */
diff --git a/drivers/char/macmouse.c b/drivers/char/macmouse.c
index 0cf1fab20..2d7145203 100644
--- a/drivers/char/macmouse.c
+++ b/drivers/char/macmouse.c
@@ -227,7 +227,7 @@ static ssize_t read_mouse(struct file *file, char *buffer, size_t count,
static unsigned int mouse_poll(struct file *file, poll_table *wait)
{
- poll_wait(&mouse.wait, wait);
+ poll_wait(file, &mouse.wait, wait);
if (mouse.ready)
return POLLIN | POLLRDNORM;
return 0;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 9a0fe22de..2e1c46973 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -27,19 +27,22 @@
#include <asm/pgtable.h>
#ifdef CONFIG_SOUND
+void soundcore_init(void);
+#ifdef CONFIG_SOUND_OSS
void soundcard_init(void);
#endif
+#ifdef CONFIG_DMASOUND
+void dmasound_init(void);
+#endif
+#endif
#ifdef CONFIG_ISDN
int isdn_init(void);
#endif
-#ifdef CONFIG_PCWATCHDOG
-int pcwatchdog_init(void);
-#endif
#ifdef CONFIG_VIDEO_DEV
extern int videodev_init(void);
#endif
-#if defined(CONFIG_FB)
-extern void fbmem_init( void );
+#ifdef CONFIG_FB
+extern void fbmem_init(void);
#endif
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
@@ -60,7 +63,7 @@ static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
written+=sz;
}
#endif
- if (copy_from_user(p, buf, count) < 0)
+ if (copy_from_user(p, buf, count))
return -EFAULT;
written += count;
*ppos += written;
@@ -101,7 +104,7 @@ static ssize_t read_mem(struct file * file, char * buf,
}
}
#endif
- if (copy_to_user(buf, __va(p), count) < 0)
+ if (copy_to_user(buf, __va(p), count))
return -EFAULT;
read += count;
*ppos += read;
@@ -260,45 +263,55 @@ static ssize_t write_null(struct file * file, const char * buf,
*/
static inline size_t read_zero_pagealigned(char * buf, size_t size)
{
+ struct mm_struct *mm;
struct vm_area_struct * vma;
unsigned long addr=(unsigned long)buf;
+ mm = current->mm;
+ /* Oops, this was forgotten before. -ben */
+ down(&mm->mmap_sem);
+
/* For private mappings, just map in zero pages. */
- for (vma = find_vma(current->mm, addr); vma; vma = vma->vm_next) {
+ for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
unsigned long count;
if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0)
- return size;
+ goto out_up;
if (vma->vm_flags & VM_SHARED)
break;
count = vma->vm_end - addr;
if (count > size)
count = size;
- flush_cache_range(current->mm, addr, addr + count);
- zap_page_range(current->mm, addr, count);
+ flush_cache_range(mm, addr, addr + count);
+ zap_page_range(mm, addr, count);
zeromap_page_range(addr, count, PAGE_COPY);
- flush_tlb_range(current->mm, addr, addr + count);
+ flush_tlb_range(mm, addr, addr + count);
size -= count;
buf += count;
addr += count;
if (size == 0)
- return 0;
+ goto out_up;
}
+
+ up(&mm->mmap_sem);
- /* The shared case is hard. Lets do the conventional zeroing. */
+ /* The shared case is hard. Let's do the conventional zeroing. */
do {
unsigned long unwritten = clear_user(buf, PAGE_SIZE);
if (unwritten)
return size + unwritten - PAGE_SIZE;
- if (need_resched)
+ if (current->need_resched)
schedule();
buf += PAGE_SIZE;
size -= PAGE_SIZE;
} while (size);
return size;
+out_up:
+ up(&mm->mmap_sem);
+ return size;
}
static ssize_t read_zero(struct file * file, char * buf,
@@ -533,18 +546,24 @@ __initfunc(int chr_dev_init(void))
defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \
defined (CONFIG_AMIGAMOUSE) || defined (CONFIG_ATARIMOUSE) || \
- defined (CONFIG_PCWATCHDOG) || \
+ defined (CONFIG_MACMOUSE) || defined (CONFIG_PCWATCHDOG) || \
defined (CONFIG_APM) || defined (CONFIG_RTC) || \
defined (CONFIG_SGI_DS1286) || defined (CONFIG_SUN_MOUSE) || \
defined (CONFIG_NVRAM)
misc_init();
#endif
#ifdef CONFIG_SOUND
+ soundcore_init();
+#ifdef CONFIG_SOUND_OSS
soundcard_init();
+#endif
+#ifdef CONFIG_DMASOUND
+ dmasound_init();
+#endif
#endif
#ifdef CONFIG_JOYSTICK
/*
- * Some joysticks only appear when the soundcard they are
+ * Some joysticks only appear when the sound card they are
* connected to is configured. Keep the sound/joystick ordering.
*/
js_init();
@@ -558,6 +577,9 @@ __initfunc(int chr_dev_init(void))
#ifdef CONFIG_FTAPE
ftape_init();
#endif
+#ifdef CONFIG_VIDEO_BT848
+ i2c_init();
+#endif
#ifdef CONFIG_VIDEO_DEV
videodev_init();
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index e2b5bfa41..8b4b16b99 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -65,13 +65,16 @@ static struct miscdevice misc_list = { 0, "head", NULL, &misc_list, &misc_list }
static unsigned char misc_minors[DYNAMIC_MINORS / 8];
#ifndef MODULE
+extern int adbdev_init(void);
extern int bus_mouse_init(void);
extern int psaux_init(void);
extern int ms_bus_mouse_init(void);
extern int atixl_busmouse_init(void);
extern int amiga_mouse_init(void);
extern int atari_mouse_init(void);
+extern int mac_mouse_init(void);
extern int sun_mouse_init(void);
+extern int adb_mouse_init(void);
extern void gfx_register(void);
extern void streamable_init(void);
extern void watchdog_init(void);
@@ -79,13 +82,13 @@ extern void wdt_init(void);
extern void acq_init(void);
extern void pcwatchdog_init(void);
extern int rtc_init(void);
+extern int ds1286_init(void);
extern int dsp56k_init(void);
extern int nvram_init(void);
extern int radio_init(void);
extern void hfmodem_init(void);
-#ifdef CONFIG_PC110_PAD
extern int pc110pad_init(void);
-#endif
+extern int pmu_device_init(void);
#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -206,6 +209,9 @@ __initfunc(int misc_init(void))
if (proc_misc)
proc_misc->read_proc = misc_read_proc;
#endif /* PROC_FS */
+#ifdef CONFIG_MAC
+ adbdev_init();
+#endif
#ifdef CONFIG_BUSMOUSE
bus_mouse_init();
#endif
@@ -224,9 +230,15 @@ __initfunc(int misc_init(void))
#ifdef CONFIG_ATARIMOUSE
atari_mouse_init();
#endif
+#ifdef CONFIG_MACMOUSE
+ mac_mouse_init();
+#endif
#ifdef CONFIG_SUN_MOUSE
sun_mouse_init();
#endif
+#ifdef CONFIG_MACMOUSE
+ adb_mouse_init();
+#endif
#ifdef CONFIG_PC110_PAD
pc110pad_init();
#endif
@@ -254,7 +266,7 @@ __initfunc(int misc_init(void))
#ifdef CONFIG_H8
h8_init();
#endif
-#ifdef CONFIG_RTC
+#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
rtc_init();
#endif
#ifdef CONFIG_SGI_DS1286
@@ -275,6 +287,9 @@ __initfunc(int misc_init(void))
#ifdef CONFIG_HFMODEM
hfmodem_init();
#endif
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_device_init();
+#endif
#ifdef CONFIG_SGI_GRAPHICS
gfx_register ();
streamable_init ();
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
index 0d5f02638..18cce49dd 100644
--- a/drivers/char/msp3400.c
+++ b/drivers/char/msp3400.c
@@ -5,17 +5,17 @@
*
* what works and what doesn't:
*
- * AM-Mono
+ * AM mono
* probably doesn't (untested)
*
- * FM-Mono
- * should work. The stereo modes are backward compatible to FM-mono,
- * therefore FM-Mono should be allways available.
+ * FM-mono
+ * should work. FM stereo modes are backward-compatible to mono.
+ * Therefore FM mono should always be 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)
*
@@ -37,34 +37,49 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/malloc.h>
-/* #include <asm/smp_lock.h> */
/* kernel_thread */
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
-#include "i2c.h"
+#include <linux/i2c.h>
#include <linux/videodev.h>
#include "msp3400.h"
-int debug = 0; /* insmod parameter */
-struct msp3400c
-{
+/* sound mixer stuff */
+#include <linux/config.h>
+
+#if LINUX_VERSION_CODE > 0x020140 /* need modular sound driver */
+# if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+# define REGISTER_MIXER 1
+# endif
+#endif
+
+
+static int debug = 0; /* insmod parameter */
+
+struct msp3400c {
struct i2c_bus *bus;
int nicam;
int mode;
int norm;
- int volume;
int stereo;
+ int mixer;
+ int left, right; /* volume */
+ int bass, treble;
+
/* thread */
- struct task_struct *thread;
- struct semaphore *wait;
- struct semaphore *notify;
- int active,restart,rmmod;
+ struct task_struct *thread;
+ struct semaphore *wait;
+ struct semaphore *notify;
+ int active,restart,rmmod;
+
+ int watch_stereo;
+ struct timer_list wake_stereo;
};
#define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */
@@ -88,82 +103,73 @@ static int msp3400c_reset(struct i2c_bus *bus)
{
int ret = 0;
- udelay(2000);
+ mdelay(2);
i2c_start(bus);
i2c_sendbyte(bus, I2C_MSP3400C,2000);
i2c_sendbyte(bus, 0x00,0);
i2c_sendbyte(bus, 0x80,0);
i2c_sendbyte(bus, 0x00,0);
i2c_stop(bus);
- udelay(2000);
+ mdelay(2);
i2c_start(bus);
if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
- 0 != i2c_sendbyte(bus, 0x00,0) ||
- 0 != i2c_sendbyte(bus, 0x00,0) ||
- 0 != i2c_sendbyte(bus, 0x00,0))
- {
+ 0 != i2c_sendbyte(bus, 0x00,0) ||
+ 0 != i2c_sendbyte(bus, 0x00,0) ||
+ 0 != i2c_sendbyte(bus, 0x00,0)) {
ret = -1;
printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n");
}
i2c_stop(bus);
- udelay(2000);
+ mdelay(2);
return ret;
}
-static int msp3400c_read(struct i2c_bus *bus, int dev, int addr)
+static int
+msp3400c_read(struct i2c_bus *bus, int dev, int addr)
{
int ret=0;
short val = 0;
i2c_start(bus);
if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
- 0 != i2c_sendbyte(bus, dev+1, 0) ||
- 0 != i2c_sendbyte(bus, addr >> 8, 0) ||
- 0 != i2c_sendbyte(bus, addr & 0xff, 0))
- {
+ 0 != i2c_sendbyte(bus, dev+1, 0) ||
+ 0 != i2c_sendbyte(bus, addr >> 8, 0) ||
+ 0 != i2c_sendbyte(bus, addr & 0xff, 0)) {
ret = -1;
- }
- else
- {
+ } else {
i2c_start(bus);
- if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000))
- {
+ if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000)) {
ret = -1;
- }
- else
- {
+ } else {
val |= (int)i2c_readbyte(bus,0) << 8;
val |= (int)i2c_readbyte(bus,1);
}
}
i2c_stop(bus);
- if (-1 == ret)
- {
+ if (-1 == ret) {
printk(KERN_WARNING "msp3400: I/O error, trying reset (read %s 0x%x)\n",
- (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
+ (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
msp3400c_reset(bus);
}
return val;
}
-static int msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val)
+static int
+msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val)
{
int ret = 0;
i2c_start(bus);
if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) ||
- 0 != i2c_sendbyte(bus, dev, 0) ||
- 0 != i2c_sendbyte(bus, addr >> 8, 0) ||
- 0 != i2c_sendbyte(bus, addr & 0xff, 0) ||
- 0 != i2c_sendbyte(bus, val >> 8, 0) ||
- 0 != i2c_sendbyte(bus, val & 0xff, 0))
- {
+ 0 != i2c_sendbyte(bus, dev, 0) ||
+ 0 != i2c_sendbyte(bus, addr >> 8, 0) ||
+ 0 != i2c_sendbyte(bus, addr & 0xff, 0) ||
+ 0 != i2c_sendbyte(bus, val >> 8, 0) ||
+ 0 != i2c_sendbyte(bus, val & 0xff, 0))
ret = -1;
- }
i2c_stop(bus);
- if (-1 == ret)
- {
- printk(KERN_ERR "msp3400: I/O error, trying reset (write %s 0x%x)\n",
- (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
+ if (-1 == ret) {
+ printk(KERN_WARNING "msp3400: I/O error, trying reset (write %s 0x%x)\n",
+ (dev == I2C_MSP3400C_DEM) ? "Demod" : "Audio", addr);
msp3400c_reset(bus);
}
return ret;
@@ -182,8 +188,7 @@ static int msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val)
#define MSP_MODE_FM_NICAM1 5
#define MSP_MODE_FM_NICAM2 6
-static struct MSP_INIT_DATA_DEM
-{
+static struct MSP_INIT_DATA_DEM {
int fir1[6];
int fir2[6];
int cdo1;
@@ -193,43 +198,48 @@ static struct MSP_INIT_DATA_DEM
int dfp_src;
int dfp_matrix;
} msp_init_data[] = {
- /* AM (for carrier detect / msp3400) */
- { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0500, 0x0020, 0x3000},
-
- /* AM (for carrier detect / msp3410) */
- { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0100, 0x0020, 0x3000},
-
- /* FM Radio */
- { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
- MSP_CARRIER(10.7), MSP_CARRIER(10.7), 0x00d0, 0x0480, 0x0020, 0x3002 },
-
- /* Terrestial FM-mono */
- { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0480, 0x0030, 0x3000},
-
- /* Sat FM-mono */
- { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000},
-
- /* NICAM B/G, D/K */
- { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000},
-
- /* NICAM I */
- { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 },
- MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000},
+ /* AM (for carrier detect / msp3400) */
+ { { 75, 19, 36, 35, 39, 40 }, { 75, 19, 36, 35, 39, 40 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0500, 0x0020, 0x3000},
+
+ /* AM (for carrier detect / msp3410) */
+ { { -1, -1, -8, 2, 59, 126 }, { -1, -1, -8, 2, 59, 126 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0100, 0x0020, 0x3000},
+
+ /* FM Radio */
+ { { -8, -8, 4, 6, 78, 107 }, { -8, -8, 4, 6, 78, 107 },
+ MSP_CARRIER(10.7), MSP_CARRIER(10.7),
+ 0x00d0, 0x0480, 0x0020, 0x3002 },
+
+ /* Terrestial FM-mono */
+ { { 3, 18, 27, 48, 66, 72 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0480, 0x0030, 0x3000},
+
+ /* Sat FM-mono */
+ { { 1, 9, 14, 24, 33, 37 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(6.5), MSP_CARRIER(6.5),
+ 0x00c6, 0x0480, 0x0000, 0x3000},
+
+ /* NICAM B/G, D/K */
+ { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0040, 0x0120, 0x3000},
+
+ /* NICAM I */
+ { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 },
+ MSP_CARRIER(5.5), MSP_CARRIER(5.5),
+ 0x00d0, 0x0040, 0x0120, 0x3000},
};
-struct CARRIER_DETECT
-{
+struct CARRIER_DETECT {
int cdo;
char *name;
};
-static struct CARRIER_DETECT carrier_detect_main[] =
-{
+static struct CARRIER_DETECT carrier_detect_main[] = {
/* main carrier */
{ MSP_CARRIER(4.5), "4.5 NTSC" },
{ MSP_CARRIER(5.5), "5.5 PAL B/G" },
@@ -262,15 +272,39 @@ static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2)
msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12);
}
-static void msp3400c_setvolume(struct i2c_bus *bus, int vol)
+static void msp3400c_setvolume(struct i2c_bus *bus, int left, int right)
{
- int val = (vol * 0x73 / 65535) << 8;
+ int vol,val,balance;
+
+ vol = (left > right) ? left : right;
+ val = (vol * 0x73 / 65535) << 8;
+ balance = 0;
+ if (vol > 0)
+ balance = ((right-left) * 127) / vol;
- dprintk("msp3400: setvolume: 0x%02x\n",val>>8);
+ dprintk("msp3400: setvolume: %d:%d 0x%02x 0x%02x\n",
+ left,right,val>>8,balance);
msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */
/* scart - on/off only */
msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0);
+ msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0001, balance << 8);
+}
+
+static void msp3400c_setbass(struct i2c_bus *bus, int bass)
+{
+ int val = ((bass-32768) * 0x60 / 65535) << 8;
+
+ dprintk("msp3400: setbass: %d 0x%02x\n",bass, val>>8);
+ msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
+}
+
+static void msp3400c_settreble(struct i2c_bus *bus, int treble)
+{
+ int val = ((treble-32768) * 0x60 / 65535) << 8;
+
+ dprintk("msp3400: settreble: %d 0x%02x\n",treble, val>>8);
+ msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
}
static void msp3400c_setmode(struct msp3400c *msp, int type)
@@ -282,38 +316,37 @@ static void msp3400c_setmode(struct msp3400c *msp, int type)
msp->stereo = VIDEO_SOUND_MONO;
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */
- msp_init_data[type].ad_cv);
+ msp_init_data[type].ad_cv);
for (i = 5; i >= 0; i--) /* fir 1 */
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0001,
- msp_init_data[type].fir1[i]);
+ msp_init_data[type].fir1[i]);
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0040);
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0000);
for (i = 5; i >= 0; i--)
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005,
- msp_init_data[type].fir2[i]);
+ msp_init_data[type].fir2[i]);
msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */
- msp_init_data[type].mode_reg);
+ msp_init_data[type].mode_reg);
msp3400c_setcarrier(msp->bus, msp_init_data[type].cdo1,
- msp_init_data[type].cdo2);
+ msp_init_data[type].cdo2);
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,
- msp_init_data[type].dfp_src);
+ msp_init_data[type].dfp_src);
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,
- msp_init_data[type].dfp_src);
+ msp_init_data[type].dfp_src);
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,
- msp_init_data[type].dfp_src);
+ msp_init_data[type].dfp_src);
msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e,
- msp_init_data[type].dfp_matrix);
+ msp_init_data[type].dfp_matrix);
- if (msp->nicam)
- {
+ if (msp->nicam) {
/* msp3410 needs some more initialization */
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0010, 0x3000);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0010, 0x3000);
}
}
@@ -322,86 +355,81 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode)
int nicam=0; /* channel source: FM/AM or nicam */
/* switch demodulator */
- switch (msp->mode)
- {
- case MSP_MODE_FM_TERRA:
- dprintk("msp3400: B/G setstereo: %d\n",mode);
- msp->stereo = mode;
- msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.7421875),MSP_CARRIER(5.5));
- switch (mode)
- {
- case VIDEO_SOUND_STEREO:
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001);
- break;
- case VIDEO_SOUND_MONO:
- case VIDEO_SOUND_LANG1:
- case VIDEO_SOUND_LANG2:
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3000);
- break;
- }
+ switch (msp->mode) {
+ case MSP_MODE_FM_TERRA:
+ dprintk("msp3400: B/G setstereo: %d\n",mode);
+ msp->stereo = mode;
+ msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.7421875),MSP_CARRIER(5.5));
+ switch (mode) {
+ case VIDEO_SOUND_STEREO:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001);
break;
- case MSP_MODE_FM_SAT:
- dprintk("msp3400: sat setstereo: %d\n",mode);
- msp->stereo = mode;
- switch (mode)
- {
- case VIDEO_SOUND_MONO:
- msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
- break;
- case VIDEO_SOUND_STEREO:
- msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
- break;
- case VIDEO_SOUND_LANG1:
- msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
- break;
- case VIDEO_SOUND_LANG2:
- msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
- break;
- }
+ case VIDEO_SOUND_MONO:
+ case VIDEO_SOUND_LANG1:
+ case VIDEO_SOUND_LANG2:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3000);
break;
- case MSP_MODE_FM_NICAM1:
- dprintk("msp3400: NICAM1 setstereo: %d\n",mode);
- msp->stereo = mode;
- msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.85),MSP_CARRIER(5.5));
- nicam=0x0100;
+ }
+ break;
+ case MSP_MODE_FM_SAT:
+ dprintk("msp3400: sat setstereo: %d\n",mode);
+ msp->stereo = mode;
+ switch (mode) {
+ case VIDEO_SOUND_MONO:
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
break;
- default:
- /* can't do stereo - abort here */
- return;
- }
-
- /* switch audio */
- switch (mode)
- {
case VIDEO_SOUND_STEREO:
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0020|nicam);
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0020|nicam);
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0020|nicam);
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005, 0x4000);
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.2), MSP_CARRIER(7.02));
break;
- case VIDEO_SOUND_MONO:
case VIDEO_SOUND_LANG1:
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0000|nicam);
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0000|nicam);
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0000|nicam);
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
break;
case VIDEO_SOUND_LANG2:
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, 0x0010|nicam);
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, 0x0010|nicam);
- msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, 0x0010|nicam);
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02));
break;
+ }
+ break;
+ case MSP_MODE_FM_NICAM1:
+ dprintk("msp3400: NICAM1 setstereo: %d\n",mode);
+ msp->stereo = mode;
+ msp3400c_setcarrier(msp->bus,MSP_CARRIER(5.85),MSP_CARRIER(5.5));
+ nicam=0x0100;
+ break;
+ default:
+ /* can't do stereo - abort here */
+ return;
+ }
+
+ /* switch audio */
+ switch (mode) {
+ case VIDEO_SOUND_STEREO:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0020|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0020|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0020|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005,0x4000);
+ break;
+ case VIDEO_SOUND_MONO:
+ case VIDEO_SOUND_LANG1:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0000|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0000|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0000|nicam);
+ break;
+ case VIDEO_SOUND_LANG2:
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,0x0010|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,0x0010|nicam);
+ msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,0x0010|nicam);
+ break;
}
}
/* ----------------------------------------------------------------------- */
struct REGISTER_DUMP {
- int addr;
+ int addr;
char *name;
};
-struct REGISTER_DUMP d1[] =
-{
+struct REGISTER_DUMP d1[] = {
{ 0x007e, "autodetect" },
{ 0x0023, "C_AD_BITS " },
{ 0x0038, "ADD_BITS " },
@@ -414,15 +442,23 @@ struct REGISTER_DUMP d1[] =
* in the ioctl while doing the sound carrier & stereo detect
*/
-int msp3400c_thread(void *data)
+static void msp3400c_stereo_wake(unsigned long data)
+{
+ struct msp3400c *msp = (struct msp3400c*)data; /* XXX alpha ??? */
+
+ if (!msp->active)
+ up(msp->wait);
+}
+
+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, check_stereo;
- int i;
+ int count, max1,max2,val1,val2, val,this;
+ int newstereo;
/* lock_kernel(); */
@@ -442,57 +478,87 @@ int msp3400c_thread(void *data)
if(msp->notify != NULL)
up(msp->notify);
- for (;;)
- {
+ for (;;) {
if (msp->rmmod)
goto done;
dprintk("msp3400: thread: sleep\n");
down_interruptible(&sem);
dprintk("msp3400: thread: wakeup\n");
- if (msp->rmmod)
+ if (msp->rmmod || signal_pending(current))
goto done;
-#if 0
- if (VIDEO_MODE_RADIO == msp->norm)
- {
- msp->active = 1;
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + HZ/10;
- schedule();
- if (signal_pending(current))
- goto done;
+
+ if (VIDEO_MODE_RADIO == msp->norm)
+ continue; /* nothing to do */
+
+ msp->active = 1;
+
+ if (msp->watch_stereo) {
+ /* do that stereo/multilang handling */
LOCK_I2C_BUS(msp->bus);
- val1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b);
- val2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
+ newstereo = msp->stereo;
+ switch (msp->mode) {
+ case MSP_MODE_FM_TERRA:
+ val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18);
+ dprintk("msp3400: stereo detect register: %d\n",val);
+
+ if (val > 4096) {
+ newstereo = VIDEO_SOUND_STEREO;
+ } else if (val < -4096) {
+ newstereo = VIDEO_SOUND_LANG1;
+ } else {
+ newstereo = VIDEO_SOUND_MONO;
+ }
+ break;
+ case MSP_MODE_FM_NICAM1:
+ val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23);
+ switch ((val & 0x1e) >> 1) {
+ case 0:
+ case 8:
+ newstereo = VIDEO_SOUND_STEREO;
+ break;
+ default:
+ newstereo = VIDEO_SOUND_MONO;
+ break;
+ }
+ break;
+ }
+ if (msp->stereo != newstereo) {
+ dprintk("msp3400: watch: stereo %d ==> %d\n",
+ msp->stereo,newstereo);
+ msp3400c_setstereo(msp,newstereo);
+ }
UNLOCK_I2C_BUS(msp->bus);
- printk("msp3400: DC %d/%d\n",val1,val2);
+ if (msp->watch_stereo) {
+ del_timer(&msp->wake_stereo);
+ msp->wake_stereo.expires = jiffies + 5*HZ;
+ add_timer(&msp->wake_stereo);
+ }
+
msp->active = 0;
continue;
}
-#endif
-
- if (VIDEO_MODE_RADIO == msp->norm)
- continue; /* nothing to do */
- msp->active = 1;
-restart:
+ restart:
LOCK_I2C_BUS(msp->bus);
- msp3400c_setvolume(msp->bus, 0);
+ msp3400c_setvolume(msp->bus, 0, 0);
msp3400c_setmode(msp, MSP_MODE_AM_DETECT);
- val1 = val2 = max1 = max2 = check_stereo = 0;
+ val1 = val2 = 0;
+ max1 = max2 = -1;
+ del_timer(&msp->wake_stereo);
+ msp->watch_stereo = 0;
/* carrier detect pass #1 -- main carrier */
cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main);
- for (this = 0; this < count; this++)
- {
+ for (this = 0; this < count; this++) {
msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
UNLOCK_I2C_BUS(msp->bus);
+
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + HZ/25;
schedule();
if (signal_pending(current))
goto done;
- if (msp->restart)
- {
+ if (msp->restart) {
msp->restart = 0;
goto restart;
}
@@ -505,22 +571,20 @@ restart:
}
/* carrier detect pass #2 -- second (stereo) carrier */
- switch (max1)
- {
- case 1: /* 5.5 */
- cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55);
- break;
- case 3: /* 6.5 */
- cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65);
- break;
- case 0: /* 4.5 */
- case 2: /* 6.0 */
- default:
- cd = NULL; count = 0;
- break;
+ switch (max1) {
+ case 1: /* 5.5 */
+ cd = carrier_detect_55; count = CARRIER_COUNT(carrier_detect_55);
+ break;
+ case 3: /* 6.5 */
+ cd = carrier_detect_65; count = CARRIER_COUNT(carrier_detect_65);
+ break;
+ case 0: /* 4.5 */
+ case 2: /* 6.0 */
+ default:
+ cd = NULL; count = 0;
+ break;
}
- for (this = 0; this < count; this++)
- {
+ for (this = 0; this < count; this++) {
msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo);
UNLOCK_I2C_BUS(msp->bus);
@@ -529,8 +593,7 @@ restart:
schedule();
if (signal_pending(current))
goto done;
- if (msp->restart)
- {
+ if (msp->restart) {
msp->restart = 0;
goto restart;
}
@@ -542,106 +605,46 @@ restart:
dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name);
}
- /* programm the msp3400 according to the results */
- switch (max1)
- {
- case 0: /* 4.5 */
- case 1: /* 5.5 */
- msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
- msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
- carrier_detect_main[max1].cdo);
- if (max2 == 0)
- {
- /* B/G FM-stereo */
- msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
- check_stereo = 1;
- }
- if (max2 == 1 && msp->nicam)
- {
- /* B/G NICAM */
- msp3400c_setmode(msp, MSP_MODE_FM_NICAM1);
- /* msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); */
- msp3400c_setcarrier(msp->bus, MSP_CARRIER(5.85),
- MSP_CARRIER(5.5));
- check_stereo = 1;
- }
- break;
- case 2: /* 6.0 */
- case 3: /* 6.5 */
- default:
- msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
- msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
- carrier_detect_main[max1].cdo);
- msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
- break;
- }
-
- /* unmute */
- msp3400c_setvolume(msp->bus, msp->volume);
-
- if (check_stereo)
- {
- /* stereo available -- check current mode */
- UNLOCK_I2C_BUS(msp->bus);
-
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + HZ;
- schedule();
- if (signal_pending(current))
- goto done;
- if (msp->restart)
- {
- msp->restart = 0;
- goto restart;
+ /* program the msp3400 according to the results */
+ switch (max1) {
+ case 0: /* 4.5 */
+ case 1: /* 5.5 */
+ msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
+ msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
+ carrier_detect_main[max1].cdo);
+ if (max2 == 0) {
+ /* B/G FM-stereo */
+ msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
+ msp->watch_stereo = 1;
}
-
- LOCK_I2C_BUS(msp->bus);
- switch (msp->mode)
- {
- case MSP_MODE_FM_TERRA:
- val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18);
- dprintk("msp3400: stereo detect register: %d\n",val);
-
- if (val > 4096)
- {
- msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
- }
- else if (val < -4096)
- {
- msp3400c_setstereo(msp, VIDEO_SOUND_LANG1);
- }
- else
- {
- msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
- }
- break;
- case MSP_MODE_FM_NICAM1:
- val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23);
- switch ((val & 0x1e) >> 1)
- {
- case 0:
- case 8:
- msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
- break;
- default:
- msp3400c_setstereo(msp, VIDEO_SOUND_MONO);
- break;
- }
-
- /* dump registers (for debugging) */
- if (debug)
- {
- for (i=0; i<sizeof(d1)/sizeof(struct REGISTER_DUMP); i++)
- {
- val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM, d1[i].addr);
- printk(KERN_DEBUG "msp3400: %s = 0x%x\n",
- d1[i].name,val);
- }
- }
- break;
+ if (max2 == 1 && msp->nicam) {
+ /* B/G NICAM */
+ msp3400c_setmode(msp, MSP_MODE_FM_NICAM1);
+ /* msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); */
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(5.85),
+ MSP_CARRIER(5.5));
+ msp->watch_stereo = 1;
}
+ break;
+ case 2: /* 6.0 */
+ case 3: /* 6.5 */
+ default:
+ msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
+ msp3400c_setcarrier(msp->bus, carrier_detect_main[max1].cdo,
+ carrier_detect_main[max1].cdo);
+ msp3400c_setstereo(msp, VIDEO_SOUND_STEREO);
+ break;
}
+
+ /* unmute */
+ msp3400c_setvolume(msp->bus, msp->left, msp->right);
UNLOCK_I2C_BUS(msp->bus);
+
+ if (msp->watch_stereo) {
+ del_timer(&msp->wake_stereo);
+ msp->wake_stereo.expires = jiffies + HZ;
+ add_timer(&msp->wake_stereo);
+ }
msp->active = 0;
}
@@ -656,12 +659,15 @@ done:
return 0;
}
-int msp3410d_thread(void *data)
+
+#if 0 /* not finished yet */
+
+static int msp3410d_thread(void *data)
{
unsigned long flags;
struct msp3400c *msp = data;
struct semaphore sem = MUTEX_LOCKED;
- int i, val;
+ int i, val;
/* lock_kernel(); */
@@ -681,8 +687,7 @@ int msp3410d_thread(void *data)
if(msp->notify != NULL)
up(msp->notify);
- for (;;)
- {
+ for (;;) {
if (msp->rmmod)
goto done;
dprintk("msp3410: thread: sleep\n");
@@ -696,7 +701,7 @@ int msp3410d_thread(void *data)
msp->active = 1;
-restart:
+ restart:
LOCK_I2C_BUS(msp->bus);
/* mute */
msp3400c_setvolume(msp->bus, 0);
@@ -714,16 +719,14 @@ restart:
schedule();
if (signal_pending(current))
goto done;
- if (msp->restart)
- {
+ if (msp->restart) {
msp->restart = 0;
goto restart;
}
LOCK_I2C_BUS(msp->bus);
/* debug register dump */
- for (i = 0; i < sizeof(d1)/sizeof(struct REGISTER_DUMP); i++)
- {
+ for (i = 0; i < sizeof(d1)/sizeof(struct REGISTER_DUMP); i++) {
val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM,d1[i].addr);
printk(KERN_DEBUG "msp3400: %s = 0x%x\n",d1[i].name,val);
}
@@ -744,6 +747,151 @@ done:
up(msp->notify);
return 0;
}
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* mixer stuff -- with the modular sound driver in 2.1.x we can easily */
+/* register the msp3400 as mixer device */
+
+#ifdef REGISTER_MIXER
+
+#include <linux/soundcard.h>
+#include <../drivers/sound/sound_config.h>
+#include <../drivers/sound/dev_table.h>
+
+static int mix_to_v4l(int i)
+{
+ int r;
+
+ r = ((i & 0xff) * 65536 + 50) / 100;
+ if (r > 65535) r = 65535;
+ if (r < 0) r = 0;
+ return r;
+}
+
+static int v4l_to_mix(int i)
+{
+ int r;
+
+ r = (i * 100 + 32768) / 65536;
+ if (r > 100) r = 100;
+ if (r < 0) r = 0;
+ return r | (r << 8);
+}
+
+static int v4l_to_mix2(int l, int r)
+{
+ r = (r * 100 + 32768) / 65536;
+ if (r > 100) r = 100;
+ if (r < 0) r = 0;
+ l = (l * 100 + 32768) / 65536;
+ if (l > 100) l = 100;
+ if (l < 0) l = 0;
+ return (r << 8) | l;
+}
+
+static int msp3400c_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+ struct msp3400c *msp = mixer_devs[dev]->devc;
+ unsigned long flags;
+ int ret,val = 0;
+
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (cmd) {
+ case MIXER_READ(SOUND_MIXER_RECMASK):
+ case MIXER_READ(SOUND_MIXER_CAPS):
+ case MIXER_READ(SOUND_MIXER_RECSRC):
+ case MIXER_WRITE(SOUND_MIXER_RECSRC):
+ ret = 0;
+ break;
+
+ case MIXER_READ(SOUND_MIXER_STEREODEVS):
+ ret = SOUND_MASK_VOLUME;
+ break;
+ case MIXER_READ(SOUND_MIXER_DEVMASK):
+ ret = SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE;
+ 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);
+ /* fall */
+ case MIXER_READ(SOUND_MIXER_VOLUME):
+ ret = v4l_to_mix2(msp->left, msp->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);
+ /* fall */
+ case MIXER_READ(SOUND_MIXER_BASS):
+ ret = v4l_to_mix(msp->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);
+ /* fall */
+ case MIXER_READ(SOUND_MIXER_TREBLE):
+ ret = v4l_to_mix(msp->treble);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ 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)
+{
+ 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;
+}
+
+static int msp3400c_mixer_close(struct msp3400c *msp)
+{
+ int m = msp->mixer;
+
+ if (m != -1 ) {
+ sound_unload_mixerdev(m);
+ kfree(mixer_devs[m]);
+ }
+ return 0;
+}
+
+#endif
/* ----------------------------------------------------------------------- */
@@ -752,35 +900,30 @@ static int msp3400c_attach(struct i2c_device *device)
unsigned long flags;
struct semaphore sem = MUTEX_LOCKED;
struct msp3400c *msp;
- int rev1,rev2;
-
- /*
- * MSP3400's are for now only assumed to live on busses
- * connected to a BT848. Adjust as and when you get new
- * funky cards using these components.
- */
-
- if(device->bus->id != I2C_BUSID_BT848)
- return -EINVAL;
+ int rev1,rev2;
device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL);
if (NULL == msp)
return -ENOMEM;
memset(msp,0,sizeof(struct msp3400c));
msp->bus = device->bus;
- msp->volume = 65535;
+ msp->left = 65535;
+ msp->right = 65535;
+ msp->bass = 32768;
+ msp->treble = 32768;
LOCK_I2C_BUS(msp->bus);
- if (-1 == msp3400c_reset(msp->bus))
- {
+ if (-1 == msp3400c_reset(msp->bus)) {
UNLOCK_I2C_BUS(msp->bus);
kfree(msp);
- return -1;
+ return -EIO;
}
msp3400c_setmode(msp, MSP_MODE_FM_TERRA);
- msp3400c_setvolume(msp->bus, msp->volume);
-
+ 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);
@@ -793,17 +936,28 @@ 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;
- printk(KERN_INFO "msp3400: init: chip=%s%s\n",
- device->name, msp->nicam ? ", can decode nicam" : "");
- MOD_INC_USE_COUNT;
+ /* timer for stereo checking */
+ msp->wake_stereo.function = msp3400c_stereo_wake;
+ msp->wake_stereo.data = (unsigned long)msp;
+
/* startup control thread */
+ MOD_INC_USE_COUNT;
msp->notify = &sem;
kernel_thread(msp3400c_thread, (void *)msp, 0);
down(&sem);
msp->notify = NULL;
if (!msp->active)
up(msp->wait);
+
+ 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");
+#endif
+ printk("\n");
return 0;
}
@@ -813,14 +967,22 @@ static int msp3400c_detach(struct i2c_device *device)
struct semaphore sem = MUTEX_LOCKED;
struct msp3400c *msp = (struct msp3400c*)device->data;
+#ifdef REGISTER_MIXER
+ msp3400c_mixer_close(msp);
+#endif
+
/* shutdown control thread */
- msp->notify = &sem;
- msp->rmmod = 1;
- if (!msp->active)
- up(msp->wait);
- down(&sem);
- msp->notify = NULL;
-
+ del_timer(&msp->wake_stereo);
+ if (msp->thread)
+ {
+ msp->notify = &sem;
+ msp->rmmod = 1;
+ if (!msp->active)
+ up(msp->wait);
+ down(&sem);
+ msp->notify = NULL;
+ }
+
LOCK_I2C_BUS(msp->bus);
msp3400c_reset(msp->bus);
UNLOCK_I2C_BUS(msp->bus);
@@ -834,67 +996,90 @@ static int msp3400c_command(struct i2c_device *device,
unsigned int cmd, void *arg)
{
unsigned long flags;
- struct msp3400c *msp = (struct msp3400c*)device->data;
- int *iarg = (int*)arg;
-
- switch (cmd)
- {
- case MSP_SET_RADIO:
- msp->norm = VIDEO_MODE_RADIO;
- LOCK_I2C_BUS(msp->bus);
- msp3400c_setmode(msp,MSP_MODE_FM_RADIO);
- msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
- UNLOCK_I2C_BUS(msp->bus);
- break;
- case MSP_SET_TVNORM:
- msp->norm = *iarg;
- break;
- case MSP_NEWCHANNEL:
- if (!msp->active)
- up(msp->wait);
- else
- msp->restart = 1;
- break;
+ struct msp3400c *msp = (struct msp3400c*)device->data;
+ int *iarg = (int*)arg;
- case MSP_GET_VOLUME:
- *iarg = msp->volume;
- break;
- case MSP_SET_VOLUME:
- msp->volume = *iarg;
- LOCK_I2C_BUS(msp->bus);
- msp3400c_setvolume(msp->bus,msp->volume);
- UNLOCK_I2C_BUS(msp->bus);
- break;
+ switch (cmd) {
+ case MSP_SET_RADIO:
+ msp->norm = VIDEO_MODE_RADIO;
+ msp->watch_stereo=0;
+ del_timer(&msp->wake_stereo);
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setmode(msp,MSP_MODE_FM_RADIO);
+ msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7));
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
+ case MSP_SET_TVNORM:
+ msp->norm = *iarg;
+ break;
+ case MSP_NEWCHANNEL:
+ msp->watch_stereo=0;
+ del_timer(&msp->wake_stereo);
+ if (!msp->active)
+ up(msp->wait);
+ else
+ msp->restart = 1;
+ break;
+
+ case MSP_GET_VOLUME:
+ *iarg = (msp->left > msp->right) ? msp->left : msp->right;
+ break;
+ case MSP_SET_VOLUME:
+ msp->left = msp->right = *iarg;
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setvolume(msp->bus,msp->left, msp->right);
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
- case MSP_GET_STEREO:
- *iarg = msp->stereo;
- break;
- case MSP_SET_STEREO:
- if (*iarg)
- {
- LOCK_I2C_BUS(msp->bus);
- msp3400c_setstereo(msp,*iarg);
- UNLOCK_I2C_BUS(msp->bus);
- }
- break;
+ case MSP_GET_BASS:
+ *iarg = msp->bass;
+ break;
+ case MSP_SET_BASS:
+ msp->bass = *iarg;
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_setbass(msp->bus,msp->bass);
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
- case MSP_GET_DC:
+ case MSP_GET_TREBLE:
+ *iarg = msp->treble;
+ break;
+ case MSP_SET_TREBLE:
+ msp->treble = *iarg;
+ LOCK_I2C_BUS(msp->bus);
+ msp3400c_settreble(msp->bus,msp->treble);
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
+
+ case MSP_GET_STEREO:
+ *iarg = msp->stereo;
+ break;
+ case MSP_SET_STEREO:
+ if (*iarg) {
+ msp->watch_stereo=0;
+ del_timer(&msp->wake_stereo);
LOCK_I2C_BUS(msp->bus);
- *iarg = (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) +
- (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
+ msp3400c_setstereo(msp,*iarg);
UNLOCK_I2C_BUS(msp->bus);
- break;
+ }
+ break;
+
+ case MSP_GET_DC:
+ LOCK_I2C_BUS(msp->bus);
+ *iarg = (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) +
+ (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c);
+ UNLOCK_I2C_BUS(msp->bus);
+ break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
return 0;
}
/* ----------------------------------------------------------------------- */
-struct i2c_driver i2c_driver_msp =
-{
+struct i2c_driver i2c_driver_msp = {
"msp3400", /* name */
I2C_DRIVERID_MSP3400, /* ID */
I2C_MSP3400C, I2C_MSP3400C, /* addr range */
@@ -904,10 +1089,12 @@ struct i2c_driver i2c_driver_msp =
msp3400c_command
};
+EXPORT_NO_SYMBOLS;
+
#ifdef MODULE
int init_module(void)
#else
-int msp3400c_init(void)
+ int msp3400c_init(void)
#endif
{
i2c_register_driver(&i2c_driver_msp);
@@ -921,3 +1108,10 @@ void cleanup_module(void)
}
#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/char/msp3400.h b/drivers/char/msp3400.h
index 1b4eedab0..e4029c03e 100644
--- a/drivers/char/msp3400.h
+++ b/drivers/char/msp3400.h
@@ -15,4 +15,9 @@
#define MSP_GET_DC _IOW('m',8,int)
+#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)
+
#endif /* MSP3400_H */
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index a434cf405..1cf7e9d01 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -190,7 +190,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
* opost_block --- to speed up block console writes, among other
* things.
*/
-static int opost_block(struct tty_struct * tty,
+static ssize_t opost_block(struct tty_struct * tty,
const unsigned char * inbuf, unsigned int nr)
{
char buf[80];
@@ -863,9 +863,9 @@ static inline void copy_from_read_buf(struct tty_struct *tty,
static ssize_t read_chan(struct tty_struct *tty, struct file *file,
unsigned char *buf, size_t nr)
{
+ unsigned char *b = buf;
struct wait_queue wait = { current, NULL };
int c;
- unsigned char *b = buf;
int minimum, time;
ssize_t retval = 0;
ssize_t size;
@@ -896,25 +896,23 @@ do_it_again:
}
}
- if (tty->icanon) {
- minimum = time = 0;
- current->timeout = (unsigned long) -1;
- } else {
+ minimum = time = 0;
+ current->timeout = (unsigned long) -1;
+ if (!tty->icanon) {
time = (HZ / 10) * TIME_CHAR(tty);
minimum = MIN_CHAR(tty);
if (minimum) {
- current->timeout = (unsigned long) -1;
if (time)
tty->minimum_to_wake = 1;
else if (!waitqueue_active(&tty->read_wait) ||
(tty->minimum_to_wake > minimum))
tty->minimum_to_wake = minimum;
} else {
+ current->timeout = 0;
if (time) {
current->timeout = time + jiffies;
time = 0;
- } else
- current->timeout = 0;
+ }
tty->minimum_to_wake = minimum = 1;
}
}
@@ -922,10 +920,10 @@ do_it_again:
add_wait_queue(&tty->read_wait, &wait);
disable_bh(TQUEUE_BH);
- while (1) {
+ while (nr) {
/* First test for status change. */
if (tty->packet && tty->link->ctrl_status) {
- if (b != buf || !nr)
+ if (b != buf)
break;
put_user(tty->link->ctrl_status, b++);
nr--;
@@ -966,7 +964,7 @@ do_it_again:
current->state = TASK_RUNNING;
/* Deal with packet mode. */
- if (tty->packet && b == buf && nr) {
+ if (tty->packet && b == buf) {
put_user(TIOCPKT_DATA, b++);
nr--;
}
@@ -1013,7 +1011,7 @@ do_it_again:
if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
check_unthrottle(tty);
- if (b - buf >= minimum || !nr)
+ if (b - buf >= minimum)
break;
if (time)
current->timeout = time + jiffies;
@@ -1027,25 +1025,27 @@ do_it_again:
current->state = TASK_RUNNING;
current->timeout = 0;
size = b - buf;
- if (size && nr)
- clear_bit(TTY_PUSH, &tty->flags);
- if (!size && test_and_clear_bit(TTY_PUSH, &tty->flags))
- goto do_it_again;
- if (!size && !retval)
- clear_bit(TTY_PUSH, &tty->flags);
- return (size ? size : retval);
+ if (size) {
+ retval = size;
+ if (nr)
+ clear_bit(TTY_PUSH, &tty->flags);
+ } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
+ goto do_it_again;
+
+ return retval;
}
static ssize_t write_chan(struct tty_struct * tty, struct file * file,
const unsigned char * buf, size_t nr)
{
+ const unsigned char *b = buf;
struct wait_queue wait = { current, NULL };
int c;
- const unsigned char *b = buf;
- ssize_t retval = 0, num;
+ ssize_t retval = 0;
/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
- if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
+ if (L_TOSTOP(tty) &&
+ file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
retval = tty_check_change(tty);
if (retval)
@@ -1065,7 +1065,11 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
}
if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
while (nr > 0) {
- num = opost_block(tty, b, nr);
+ ssize_t num = opost_block(tty, b, nr);
+ if (num < 0) {
+ retval = num;
+ goto break_out;
+ }
b += num;
nr -= num;
if (nr == 0)
@@ -1081,7 +1085,7 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
c = tty->driver.write(tty, 1, b, nr);
if (c < 0) {
retval = c;
- break;
+ goto break_out;
}
b += c;
nr -= c;
@@ -1094,6 +1098,7 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
}
schedule();
}
+break_out:
current->state = TASK_RUNNING;
remove_wait_queue(&tty->write_wait, &wait);
return (b - buf) ? b - buf : retval;
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index fba8c7d51..a3353f4af 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -156,7 +156,7 @@ static __inline__ void nvram_set_checksum_int( void )
*
* They're only built if CONFIG_ATARI is defined, because Atari drivers use
* them. For other configurations (PC), the rest of the kernel can't rely on
- * them being present (this driver couldn't be configured at all, or as a
+ * them being present (this driver may not be configured at all, or as a
* module), so they access config information themselves.
*/
@@ -227,12 +227,15 @@ static long long nvram_llseek(struct file *file,loff_t offset, int origin )
return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
}
-static ssize_t nvram_read( struct file * file,
- char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_read(struct file * file,
+ char * buf, size_t count, loff_t *ppos )
{
unsigned long flags;
unsigned i = *ppos;
char *tmp = buf;
+
+ if (i != *ppos)
+ return -EINVAL;
save_flags(flags);
cli();
@@ -250,12 +253,16 @@ static ssize_t nvram_read( struct file * file,
return( tmp - buf );
}
-static ssize_t nvram_write( struct file * file, const char * buf, size_t count, loff_t *ppos )
+static ssize_t nvram_write(struct file * file,
+ const char * buf, size_t count, loff_t *ppos )
{
unsigned long flags;
unsigned i = *ppos;
const char *tmp = buf;
char c;
+
+ if (i != *ppos)
+ return -EINVAL;
save_flags(flags);
cli();
@@ -411,7 +418,7 @@ __initfunc(int nvram_init(void))
if (!CHECK_DRIVER_INIT())
return( -ENXIO );
- printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION );
+ printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION );
misc_register( &nvram_dev );
#ifdef CONFIG_PROC_FS
if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
@@ -618,7 +625,7 @@ static char *colors[] = {
#define fieldsize(a) (sizeof(a)/sizeof(*a))
static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
- off_t *begin, off_t offset, int size )
+ off_t *begin, off_t offset, int size )
{
int checksum = nvram_check_checksum();
int i;
@@ -645,7 +652,7 @@ static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
/* the following entries are defined only for the Falcon */
if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
- return;
+ return 1;
PRINT_PROC( "OS language : " );
if (nvram[6] < fieldsize(languages))
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index c466ae4a4..67d652aab 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -37,7 +37,7 @@
*/
/*
- * Some x86 BIOSes do not correctly initializes the keyboard, so the
+ * Some x86 BIOSes do not correctly initialize the keyboard, so the
* "kbd-reset" command line options can be given to force a reset.
* [Ranger]
*/
@@ -155,6 +155,19 @@ static char *initialize_kbd2(void)
| KBD_MODE_DISABLE_MOUSE
| KBD_MODE_KCC);
+ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
+ kbd_write_command(KBD_CCMD_READ_MODE);
+ if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
+ /*
+ * If the controller does not support conversion,
+ * Set the keyboard to scan-code set 1.
+ */
+ kbd_write_output(0xF0);
+ kbd_wait_for_input();
+ kbd_write_output(0x01);
+ kbd_wait_for_input();
+ }
+
kbd_write_output(KBD_CMD_ENABLE);
if (kbd_wait_for_input() != KBD_REPLY_ACK)
return "Enable keyboard: no ACK";
@@ -187,7 +200,7 @@ void initialize_kbd(void)
-unsigned char kbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
+unsigned char pckbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
/* used only by send_data - set by keyboard_interrupt */
static volatile unsigned char reply_expected = 0;
@@ -208,7 +221,7 @@ static inline void kb_wait(void)
do {
if (! (kbd_read_status() & KBD_STAT_IBF))
return;
- udelay(1000);
+ mdelay(1);
timeout--;
} while (timeout);
#ifdef KBD_REPORT_TIMEOUTS
@@ -522,7 +535,7 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned char scancode;
/* mouse data? */
- if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF) {
+ if (status & pckbd_read_mask & KBD_STAT_MOUSE_OBF) {
#if defined(CONFIG_SGI) && defined(CONFIG_PSMOUSE)
scancode = kbd_read_input();
aux_interrupt(status, scancode);
@@ -566,7 +579,7 @@ static int send_data(unsigned char data)
return 1;
if (resend)
break;
- udelay(1000);
+ mdelay(1);
if (!--timeout) {
#ifdef KBD_REPORT_TIMEOUTS
printk(KERN_WARNING "Keyboard timeout\n");
diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
index 1bd7ab8b2..4357e099f 100644
--- a/drivers/char/pc_keyb.h
+++ b/drivers/char/pc_keyb.h
@@ -23,7 +23,7 @@
* Internal variables of the driver
*/
-extern unsigned char kbd_read_mask;
+extern unsigned char pckbd_read_mask;
extern unsigned char aux_device_present;
/*
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index 12ad2e53c..4bd0f0f29 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -126,7 +126,7 @@ __initfunc(static int pcwd_checkcard(void))
/* Sleep 1/2 second (or 500000 microseconds :) */
- udelay(500000L);
+ mdelay(500);
done = 0;
/* If there's a heart beat in both instances, then this means we
@@ -455,7 +455,7 @@ __initfunc(static int send_command(int cmd))
int i;
outb_p(cmd, current_readport + 2);
- udelay(1000L);
+ mdelay(1);
i = inb(current_readport);
i = inb(current_readport);
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index eecdaee5a..9fe8bcc23 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -619,7 +619,7 @@ static void pcxe_close(struct tty_struct * tty, struct file * filp)
** worth noting that while I'm not sure what this hunk of code is supposed
** to do, it is not present in the serial.c driver. Hmmm. If you know,
** please send me a note. brian@ilinx.com
-** Dont know either what this is supposed to do clameter@waterf.org.
+** Don't know either what this is supposed to do clameter@waterf.org.
*/
if(tty->ldisc.num != ldiscs[N_TTY].num) {
if(tty->ldisc.close)
diff --git a/drivers/char/pms.c b/drivers/char/pms.c
index c17cb20ae..81c8fbb79 100644
--- a/drivers/char/pms.c
+++ b/drivers/char/pms.c
@@ -630,7 +630,7 @@ static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count)
while (cnt <= 0)
{
/*
- * Dont copy too far
+ * Don't copy too far
*/
int dt=dw;
if(dt+len>count)
@@ -893,6 +893,7 @@ struct video_device pms_template=
pms_close,
pms_read,
pms_write,
+ NULL, /* FIXME - we can use POLL on this board with the irq */
pms_ioctl,
NULL,
pms_init_done,
diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c
index 29f86263b..17c6c5383 100644
--- a/drivers/char/psaux.c
+++ b/drivers/char/psaux.c
@@ -636,7 +636,7 @@ __initfunc(int psaux_init(void))
printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
aux_present = 1;
#ifdef CONFIG_VT
- kbd_read_mask = AUX_STAT_OBF;
+ pckbd_read_mask = AUX_STAT_OBF;
#endif
} else {
return -EIO;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index fb136c3e8..a7ea98497 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -7,6 +7,7 @@
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
*/
+#include <linux/config.h>
#include <linux/module.h> /* For EXPORT_SYMBOL */
#include <linux/errno.h>
@@ -35,9 +36,9 @@ struct pty_struct {
#define PTY_MAGIC 0x5001
static struct tty_driver pty_driver, pty_slave_driver;
-static struct tty_driver old_pty_driver, old_pty_slave_driver;
static int pty_refcount;
+/* Note: one set of tables for BSD and one for Unix98 */
static struct tty_struct *pty_table[NR_PTYS];
static struct termios *pty_termios[NR_PTYS];
static struct termios *pty_termios_locked[NR_PTYS];
@@ -46,6 +47,20 @@ static struct termios *ttyp_termios[NR_PTYS];
static struct termios *ttyp_termios_locked[NR_PTYS];
static struct pty_struct pty_state[NR_PTYS];
+#ifdef CONFIG_UNIX98_PTYS
+/* These are global because they are accessed in tty_io.c */
+struct tty_driver ptm_driver[UNIX98_NR_MAJORS];
+struct tty_driver pts_driver[UNIX98_NR_MAJORS];
+
+static struct tty_struct *ptm_table[UNIX98_NR_MAJORS][NR_PTYS];
+static struct termios *ptm_termios[UNIX98_NR_MAJORS][NR_PTYS];
+static struct termios *ptm_termios_locked[UNIX98_NR_MAJORS][NR_PTYS];
+static struct tty_struct *pts_table[UNIX98_NR_MAJORS][NR_PTYS];
+static struct termios *pts_termios[UNIX98_NR_MAJORS][NR_PTYS];
+static struct termios *pts_termios_locked[UNIX98_NR_MAJORS][NR_PTYS];
+static struct pty_struct ptm_state[UNIX98_NR_MAJORS][NR_PTYS];
+#endif
+
#define MIN(a,b) ((a) < (b) ? (a) : (b))
static void pty_close(struct tty_struct * tty, struct file * filp)
@@ -71,7 +86,15 @@ static void pty_close(struct tty_struct * tty, struct file * filp)
if (tty->driver.subtype == PTY_TYPE_MASTER) {
tty_hangup(tty->link);
set_bit(TTY_OTHER_CLOSED, &tty->flags);
- devpts_pty_kill(MINOR(tty->device) - tty->driver.minor_start);
+#ifdef CONFIG_UNIX98_PTYS
+ {
+ unsigned int major = MAJOR(tty->device) - UNIX98_PTY_MASTER_MAJOR;
+ if ( major < UNIX98_NR_MAJORS ) {
+ devpts_pty_kill( MINOR(tty->device)
+ - tty->driver.minor_start + tty->driver.name_base );
+ }
+ }
+#endif
}
}
@@ -200,16 +223,20 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
return ((count < N_TTY_BUF_SIZE/2) ? 0 : count);
}
-/*
- * Return the minor device number of a given pty. This lets us
- * open a master pty with the multi-headed ptmx device, then
- * find out which one we got after it is open, with an ioctl.
+/*
+ * Return the device number of a Unix98 PTY (only!). This lets us open a
+ * master pty with the multi-headed ptmx device, then find out which
+ * one we got after it is open, with an ioctl.
*/
-static int pty_get_device_minor(struct tty_struct *tty, unsigned int *value)
+#ifdef CONFIG_UNIX98_PTYS
+static int pty_get_device_number(struct tty_struct *tty, unsigned int *value)
{
- unsigned int result = MINOR(tty->device);
+ unsigned int result = MINOR(tty->device)
+ - tty->driver.minor_start + tty->driver.name_base;
return put_user(result, value);
}
+#endif
+
/* Set the lock flag on a pty */
static int pty_set_lock(struct tty_struct *tty, int * arg)
{
@@ -223,22 +250,37 @@ static int pty_set_lock(struct tty_struct *tty, int * arg)
return 0;
}
-static int pty_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
if (!tty) {
printk("pty_ioctl called with NULL tty!\n");
return -EIO;
}
switch(cmd) {
- case TIOCGPTN: /* Get PT Number */
- return pty_get_device_minor(tty, (unsigned int *)arg);
case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
return pty_set_lock(tty, (int *) arg);
}
return -ENOIOCTLCMD;
}
+#ifdef CONFIG_UNIX98_PTYS
+static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ if (!tty) {
+ printk("pty_unix98_ioctl called with NULL tty!\n");
+ return -EIO;
+ }
+ switch(cmd) {
+ case TIOCGPTN: /* Get PT Number */
+ return pty_get_device_number(tty, (unsigned int *)arg);
+ }
+
+ return pty_bsd_ioctl(tty,file,cmd,arg);
+}
+#endif
+
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
@@ -267,7 +309,7 @@ static int pty_open(struct tty_struct *tty, struct file * filp)
line = MINOR(tty->device) - tty->driver.minor_start;
if ((line < 0) || (line >= NR_PTYS))
goto out;
- pty = pty_state + line;
+ pty = (struct pty_struct *)(tty->driver.driver_state) + line;
tty->driver_data = pty;
retval = -EIO;
@@ -294,6 +336,10 @@ static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
__initfunc(int pty_init(void))
{
+ int i;
+
+ /* Traditional BSD devices */
+
memset(&pty_state, 0, sizeof(pty_state));
memset(&pty_driver, 0, sizeof(struct tty_driver));
pty_driver.magic = TTY_DRIVER_MAGIC;
@@ -314,6 +360,7 @@ __initfunc(int pty_init(void))
pty_driver.table = pty_table;
pty_driver.termios = pty_termios;
pty_driver.termios_locked = pty_termios_locked;
+ pty_driver.driver_state = pty_state;
pty_driver.other = &pty_slave_driver;
pty_driver.open = pty_open;
@@ -337,37 +384,60 @@ __initfunc(int pty_init(void))
pty_slave_driver.table = ttyp_table;
pty_slave_driver.termios = ttyp_termios;
pty_slave_driver.termios_locked = ttyp_termios_locked;
+ pty_slave_driver.driver_state = pty_state;
pty_slave_driver.other = &pty_driver;
- old_pty_driver = pty_driver;
- old_pty_driver.driver_name = "compat_pty_master";
- old_pty_driver.proc_entry = 0;
- old_pty_driver.major = TTY_MAJOR;
- old_pty_driver.minor_start = 128;
- old_pty_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
- old_pty_driver.other = &old_pty_slave_driver;
-
- old_pty_slave_driver = pty_slave_driver;
- old_pty_slave_driver.driver_name = "compat_pty_slave";
- old_pty_slave_driver.proc_entry = 0;
- old_pty_slave_driver.major = TTY_MAJOR;
- old_pty_slave_driver.minor_start = 192;
- old_pty_slave_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS;
- old_pty_slave_driver.other = &old_pty_driver;
-
- /* only the master pty gets this ioctl (which is why we
- * assign it here, instead of up with the rest of the
- * pty_driver initialization. <cananian@alumni.princeton.edu>
- */
- pty_driver.ioctl = pty_ioctl;
-
if (tty_register_driver(&pty_driver))
panic("Couldn't register pty driver");
if (tty_register_driver(&pty_slave_driver))
panic("Couldn't register pty slave driver");
- if (tty_register_driver(&old_pty_driver))
- panic("Couldn't register compat pty driver");
- if (tty_register_driver(&old_pty_slave_driver))
- panic("Couldn't register compat pty slave driver");
+
+ /*
+ * only the master pty gets this ioctl (which is why we
+ * assign it here, instead of up with the rest of the
+ * pty_driver initialization. <cananian@alumni.princeton.edu>
+ */
+ pty_driver.ioctl = pty_bsd_ioctl;
+
+ /* Unix98 devices */
+#ifdef CONFIG_UNIX98_PTYS
+ printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS);
+ for ( i = 0 ; i < UNIX98_NR_MAJORS ; i++ ) {
+ ptm_driver[i] = pty_driver;
+ ptm_driver[i].name = "ptm";
+ ptm_driver[i].proc_entry = 0;
+ ptm_driver[i].major = UNIX98_PTY_MASTER_MAJOR+i;
+ ptm_driver[i].minor_start = 0;
+ ptm_driver[i].name_base = i*NR_PTYS;
+ ptm_driver[i].num = NR_PTYS;
+ ptm_driver[i].other = &pts_driver[i];
+ ptm_driver[i].table = ptm_table[i];
+ ptm_driver[i].termios = ptm_termios[i];
+ ptm_driver[i].termios_locked = ptm_termios_locked[i];
+ ptm_driver[i].driver_state = ptm_state[i];
+
+ pts_driver[i] = pty_slave_driver;
+ pts_driver[i].name = "pts";
+ pts_driver[i].proc_entry = 0;
+ pts_driver[i].major = UNIX98_PTY_SLAVE_MAJOR+i;
+ pts_driver[i].minor_start = 0;
+ pts_driver[i].name_base = i*NR_PTYS;
+ pts_driver[i].num = ptm_driver[i].num;
+ pts_driver[i].other = &ptm_driver[i];
+ pts_driver[i].table = pts_table[i];
+ pts_driver[i].termios = pts_termios[i];
+ pts_driver[i].termios_locked = pts_termios_locked[i];
+ pts_driver[i].driver_state = ptm_state[i];
+
+ ptm_driver[i].ioctl = pty_unix98_ioctl;
+
+ if (tty_register_driver(&ptm_driver[i]))
+ panic("Couldn't register Unix98 ptm driver major %d",
+ ptm_driver[i].major);
+ if (tty_register_driver(&pts_driver[i]))
+ panic("Couldn't register Unix98 pts driver major %d",
+ pts_driver[i].major);
+ }
+#endif
return 0;
}
diff --git a/drivers/char/radio-aimslab.c b/drivers/char/radio-aimslab.c
new file mode 100644
index 000000000..014def0c4
--- /dev/null
+++ b/drivers/char/radio-aimslab.c
@@ -0,0 +1,373 @@
+/* radiotrack (radioreveal) driver for Linux radio support
+ * (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 :-)
+ *
+ * Notes on the hardware (reverse engineered from other peoples'
+ * reverse engineering of AIMS' code :-)
+ *
+ * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ *
+ * The signal strength query is unsurprisingly inaccurate. And it seems
+ * to indicate that (on my card, at least) the frequency setting isn't
+ * too great. (I have to tune up .025MHz from what the freq should be
+ * to get a report that the thing is tuned.)
+ *
+ * Volume control is (ugh) analogue:
+ * out(port, start_increasing_volume);
+ * wait(a_wee_while);
+ * out(port, stop_changing_the_volume);
+ *
+ */
+
+#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_RTRACK_PORT */
+
+#ifndef CONFIG_RADIO_RTRACK_PORT
+#define CONFIG_RADIO_RTRACK_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_RTRACK_PORT;
+static int users = 0;
+
+struct rt_device
+{
+ int port;
+ int curvol;
+ unsigned long curfreq;
+ int muted;
+};
+
+
+/* local things */
+
+static void sleep_delay(long n)
+{
+ /* Sleep nicely for 'n' uS */
+ int d=n/(1000000/HZ);
+ if(!d)
+ udelay(n);
+ else
+ {
+ /* Yield CPU time */
+ unsigned long x=jiffies;
+ while((jiffies-x)<=d)
+ schedule();
+ }
+}
+
+static void rt_decvol(void)
+{
+ outb(0x58, io); /* volume down + sigstr + on */
+ sleep_delay(100000);
+ outb(0xd8, io); /* volume steady + sigstr + on */
+}
+
+static void rt_incvol(void)
+{
+ outb(0x98, io); /* volume up + sigstr + on */
+ sleep_delay(100000);
+ outb(0xd8, io); /* volume steady + sigstr + on */
+}
+
+static void rt_mute(struct rt_device *dev)
+{
+ dev->muted = 1;
+ outb(0xd0, io); /* volume steady, off */
+}
+
+static int rt_setvol(struct rt_device *dev, int vol)
+{
+ int i;
+
+ if(vol == dev->curvol) { /* requested volume = current */
+ if (dev->muted) { /* user is unmuting the card */
+ dev->muted = 0;
+ outb (0xd8, io); /* enable card */
+ }
+
+ return 0;
+ }
+
+ if(vol == 0) { /* volume = 0 means mute the card */
+ outb(0x48, io); /* volume down but still "on" */
+ sleep_delay(2000000); /* make sure it's totally down */
+ outb(0xd0, io); /* volume steady, off */
+ return 0;
+ }
+
+ dev->muted = 0;
+ if(vol > dev->curvol)
+ for(i = dev->curvol; i < vol; i++)
+ rt_incvol();
+ else
+ for(i = dev->curvol; i > vol; i--)
+ rt_decvol();
+
+ dev->curvol = vol;
+
+ return 0;
+}
+
+/* the 128+64 on these outb's is to keep the volume stable while tuning
+ * without them, the volume _will_ creep up with each frequency change
+ * and bit 4 (+16) is to keep the signal strength meter enabled
+ */
+
+void send_0_byte(int port, struct rt_device *dev)
+{
+ if ((dev->curvol == 0) || (dev->muted)) {
+ outb_p(128+64+16+ 1, port); /* wr-enable + data low */
+ outb_p(128+64+16+2+1, port); /* clock */
+ }
+ else {
+ outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */
+ outb_p(128+64+16+8+2+1, port); /* clock */
+ }
+ sleep_delay(1000);
+}
+
+void send_1_byte(int port, struct rt_device *dev)
+{
+ if ((dev->curvol == 0) || (dev->muted)) {
+ outb_p(128+64+16+4 +1, port); /* wr-enable+data high */
+ outb_p(128+64+16+4+2+1, port); /* clock */
+ }
+ else {
+ outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */
+ outb_p(128+64+16+8+4+2+1, port); /* clock */
+ }
+
+ sleep_delay(1000);
+}
+
+static int rt_setfreq(struct rt_device *dev, unsigned long freq)
+{
+ int i;
+
+ /* adapted from radio-aztech.c */
+
+ /* We want to compute x * 100 / 16 without overflow
+ * So we compute x*6 + (x/100)*25 to give x*6.25
+ */
+
+ freq = freq * 6 + freq/4; /* massage the data a little */
+ freq += 1070; /* IF = 10.7 MHz */
+ freq /= 5; /* ref = 25 kHz */
+
+ send_0_byte (io, dev); /* 0: LSB of frequency */
+
+ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
+ if (freq & (1 << i))
+ send_1_byte (io, dev);
+ else
+ send_0_byte (io, dev);
+
+ send_0_byte (io, dev); /* 14: test bit - always 0 */
+ send_0_byte (io, dev); /* 15: test bit - always 0 */
+
+ send_0_byte (io, dev); /* 16: band data 0 - always 0 */
+ send_0_byte (io, dev); /* 17: band data 1 - always 0 */
+ send_0_byte (io, dev); /* 18: band data 2 - always 0 */
+ send_0_byte (io, dev); /* 19: time base - always 0 */
+
+ send_0_byte (io, dev); /* 20: spacing (0 = 25 kHz) */
+ send_1_byte (io, dev); /* 21: spacing (1 = 25 kHz) */
+ send_0_byte (io, dev); /* 22: spacing (0 = 25 kHz) */
+ send_1_byte (io, dev); /* 23: AM/FM (FM = 1, always) */
+
+ if ((dev->curvol == 0) || (dev->muted))
+ outb (0xd0, io); /* volume steady + sigstr */
+ else
+ outb (0xd8, io); /* volume steady + sigstr + on */
+
+ return 0;
+}
+
+int rt_getsigstr(struct rt_device *dev)
+{
+ if (inb(io) & 2) /* bit set = no signal present */
+ return 0;
+ return 1; /* signal present */
+}
+
+static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct rt_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;
+ 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=(88*16);
+ v.rangehigh=(108*16);
+ v.flags=0;
+ v.mode=VIDEO_MODE_AUTO;
+ v.signal=0xFFFF*rt_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;
+ rt_setfreq(rt, rt->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 * 6554;
+ 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)
+ rt_mute(rt);
+ else
+ rt_setvol(rt,v.volume/6554);
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int rt_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void rt_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct rt_device rtrack_unit;
+
+static struct video_device rtrack_radio=
+{
+ "RadioTrack radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_RTRACK,
+ rt_open,
+ rt_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL, /* No poll */
+ rt_ioctl,
+ NULL,
+ NULL
+};
+
+__initfunc(int rtrack_init(struct video_init *v))
+{
+ if (check_region(io, 2))
+ {
+ printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+
+ rtrack_radio.priv=&rtrack_unit;
+
+ if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ request_region(io, 2, "rtrack");
+ printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n");
+
+ /* mute card - prevents noisy bootups */
+
+ /* this ensures that the volume is all the way down */
+ outb(0x48, io); /* volume down but still "on" */
+ sleep_delay(2000000); /* make sure it's totally down */
+ outb(0xc0, io); /* steady volume, mute card */
+ rtrack_unit.curvol = 0;
+
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("M.Kirkwood");
+MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
+ return rtrack_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ video_unregister_device(&rtrack_radio);
+ release_region(io,2);
+}
+
+#endif
diff --git a/drivers/char/radio-aztech.c b/drivers/char/radio-aztech.c
new file mode 100644
index 000000000..aaeaa7265
--- /dev/null
+++ b/drivers/char/radio-aztech.c
@@ -0,0 +1,324 @@
+/* aztech.c - Aztech radio card driver for Linux 2.1 by Russell Kroll
+ *
+ * Heavily modified to support the new 2.1 radio card interfaces by
+ * Russell Kroll (rkroll@exploits.org)
+ *
+ * Based on code by
+ *
+ * Quay Ly
+ * Donald Song
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
+ * William McGrath (wmcgrath@twilight.vtc.vsc.edu)
+ *
+ * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
+ * along with more information on the card itself.
+ *
+ * Notable changes from the original source:
+ * - includes stripped down to the essentials
+ * - for loops used as delays replaced with udelay()
+ * - #defines removed, changed to static values
+ * - tuning structure changed - no more character arrays, other changes
+*/
+
+#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_AZTECH_PORT */
+
+/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
+
+#ifndef CONFIG_RADIO_AZTECH_PORT
+#define CONFIG_RADIO_AZTECH_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_AZTECH_PORT;
+static int radio_wait_time = 1000;
+static int users = 0;
+
+struct az_device
+{
+ int curvol;
+ unsigned long curfreq;
+ int stereo;
+};
+
+static int volconvert(int level)
+{
+ level>>=14; /* Map 16bits down to 2 bit */
+ level&=3;
+
+ /* convert to card-friendly values */
+ switch (level)
+ {
+ case 0:
+ return 0;
+ case 1:
+ return 1;
+ case 2:
+ return 4;
+ case 3:
+ return 5;
+ }
+ return 0; /* Quieten gcc */
+}
+
+static void send_0_byte (struct az_device *dev)
+{
+ udelay(radio_wait_time);
+ outb_p(2+volconvert(dev->curvol), io);
+ outb_p(64+2+volconvert(dev->curvol), io);
+}
+
+static void send_1_byte (struct az_device *dev)
+{
+ udelay (radio_wait_time);
+ outb_p(128+2+volconvert(dev->curvol), io);
+ outb_p(128+64+2+volconvert(dev->curvol), io);
+}
+
+static int az_setvol(struct az_device *dev, int vol)
+{
+ outb (volconvert(vol), io);
+ return 0;
+}
+
+/* thanks to Michael Dwyer for giving me a dose of clues in
+ * the signal strength department..
+ *
+ * This card has a stereo bit - bit 0 set = mono, not set = stereo
+ * It also has a "signal" bit - bit 1 set = bad signal, not set = good
+ *
+ */
+
+static int az_getsigstr(struct az_device *dev)
+{
+ if (inb(io) & 2) /* bit set = no signal present */
+ return 0;
+ return 1; /* signal present */
+}
+
+static int az_getstereo(struct az_device *dev)
+{
+ if (inb(io) & 1) /* bit set = mono */
+ return 0;
+ return 1; /* stereo */
+}
+
+static int az_setfreq(struct az_device *dev, unsigned long frequency)
+{
+ int i;
+
+ /* 6.25 * */
+ frequency = frequency*6 + frequency/4; /* massage data a bit */
+
+ frequency += 1070; /* tuning needs 24 data bits */
+ frequency /= 5;
+
+ send_0_byte (dev); /* 0: LSB of frequency */
+
+ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
+ if (frequency & (1 << i))
+ send_1_byte (dev);
+ else
+ send_0_byte (dev);
+
+ send_0_byte (dev); /* 14: test bit - always 0 */
+ send_0_byte (dev); /* 15: test bit - always 0 */
+ send_0_byte (dev); /* 16: band data 0 - always 0 */
+ if (dev->stereo) /* 17: stereo (1 to enable) */
+ send_1_byte (dev);
+ else
+ send_0_byte (dev);
+
+ send_1_byte (dev); /* 18: band data 1 - unknown */
+ send_0_byte (dev); /* 19: time base - always 0 */
+ send_0_byte (dev); /* 20: spacing (0 = 25 kHz) */
+ send_1_byte (dev); /* 21: spacing (1 = 25 kHz) */
+ send_0_byte (dev); /* 22: spacing (0 = 25 kHz) */
+ send_1_byte (dev); /* 23: AM/FM (FM = 1, always) */
+
+ /* latch frequency */
+
+ udelay (radio_wait_time);
+ outb_p(128+64+volconvert(dev->curvol), io);
+
+ return 0;
+}
+
+static int az_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct az_device *az=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;
+ 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=(879*16)/10;
+ v.rangehigh=(1078*16)/10;
+ v.flags=0;
+ v.mode=VIDEO_MODE_AUTO;
+ v.signal=0xFFFF*az_getsigstr(az);
+ if(az_getstereo(az))
+ v.flags|=VIDEO_TUNER_STEREO_ON;
+ 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, &az->curfreq, sizeof(az->curfreq)))
+ return -EFAULT;
+ return 0;
+ case VIDIOCSFREQ:
+ if(copy_from_user(&az->curfreq, arg,sizeof(az->curfreq)))
+ return -EFAULT;
+ az_setfreq(az, az->curfreq);
+ return 0;
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio v;
+ memset(&v,0, sizeof(v));
+ v.flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
+ if(az->stereo)
+ v.mode=VIDEO_SOUND_STEREO;
+ else
+ v.mode=VIDEO_SOUND_MONO;
+ v.volume=az->curvol;
+ 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;
+ az->curvol=v.volume;
+
+ az->stereo=(v.mode&VIDEO_SOUND_STEREO)?1:0;
+ if(v.flags&VIDEO_AUDIO_MUTE)
+ az_setvol(az,0);
+ else
+ az_setvol(az,az->curvol);
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int az_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void az_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct az_device aztech_unit;
+
+static struct video_device aztech_radio=
+{
+ "Aztech radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_AZTECH,
+ az_open,
+ az_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL, /* No poll */
+ az_ioctl,
+ NULL,
+ NULL
+};
+
+__initfunc(int aztech_init(struct video_init *v))
+{
+ if (check_region(io, 2))
+ {
+ printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+
+ aztech_radio.priv=&aztech_unit;
+
+ if(video_register_device(&aztech_radio, VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ request_region(io, 2, "aztech");
+ printk(KERN_INFO "Aztech radio card driver v0.40/19980422 rkroll@exploits.org\n");
+ /* mute card - prevents noisy bootups */
+ outb (0, io);
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
+MODULE_DESCRIPTION("A driver for the Aztech radio card.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
+ return aztech_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ video_unregister_device(&aztech_radio);
+ release_region(io,2);
+}
+
+#endif
diff --git a/drivers/char/radio-rtrack2.c b/drivers/char/radio-rtrack2.c
new file mode 100644
index 000000000..7daeb4e01
--- /dev/null
+++ b/drivers/char/radio-rtrack2.c
@@ -0,0 +1,272 @@
+/* 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_RTRACK2_PORT */
+
+#ifndef CONFIG_RADIO_RTRACK2_PORT
+#define CONFIG_RADIO_RTRACK2_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_RTRACK2_PORT;
+static int users = 0;
+
+struct rt_device
+{
+ int port;
+ unsigned long curfreq;
+ int muted;
+};
+
+
+/* local things */
+
+static void rt_mute(struct rt_device *dev)
+{
+ if(dev->muted)
+ return;
+ outb(1, io);
+ dev->muted = 1;
+}
+
+static void rt_unmute(struct rt_device *dev)
+{
+ if(dev->muted == 0)
+ return;
+ outb(0, io);
+ dev->muted = 0;
+}
+
+static void zero(void)
+{
+ outb_p(1, io);
+ outb_p(3, io);
+ outb_p(1, io);
+}
+
+static void one(void)
+{
+ outb_p(5, io);
+ outb_p(7, io);
+ outb_p(5, io);
+}
+
+static int rt_setfreq(struct rt_device *dev, unsigned long freq)
+{
+ int i;
+
+ freq = freq / 200 + 856;
+
+ outb_p(0xc8, io);
+ outb_p(0xc9, io);
+ outb_p(0xc9, io);
+
+ for (i = 0; i < 10; i++)
+ zero ();
+
+ for (i = 14; i >= 0; i--)
+ if (freq & (1 << i))
+ one ();
+ else
+ zero ();
+
+ outb_p(0xc8, io);
+ if (!dev->muted)
+ outb_p(0, io);
+ return 0;
+}
+
+int rt_getsigstr(struct rt_device *dev)
+{
+ if (inb(io) & 2) /* bit set = no signal present */
+ return 0;
+ return 1; /* signal present */
+}
+
+static int rt_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct rt_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;
+ 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=88*16000;
+ v.rangehigh=108*16000;
+ v.flags=VIDEO_TUNER_LOW;
+ v.mode=VIDEO_MODE_AUTO;
+ v.signal=0xFFFF*rt_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;
+ rt_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;
+ 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)
+ rt_mute(rt);
+ else
+ rt_unmute(rt);
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int rt_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void rt_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct rt_device rtrack2_unit;
+
+static struct video_device rtrack2_radio=
+{
+ "RadioTrack II radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_RTRACK2,
+ rt_open,
+ rt_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL, /* Can't poll */
+ rt_ioctl,
+ NULL,
+ NULL
+};
+
+__initfunc(int rtrack2_init(struct video_init *v))
+{
+ if (check_region(io, 4))
+ {
+ printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+
+ rtrack2_radio.priv=&rtrack2_unit;
+
+ if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ request_region(io, 4, "rtrack2");
+ printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
+
+ /* mute card - prevents noisy bootups */
+ outb(1, io);
+ rtrack2_unit.muted = 1;
+
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Ben Pfaff");
+MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
+ return -EINVAL;
+ }
+ return rtrack2_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ video_unregister_device(&rtrack2_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-sf16fmi.c b/drivers/char/radio-sf16fmi.c
new file mode 100644
index 000000000..13659fd85
--- /dev/null
+++ b/drivers/char/radio-sf16fmi.c
@@ -0,0 +1,285 @@
+/* SF16FMI radio driver for Linux radio support
+ * heavily based on rtrack driver...
+ * (c) 1997 M. Kirkwood
+ * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
+ *
+ * Fitted to new interface by Alan Cox <alan.cox@linux.org>
+ *
+ * Notes on the hardware
+ *
+ * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
+ * No volume control - only mute/unmute - you have to use line volume
+ * control on SB-part of SF16FMI
+ *
+ */
+
+#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_SF16MI_PORT */
+
+#include "rsf16fmi.h"
+
+struct fmi_device
+{
+ int port;
+ int curvol;
+ unsigned long curfreq;
+ int flags;
+};
+
+#ifndef CONFIG_RADIO_SF16FMI_PORT
+#define CONFIG_RADIO_SF16FMI_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_SF16FMI_PORT;
+static int users = 0;
+
+/* local things */
+/* freq in 1/16kHz to internal number */
+#define RSF16_ENCODE(x) ((x/16+10700)/50)
+
+static void outbits(int bits, int data, int port)
+{
+ while(bits--) {
+ if(data & 1) {
+ outb(5, port);
+ udelay(6);
+ outb(7, port);
+ udelay(6);
+ } else {
+ outb(1, port);
+ udelay(6);
+ outb(3, port);
+ udelay(6);
+ }
+ data>>=1;
+ }
+}
+
+static void fmi_mute(int port)
+{
+ outb(0x00, port);
+}
+
+static void fmi_unmute(int port)
+{
+ outb(0x08, port);
+}
+
+static int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
+{
+ int myport = dev->port;
+
+ outbits(16, RSF16_ENCODE(freq), myport);
+ outbits(8, 0xC0, myport);
+ /* we should wait here... */
+ return 0;
+}
+
+static int fmi_getsigstr(struct fmi_device *dev)
+{
+ int val;
+ int res;
+ int myport = dev->port;
+
+ val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
+ outb(val, myport);
+ outb(val | 0x10, myport);
+ udelay(140000);
+ res = (int)inb(myport+1);
+ outb(val, myport);
+ return (res & 2) ? 0 : 1;
+}
+
+static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct fmi_device *fmi=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;
+ 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;
+ if (fmi->flags & VIDEO_TUNER_LOW) {
+ v.rangelow = 87500 * 16;
+ v.rangehigh = 108000 * 16;
+ } else {
+ v.rangelow=(int)(175*8 /* 87.5 *16 */);
+ v.rangehigh=(int)(108*16);
+ }
+ v.flags=fmi->flags;
+ v.mode=VIDEO_MODE_AUTO;
+ v.signal=0xFFFF*fmi_getsigstr(fmi);
+ 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;
+ fmi->flags = v.flags & VIDEO_TUNER_LOW;
+ /* Only 1 tuner so no setting needed ! */
+ return 0;
+ }
+ case VIDIOCGFREQ:
+ {
+ unsigned long tmp = fmi->curfreq;
+ if (!(fmi->flags & VIDEO_TUNER_LOW))
+ tmp /= 1000;
+ if(copy_to_user(arg, &tmp, sizeof(tmp)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSFREQ:
+ {
+ unsigned long tmp;
+ if(copy_from_user(&tmp, arg, sizeof(tmp)))
+ return -EFAULT;
+ if (!(fmi->flags & VIDEO_TUNER_LOW))
+ tmp *= 1000;
+ fmi->curfreq = tmp;
+ fmi_setfreq(fmi, fmi->curfreq);
+ return 0;
+ }
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio v;
+ memset(&v,0, sizeof(v));
+ v.flags|=VIDEO_AUDIO_MUTABLE;
+ v.mode=VIDEO_SOUND_MONO;
+ v.volume=fmi->curvol;
+ 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;
+ fmi->curvol=v.volume;
+ if(v.flags&VIDEO_AUDIO_MUTE)
+ fmi_mute(fmi->port);
+ else if(fmi->curvol)
+ fmi_unmute(fmi->port);
+ else
+ fmi_mute(fmi->port);
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int fmi_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void fmi_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct fmi_device fmi_unit;
+
+static struct video_device fmi_radio=
+{
+ "SF16FMI radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_SF16MI,
+ fmi_open,
+ fmi_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL, /* Can't poll */
+ fmi_ioctl,
+ NULL,
+ NULL
+};
+
+__initfunc(int fmi_init(struct video_init *v))
+{
+ if (check_region(io, 2))
+ {
+ printk(KERN_ERR "fmi: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+
+ fmi_unit.port=io;
+ fmi_unit.flags = VIDEO_TUNER_LOW;
+ fmi_radio.priv=&fmi_unit;
+
+ if(video_register_device(&fmi_radio, VFL_TYPE_RADIO)==-1)
+ return -EINVAL;
+
+ request_region(io, 2, "fmi");
+ printk(KERN_INFO "SF16FMI radio card driver.\n");
+ printk(KERN_INFO "(c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz.\n");
+ /* mute card - prevents noisy bootups */
+ fmi_mute(io);
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
+MODULE_DESCRIPTION("A driver for the SF16MI radio.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if(io==-1)
+ {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
+ return fmi_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ video_unregister_device(&fmi_radio);
+ release_region(io,2);
+}
+
+#endif
diff --git a/drivers/char/radio-zoltrix.c b/drivers/char/radio-zoltrix.c
new file mode 100644
index 000000000..c820c8a36
--- /dev/null
+++ b/drivers/char/radio-zoltrix.c
@@ -0,0 +1,333 @@
+/* zoltrix radio plus driver for Linux radio support
+ * (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
+ *
+ * BUGS
+ * Due to the inconsistancy in reading from the signal flags
+ * it is difficult to get an accurate tuned signal.
+ *
+ * There seems to be a problem with the volume setting that I must still
+ * figure out.
+ * It seems that the card has is not linear to 0 volume. It cuts off
+ * at a low frequency, and it is not possible (at least I have not found)
+ * to get fine volume control over the low volume range.
+ *
+ * Some code derived from code by Frans Brinkman
+ */
+
+#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_ZOLTRIX_PORT */
+
+#ifndef CONFIG_RADIO_ZOLTRIX_PORT
+#define CONFIG_RADIO_ZOLTRIX_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_ZOLTRIX_PORT;
+static int users = 0;
+
+struct zol_device {
+ int port;
+ int curvol;
+ unsigned long curfreq;
+ int muted;
+};
+
+
+/* local things */
+
+static void sleep_delay(long n)
+{
+ /* Sleep nicely for 'n' uS */
+ int d = n / (1000000 / HZ);
+ if (!d)
+ udelay(n);
+ else {
+ /* Yield CPU time */
+ unsigned long x = jiffies;
+ while ((jiffies - x) <= d)
+ schedule();
+ }
+}
+
+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);
+}
+
+static int zol_setvol(struct zol_device *dev, int vol)
+{
+ 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;
+}
+
+static int zol_setfreq(struct zol_device *dev, unsigned long freq)
+{
+ /* tunes the radio to the desired frequency */
+ unsigned long long bitmask, f, m;
+ int i;
+
+ m = (freq * 25 / 4 - 8800) * 2;
+ f = (unsigned long long) m + 0x4d1c;
+
+ bitmask = 0xc480402c10080000ull;
+ i = 45;
+
+ zol_mute(dev);
+
+ outb(0x40, io);
+ outb(0xc0, io);
+
+ bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( /*stereo */ 0 << 31));
+ while (i--) {
+ if ((bitmask & 0x8000000000000000ull) != 0) {
+ outb(0x80, io);
+ sleep_delay(50);
+ outb(0x00, io);
+ sleep_delay(50);
+ outb(0x80, io);
+ sleep_delay(50);
+ } else {
+ outb(0xc0, io);
+ sleep_delay(50);
+ outb(0x40, io);
+ sleep_delay(50);
+ outb(0xc0, io);
+ sleep_delay(50);
+ }
+ bitmask *= 2;
+ }
+ /* termination sequence */
+ outb(0x80, io);
+ outb(0xc0, io);
+ outb(0x40, io);
+ zol_on(dev->curvol);
+ return 0;
+}
+
+/* Get signal strength */
+
+int zol_getsigstr(struct zol_device *dev)
+{
+ int a, b;
+
+ outb(0x00, io); /* This stuff I found to do nothing */
+ outb(dev->curvol, io);
+ sleep_delay(20000);
+
+ a = inb(io);
+ 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
+ return (0);
+
+ if (inb(io) & 2) /* bit set = no signal present */
+ return 0;
+ return 1; /* signal present */
+}
+
+static int zol_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct zol_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;
+ if (copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner v;
+ if (copy_from_user(&v, arg, sizeof(v)) != 0)
+ return -EFAULT;
+ if (v.tuner) /* Only 1 tuner */
+ return -EINVAL;
+ v.rangelow = (int) (88.0 * 16);
+ v.rangehigh = (int) (108.0 * 16);
+ v.flags = 0;
+ v.mode = VIDEO_MODE_AUTO;
+ v.signal = 0xFFFF * zol_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;
+ zol_setfreq(rt, rt->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 * 4095;
+ 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)
+ zol_mute(rt);
+ else
+ zol_setvol(rt, v.volume / 4096);
+
+ return 0;
+ }
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int zol_open(struct video_device *dev, int flags)
+{
+ if (users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void zol_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+static struct zol_device zoltrix_unit;
+
+static struct video_device zoltrix_radio =
+{
+ "Zoltrix Radio Plus",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_ZOLTRIX,
+ zol_open,
+ zol_close,
+ NULL, /* Can't read (no capture ability) */
+ NULL, /* Can't write */
+ NULL,
+ zol_ioctl,
+ NULL,
+ NULL
+};
+
+__initfunc(int zoltrix_init(struct video_init *v))
+{
+ if (check_region(io, 2)) {
+ printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io);
+ return -EBUSY;
+ }
+ zoltrix_radio.priv = &zoltrix_unit;
+
+ if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO) == -1)
+ return -EINVAL;
+
+ request_region(io, 2, "zoltrix");
+ printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
+
+ /* mute card - prevents noisy bootups */
+
+ /* this ensures that the volume is all the way down */
+
+ outb(0, io);
+ outb(0, io);
+ sleep_delay(20000);
+ inb(io + 3);
+
+ zoltrix_unit.curvol = 0;
+
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("C.van Schaik");
+MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+ if (io == -1) {
+ printk(KERN_ERR "You must set an I/O address with io=0x???\n");
+ return -EINVAL;
+ }
+ return zoltrix_init(NULL);
+}
+
+void cleanup_module(void)
+{
+ video_unregister_device(&zoltrix_radio);
+ release_region(io, 2);
+}
+
+#endif
diff --git a/drivers/char/radio.c b/drivers/char/radio.c
deleted file mode 100644
index 2b79e9872..000000000
--- a/drivers/char/radio.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Radio Card Device Driver for Linux
- *
- * (c) 1997 Matthew Kirkwood <weejock@ferret.lmh.ox.ac.uk>
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-
-#include <linux/miscdevice.h>
-
-#include <asm/uaccess.h>
-
-#include <linux/config.h>
-
-#include <linux/radio.h>
-#ifdef CONFIG_RADIO_RTRACK
-#include "rtrack.h"
-#endif
-#ifdef CONFIG_RADIO_WINRADIO
-#include "winradio.h"
-#endif
-
-int radio_open(struct inode *inode, struct file *file);
-int radio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-
-/* /dev/radio interface */
-static struct file_operations radio_fops = {
- NULL, /* seek */
- NULL, /* read */
- NULL, /* write */
- NULL, /* readdir */
- NULL, /* select */
- &radio_ioctl, /* ioctl */
- NULL, /* mmap */
- &radio_open, /* we're not allowed NULL, it seems... */
- NULL /* release */
-};
-
-static struct miscdevice radio_miscdevice = {
- RADIO_MINOR, /* minor device number */
- "radio", /* title */
- &radio_fops, /* file operations */
- NULL, NULL /* previous and next (not our business) */
-};
-
-
-static struct radio_device *firstdevice, *lastdevice;
-static int numdevices;
-
-__initfunc(void radio_init(void))
-{
- /* register the handler for the device number... */
- if(misc_register(&radio_miscdevice)) {
- printk("radio: couldn't register misc device\n");
- return;
- }
-
- /* do some general initialisation stuff */
- lastdevice = firstdevice = NULL;
- numdevices = 0;
-
-#ifdef CONFIG_RADIO_RTRACK
- radiotrack_init();
-#endif
-#ifdef CONFIG_RADIO_WINRADIO
- printk("oooops. no winradio support yet... :-(\n");
-#endif
-/* etc.... */
-
- printk("radio: registered %d devices\n", numdevices);
-}
-
-
-/* according to drivers/char/misc.c, the "open" call must not be NULL.
- * I'm not sure if I approve, but I didn't write it, so...
- */
-int radio_open(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-
-/* append a device to the linked list... */
-int radio_add_device(struct radio_device *newdev)
-{
- if(firstdevice == NULL) {
- firstdevice = newdev;
- } else {
- lastdevice->next = newdev;
- }
- lastdevice = newdev; numdevices++;
- newdev->cap->dev_num=numdevices;
- newdev->next = NULL; /* don't need, but... */
- return(numdevices);
-}
-
-struct radio_device *getdev(int index)
-{
-struct radio_device *retval;
-
- if(index > numdevices)
- return NULL; /* let's have a bit less of that */
-
- retval = firstdevice;
- for(;index;index--)
- retval = retval->next;
-
- return retval;
-}
-
-
-/* interface routine */
-int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
-struct radio_device *dev;
-struct radio_ctl *ctl_arg = (struct radio_ctl*)arg;
-int nowrite;
-int val, ret;
-
- if((void*)arg == NULL)
- return -EFAULT; /* XXX - check errnos are OK */
-
-
- switch(cmd) {
- case RADIO_NUMDEVS:
- return (put_user(numdevices,(int*)arg) ? -EFAULT : 0);
-
-
- case RADIO_GETCAPS:
- /* p'raps I should verify for read then write ?? */
- if(verify_area(VERIFY_WRITE, (void*)arg, sizeof(struct radio_cap)))
- return -EFAULT;
- if((dev = getdev(((struct radio_cap*)arg)->dev_num)) == NULL)
- return -EINVAL;
- copy_to_user((void*)arg, dev->cap, sizeof(struct radio_cap));
- return 0;
-
-
- case RADIO_GETBNDCAP:
- if(verify_area(VERIFY_WRITE, (void*)arg, sizeof(struct radio_band)))
- return -EFAULT;
-
- if((dev = getdev(((struct radio_band*)arg)->dev_num)) == NULL)
- return -EINVAL;
-
- val = ((struct radio_band*)arg)->index;
- if(val >= dev->cap->num_bwidths)
- return -EINVAL; /* XXX errno */
-
- copy_to_user((void*)arg, (dev->bands)+(val*sizeof(struct radio_band)),
- sizeof(struct radio_band));
- return 0;
- }
-
-
-/* now, we know that arg points to a struct radio_ctl */
- /* get the requested device */
- if(verify_area(VERIFY_READ, ctl_arg, sizeof(struct radio_ctl)))
- return -EFAULT;
-
- if((dev = getdev(ctl_arg->dev_num)) == NULL)
- return -EINVAL;
-
- nowrite = verify_area(VERIFY_WRITE, ctl_arg, sizeof(struct radio_ctl));
-
- val = ctl_arg->value;
-
- switch(cmd) {
- case RADIO_SETVOL:
- if((val < dev->cap->volmin) || (val > dev->cap->volmax))
- return -EINVAL;
- if((ret = (*(dev->setvol))(dev, val)))
- return ret;
- dev->curvol = val;
- return 0;
-
- case RADIO_GETVOL:
- if(nowrite)
- return -EFAULT;
- ctl_arg->value = dev->curvol;
- return 0;
-
-
- case RADIO_SETBAND:
- if(val >= dev->cap->num_bwidths)
- return -EINVAL;
- if((ret = (*(dev->setband))(dev, val)))
- return ret;
- dev->curband = val;
- return 0;
-
- case RADIO_GETBAND:
- if(nowrite)
- return -EFAULT;
- ctl_arg->value = dev->curband;
- return 0;
-
-
- case RADIO_SETFREQ: {
- struct radio_band *bp;
-
- bp = (dev->bands) + ((dev->curband) * sizeof(struct radio_band));
- if((val < bp->freqmin) || (val > bp->freqmax))
- return -EINVAL;
- if((ret = (*(dev->setfreq))(dev, val)))
- return ret;
- dev->curfreq = val;
- return 0;
- }
-
- case RADIO_GETFREQ:
- if(nowrite)
- return -EFAULT;
- ctl_arg->value = dev->curfreq;
- return 0;
-
-
- case RADIO_GETSIGSTR:
- if(nowrite)
- return -EFAULT;
- ctl_arg->value = (*(dev->getsigstr))(dev);
- return 0;
-
-
- default:
- return -ENOSYS;
- }
-}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 13d5d6d36..b7ed4e10b 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1,9 +1,10 @@
/*
* random.c -- A strong random number generator
*
- * Version 1.03, last modified 26-Apr-97
+ * Version 1.04, last modified 26-Apr-98
*
- * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997. All rights reserved.
+ * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998. All rights
+ * reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -73,12 +74,12 @@
* an *estimate* of how many bits of randomness have been stored into
* the random number generator's internal state.
*
- * When random bytes are desired, they are obtained by taking the MD5
- * hash of the contents of the "entropy pool". The MD5 hash avoids
+ * When random bytes are desired, they are obtained by taking the SHA
+ * hash of the contents of the "entropy pool". The SHA hash avoids
* exposing the internal state of the entropy pool. It is believed to
* be computationally infeasible to derive any useful information
- * about the input of MD5 from its output. Even if it is possible to
- * analyze MD5 in some clever way, as long as the amount of data
+ * about the input of SHA from its output. Even if it is possible to
+ * analyze SHA in some clever way, as long as the amount of data
* returned from the generator is less than the inherent entropy in
* the pool, the output data is totally unpredictable. For this
* reason, the routine decreases its internal estimate of how many
@@ -88,7 +89,7 @@
* If this estimate goes to zero, the routine can still generate
* random numbers; however, an attacker may (at least in theory) be
* able to infer the future output of the generator from prior
- * outputs. This requires successful cryptanalysis of MD5, which is
+ * outputs. This requires successful cryptanalysis of SHA, which is
* not believed to be feasible, but there is a remote possibility.
* Nonetheless, these numbers should be useful for the vast majority
* of purposes.
@@ -162,12 +163,14 @@
* sequence:
*
* echo "Initializing random number generator..."
+ * random_seed=/var/run/random-seed
* # Carry a random seed from start-up to start-up
* # Load and then save 512 bytes, which is the size of the entropy pool
- * if [ -f /etc/random-seed ]; then
- * cat /etc/random-seed >/dev/urandom
+ * if [ -f $random_seed ]; then
+ * cat $random_seed >/dev/urandom
* fi
- * dd if=/dev/urandom of=/etc/random-seed count=1
+ * dd if=/dev/urandom of=$random_seed count=1
+ * chmod 600 $random_seed
*
* and the following lines in an appropriate script which is run as
* the system is shutdown:
@@ -175,10 +178,14 @@
* # Carry a random seed from shut-down to start-up
* # Save 512 bytes, which is the size of the entropy pool
* echo "Saving random seed..."
- * dd if=/dev/urandom of=/etc/random-seed count=1
+ * random_seed=/var/run/random-seed
+ * dd if=/dev/urandom of=$random_seed count=1
+ * chmod 600 $random_seed
*
- * For example, on many Linux systems, the appropriate scripts are
- * usually /etc/rc.d/rc.local and /etc/rc.d/rc.0, respectively.
+ * For example, on most modern systems using the System V init
+ * scripts, such code fragments would be found in
+ * /etc/rc.d/init.d/random. On older Linux systems, the correct script
+ * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0.
*
* Effectively, these commands cause the contents of the entropy pool
* to be saved at shut-down time and reloaded into the entropy pool at
@@ -204,18 +211,17 @@
* =================
*
* Ideas for constructing this random number generator were derived
- * from the Pretty Good Privacy's random number generator, and from
- * private discussions with Phil Karn. Colin Plumb provided a faster
- * random number generator, which speed up the mixing function of the
- * entropy pool, taken from PGP 3.0 (under development). It has since
- * been modified by myself to provide better mixing in the case where
- * the input values to add_entropy_word() are mostly small numbers.
- * Dale Worley has also contributed many useful ideas and suggestions
- * to improve this driver.
+ * from Pretty Good Privacy's random number generator, and from private
+ * discussions with Phil Karn. Colin Plumb provided a faster random
+ * number generator, which speed up the mixing function of the entropy
+ * pool, taken from PGPfone. Dale Worley has also contributed many
+ * useful ideas and suggestions to improve this driver.
*
* Any flaws in the design are solely my responsibility, and should
* not be attributed to the Phil, Colin, or any of authors of PGP.
*
+ * The code for SHA transform was taken from Peter Gutmann's
+ * implementation, which has been placed in the public domain.
* The code for MD5 transform was taken from Colin Plumb's
* implementation, which has been placed in the public domain. The
* MD5 cryptographic checksum was devised by Ronald Rivest, and is
@@ -237,6 +243,7 @@
#include <linux/poll.h>
#include <linux/init.h>
+#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -246,26 +253,66 @@
*/
#undef RANDOM_BENCHMARK
#undef BENCHMARK_NOINT
+#define ROTATE_PARANOIA
-/*
- * The pool is stirred with a primitive polynomial of degree 128
- * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
- * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
- */
#define POOLWORDS 128 /* Power of 2 - note that this is 32-bit words */
#define POOLBITS (POOLWORDS*32)
-#if POOLWORDS == 128
-#define TAP1 99 /* The polynomial taps */
-#define TAP2 59
-#define TAP3 31
-#define TAP4 9
-#define TAP5 7
-#elif POOLWORDS == 64
-#define TAP1 62 /* The polynomial taps */
-#define TAP2 38
-#define TAP3 10
-#define TAP4 6
-#define TAP5 1
+/*
+ * The pool is stirred with a primitive polynomial of degree POOLWORDS
+ * over GF(2). The taps for various sizes are defined below. They are
+ * chosen to be evenly spaced (minimum RMS distance from evenly spaced;
+ * the numbers in the comments are a scaled squared error sum) except
+ * for the last tap, which is 1 to get the twisting happening as fast
+ * as possible.
+ */
+#if POOLWORDS == 2048 /* 115 x^2048+x^1638+x^1231+x^819+x^411+x^1+1 */
+#define TAP1 1638
+#define TAP2 1231
+#define TAP3 819
+#define TAP4 411
+#define TAP5 1
+#elif POOLWORDS == 1024 /* 290 x^1024+x^817+x^615+x^412+x^204+x^1+1 */
+/* Alt: 115 x^1024+x^819+x^616+x^410+x^207+x^2+1 */
+#define TAP1 817
+#define TAP2 615
+#define TAP3 412
+#define TAP4 204
+#define TAP5 1
+#elif POOLWORDS == 512 /* 225 x^512+x^411+x^308+x^208+x^104+x+1 */
+/* Alt: 95 x^512+x^409+x^307+x^206+x^102+x^2+1
+ * 95 x^512+x^409+x^309+x^205+x^103+x^2+1 */
+#define TAP1 411
+#define TAP2 308
+#define TAP3 208
+#define TAP4 104
+#define TAP5 1
+#elif POOLWORDS == 256 /* 125 x^256+x^205+x^155+x^101+x^52+x+1 */
+#define TAP1 205
+#define TAP2 155
+#define TAP3 101
+#define TAP4 52
+#define TAP5 1
+#elif POOLWORDS == 128 /* 105 x^128+x^103+x^76+x^51+x^25+x+1 */
+/* Alt: 70 x^128+x^103+x^78+x^51+x^27+x^2+1 */
+#define TAP1 103
+#define TAP2 76
+#define TAP3 51
+#define TAP4 25
+#define TAP5 1
+#elif POOLWORDS == 64 /* 15 x^64+x^52+x^39+x^26+x^14+x+1 */
+#define TAP1 52
+#define TAP2 39
+#define TAP3 26
+#define TAP4 14
+#define TAP5 1
+#elif POOLWORDS == 32 /* 15 x^32+x^26+x^20+x^14+x^7+x^1+1 */
+#define TAP1 26
+#define TAP2 20
+#define TAP3 14
+#define TAP4 7
+#define TAP5 1
+#elif POOLWORDS & (POOLWORDS-1)
+#error POOLWORDS must be a power of 2
#else
#error No primitive polynomial available for chosen POOLWORDS
#endif
@@ -279,11 +326,38 @@
* Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators
* II. ACM Transactions on Mdeling and Computer Simulation 4:254-266)
*
- * Thanks to Colin Plumb for suggesting this. (Note that the behavior
- * of the 1.0 version of the driver was equivalent to using a second
- * element of 0x80000000).
+ * Thanks to Colin Plumb for suggesting this.
+ * We have not analyzed the resultant polynomial to prove it primitive;
+ * in fact it almost certainly isn't. Nonetheless, the irreducible factors
+ * of a random large-degree polynomial over GF(2) are more than large enough
+ * that periodicity is not a concern.
+ *
+ * The input hash is much less sensitive than the output hash. All that
+ * we want of it is that it be a good non-cryptographic hash; i.e. it
+ * not produce collisions when fed "random" data of the sort we expect
+ * to see. As long as the pool state differs for different inputs, we
+ * have preserved the input entropy and done a good job. The fact that an
+ * intelligent attacker can construct inputs that will produce controlled
+ * alterations to the pool's state is not important because we don't
+ * consider such inputs to contribute any randomness.
+ * The only property we need with respect to them is
+ * that the attacker can't increase his/her knowledge of the pool's state.
+ * Since all additions are reversible (knowing the final state and the
+ * input, you can reconstruct the initial state), if an attacker has
+ * any uncertainty about the initial state, he/she can only shuffle that
+ * uncertainty about, but never cause any collisions (which would
+ * decrease the uncertainty).
+ *
+ * The chosen system lets the state of the pool be (essentially) the input
+ * modulo the generator polymnomial. Now, for random primitive polynomials,
+ * this is a universal class of hash functions, meaning that the chance
+ * of a collision is limited by the attacker's knowledge of the generator
+ * polynomail, so if it is chosen at random, an attacker can never force
+ * a collision. Here, we use a fixed polynomial, but we *can* assume that
+ * ###--> it is unknown to the processes generating the input entropy. <-###
+ * Because of this important property, this is a good, collision-resistant
+ * hash; hash collisions will occur no more often than chance.
*/
-static __u32 twist_table[2] = { 0, 0xEDB88320 };
/*
* The minimum number of bits to release a "wait on input". Should
@@ -303,7 +377,9 @@ static __u32 twist_table[2] = { 0, 0xEDB88320 };
struct random_bucket {
unsigned add_ptr;
unsigned entropy_count;
+#ifdef ROTATE_PARANOIA
int input_rotate;
+#endif
__u32 pool[POOLWORDS];
};
@@ -332,8 +408,8 @@ struct random_benchmark timer_benchmark;
/* There is one of these per entropy source */
struct timer_rand_state {
- unsigned long last_time;
- int last_delta,last_delta2;
+ __u32 last_time;
+ __s32 last_delta,last_delta2;
int dont_count_entropy:1;
};
@@ -356,11 +432,10 @@ static ssize_t random_write(struct file * file, const char * buffer,
static int random_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
-static inline void fast_add_entropy_word(struct random_bucket *r,
- const __u32 input);
+static inline void fast_add_entropy_words(struct random_bucket *r,
+ __u32 x, __u32 y);
-static void add_entropy_word(struct random_bucket *r,
- const __u32 input);
+static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y);
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
@@ -391,33 +466,36 @@ extern inline __u32 rotate_left(int i, __u32 word)
* More asm magic....
*
* For entropy estimation, we need to do an integral base 2
- * logarithm. By default, use an open-coded C version, although we do
- * have a version which takes advantage of the Intel's x86's "bsr"
- * instruction.
+ * logarithm.
+ *
+ * Note the "12bits" suffix - this is used for numbers between
+ * 0 and 4095 only. This allows a few shortcuts.
*/
-#if (!defined (__i386__))
-static inline __u32 int_ln(__u32 word)
+#if 0 /* Slow but clear version */
+static inline __u32 int_ln_12bits(__u32 word)
{
__u32 nbits = 0;
- while (1) {
- word >>= 1;
- if (!word)
- break;
+ while (word >>= 1)
nbits++;
- }
return nbits;
}
-#else
-static inline __u32 int_ln(__u32 word)
+#else /* Faster (more clever) version, courtesy Colin Plumb */
+static inline __u32 int_ln_12bits(__u32 word)
{
- __asm__("bsrl %1,%0\n\t"
- "jnz 1f\n\t"
- "movl $0,%0\n"
- "1:"
- :"=r" (word)
- :"r" (word));
- return word;
+ /* Smear msbit right to make an n-bit mask */
+ word |= word >> 8;
+ word |= word >> 4;
+ word |= word >> 2;
+ word |= word >> 1;
+ /* Remove one bit to make this a logarithm */
+ word >>= 1;
+ /* Count the bits set in the word */
+ word -= (word >> 1) & 0x555;
+ word = (word & 0x333) + ((word >> 2) & 0x333);
+ word += (word >> 4);
+ word += (word >> 8);
+ return word & 15;
}
#endif
@@ -429,19 +507,22 @@ static inline __u32 int_ln(__u32 word)
*/
static void init_std_data(struct random_bucket *r)
{
- __u32 word, *p;
+ __u32 words[2], *p;
int i;
struct timeval tv;
do_gettimeofday(&tv);
- add_entropy_word(r, tv.tv_sec);
- add_entropy_word(r, tv.tv_usec);
-
- for (p = (__u32 *) &system_utsname,
- i = sizeof(system_utsname) / sizeof(__u32);
- i ; i--, p++) {
- memcpy(&word, p, sizeof(__u32));
- add_entropy_word(r, word);
+ add_entropy_words(r, tv.tv_sec, tv.tv_usec);
+
+ /*
+ * This doesnt lock system.utsname. Howeve we are generating
+ * entropy so a race with a name set here is fine.
+ */
+ p = (__u32 *)&system_utsname;
+ for (i = sizeof(system_utsname) / sizeof(words); i; i--) {
+ memcpy(words, p, sizeof(words));
+ add_entropy_words(r, words[0], words[1]);
+ p += sizeof(words)/sizeof(*words);
}
}
@@ -513,54 +594,90 @@ void rand_initialize_blkdev(int major, int mode)
* This function adds a byte into the entropy "pool". It does not
* update the entropy estimate. The caller must do this if appropriate.
*
- * The pool is stirred with a primitive polynomial of degree 128
- * over GF(2), namely x^128 + x^99 + x^59 + x^31 + x^9 + x^7 + 1.
- * For a pool of size 64, try x^64+x^62+x^38+x^10+x^6+x+1.
- *
- * We rotate the input word by a changing number of bits, to help
- * assure that all bits in the entropy get toggled. Otherwise, if we
- * consistently feed the entropy pool small numbers (like jiffies and
- * scancodes, for example), the upper bits of the entropy pool don't
- * get affected. --- TYT, 10/11/95
+ * This function is tuned for speed above most other considerations.
+ *
+ * The pool is stirred with a primitive polynomial of the appropriate degree,
+ * and then twisted. We twist by three bits at a time because it's
+ * cheap to do so and helps slightly in the expected case where the
+ * entropy is concentrated in the low-order bits.
*/
-static inline void fast_add_entropy_word(struct random_bucket *r,
- const __u32 input)
+#define MASK(x) ((x) & (POOLWORDS-1)) /* Convenient abreviation */
+static inline void fast_add_entropy_words(struct random_bucket *r,
+ __u32 x, __u32 y)
{
- unsigned i;
- int new_rotate;
- __u32 w;
+ static __u32 const twist_table[8] = {
+ 0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+ 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
+ unsigned i, j;
+
+ i = MASK(r->add_ptr - 2); /* i is always even */
+ r->add_ptr = i;
+
+#ifdef ROTATE_PARANOIA
+ j = r->input_rotate + 14;
+ if (i)
+ j -= 7;
+ r->input_rotate = j & 31;
+
+ x = rotate_left(r->input_rotate, x);
+ y = rotate_left(r->input_rotate, y);
+#endif
/*
- * Normally, we add 7 bits of rotation to the pool. At the
- * beginning of the pool, add an extra 7 bits rotation, so
- * that successive passes spread the input bits across the
- * pool evenly.
+ * XOR in the various taps. Even though logically, we compute
+ * x and then compute y, we read in y then x order because most
+ * caches work slightly better with increasing read addresses.
+ * If a tap is even then we can use the fact that i is even to
+ * avoid a masking operation. Every polynomial has at least one
+ * even tap, so j is always used.
+ * (Is there a nicer way to arrange this code?)
*/
- new_rotate = r->input_rotate + 14;
- if ((i = r->add_ptr--))
- new_rotate -= 7;
- r->input_rotate = new_rotate & 31;
-
- w = rotate_left(r->input_rotate, input);
-
- /* XOR in the various taps */
- w ^= r->pool[(i+TAP1)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP2)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP3)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP4)&(POOLWORDS-1)];
- w ^= r->pool[(i+TAP5)&(POOLWORDS-1)];
- w ^= r->pool[i&(POOLWORDS-1)];
- /* Use a twisted GFSR for the mixing operation */
- r->pool[i&(POOLWORDS-1)] = (w >> 1) ^ twist_table[w & 1];
+#if TAP1 & 1
+ y ^= r->pool[MASK(i+TAP1)]; x ^= r->pool[MASK(i+TAP1+1)];
+#else
+ j = MASK(i+TAP1); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP2 & 1
+ y ^= r->pool[MASK(i+TAP2)]; x ^= r->pool[MASK(i+TAP2+1)];
+#else
+ j = MASK(i+TAP2); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP3 & 1
+ y ^= r->pool[MASK(i+TAP3)]; x ^= r->pool[MASK(i+TAP3+1)];
+#else
+ j = MASK(i+TAP3); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP4 & 1
+ y ^= r->pool[MASK(i+TAP4)]; x ^= r->pool[MASK(i+TAP4+1)];
+#else
+ j = MASK(i+TAP4); y ^= r->pool[j]; x ^= r->pool[j+1];
+#endif
+#if TAP5 == 1
+ /* We need to pretend to write pool[i+1] before computing y */
+ y ^= r->pool[i];
+ x ^= r->pool[i+1];
+ x ^= r->pool[MASK(i+TAP5+1)];
+ y ^= r->pool[i+1] = x = (x >> 3) ^ twist_table[x & 7];
+ r->pool[i] = (y >> 3) ^ twist_table[y & 7];
+#else
+# if TAP5 & 1
+ y ^= r->pool[MASK(i+TAP5)]; x ^= r->pool[MASK(i+TAP5+1)];
+# else
+ j = MASK(i+TAP5); y ^= r->pool[j]; x ^= r->pool[j+1];
+# endif
+ y ^= r->pool[i];
+ x ^= r->pool[i+1];
+ r->pool[i] = (y >> 3) ^ twist_table[y & 7];
+ r->pool[i+1] = (x >> 3) ^ twist_table[x & 7];
+#endif
}
/*
* For places where we don't need the inlined version
*/
-static void add_entropy_word(struct random_bucket *r,
- const __u32 input)
+static void add_entropy_words(struct random_bucket *r, __u32 x, __u32 y)
{
- fast_add_entropy_word(r, input);
+ fast_add_entropy_words(r, x, y);
}
/*
@@ -578,19 +695,18 @@ static void add_entropy_word(struct random_bucket *r,
static void add_timer_randomness(struct random_bucket *r,
struct timer_rand_state *state, unsigned num)
{
- int delta, delta2, delta3;
__u32 time;
+ __s32 delta, delta2, delta3;
#ifdef RANDOM_BENCHMARK
begin_benchmark(&timer_benchmark);
#endif
#if defined (__i386__)
- if (boot_cpu_data.x86_capability & 16) {
- unsigned long low, high;
+ if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+ __u32 high;
__asm__(".byte 0x0f,0x31"
- :"=a" (low), "=d" (high));
- time = (__u32) low;
- num ^= (__u32) high;
+ :"=a" (time), "=d" (high));
+ num ^= high;
} else {
time = jiffies;
}
@@ -598,42 +714,53 @@ static void add_timer_randomness(struct random_bucket *r,
time = jiffies;
#endif
- fast_add_entropy_word(r, (__u32) num);
- fast_add_entropy_word(r, time);
+ fast_add_entropy_words(r, (__u32)num, time);
/*
- * Calculate number of bits of randomness we probably
- * added. We take into account the first and second order
- * deltas in order to make our estimate.
+ * Calculate number of bits of randomness we probably added.
+ * We take into account the first, second and third-order deltas
+ * in order to make our estimate.
*/
- if (!state->dont_count_entropy &&
- (r->entropy_count < POOLBITS)) {
+ if ((r->entropy_count < POOLBITS) && !state->dont_count_entropy) {
delta = time - state->last_time;
state->last_time = time;
- if (delta < 0) delta = -delta;
delta2 = delta - state->last_delta;
state->last_delta = delta;
- if (delta2 < 0) delta2 = -delta2;
delta3 = delta2 - state->last_delta2;
state->last_delta2 = delta2;
- if (delta3 < 0) delta3 = -delta3;
- delta = MIN(MIN(delta, delta2), delta3) >> 1;
- /* Limit entropy estimate to 12 bits */
+ if (delta < 0)
+ delta = -delta;
+ if (delta2 < 0)
+ delta2 = -delta2;
+ if (delta3 < 0)
+ delta3 = -delta3;
+ if (delta > delta2)
+ delta = delta2;
+ if (delta > delta3)
+ delta = delta3;
+
+ /*
+ * delta is now minimum absolute delta.
+ * Round down by 1 bit on general principles,
+ * and limit entropy entimate to 12 bits.
+ */
+ delta >>= 1;
delta &= (1 << 12) - 1;
- r->entropy_count += int_ln(delta);
+ r->entropy_count += int_ln_12bits(delta);
/* Prevent overflow */
if (r->entropy_count > POOLBITS)
r->entropy_count = POOLBITS;
+
+ /* Wake up waiting processes, if we have enough entropy. */
+ if (r->entropy_count >= WAIT_INPUT_BITS)
+ wake_up_interruptible(&random_read_wait);
}
- /* Wake up waiting processes, if we have enough entropy. */
- if (r->entropy_count >= WAIT_INPUT_BITS)
- wake_up_interruptible(&random_read_wait);
#ifdef RANDOM_BENCHMARK
end_benchmark(&timer_benchmark);
#endif
@@ -672,52 +799,84 @@ void add_blkdev_randomness(int major)
0x200+major);
}
+/*
+ * This chunk of code defines a function
+ * void HASH_TRANSFORM(__u32 digest[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE],
+ * __u32 const data[16])
+ *
+ * The function hashes the input data to produce a digest in the first
+ * HASH_BUFFER_SIZE words of the digest[] array, and uses HASH_EXTRA_SIZE
+ * more words for internal purposes. (This buffer is exported so the
+ * caller can wipe it once rather than this code doing it each call,
+ * and tacking it onto the end of the digest[] array is the quick and
+ * dirty way of doing it.)
+ *
+ * It so happens that MD5 and SHA share most of the initial vector
+ * used to initialize the digest[] array before the first call:
+ * 1) 0x67452301
+ * 2) 0xefcdab89
+ * 3) 0x98badcfe
+ * 4) 0x10325476
+ * 5) 0xc3d2e1f0 (SHA only)
+ *
+ * For /dev/random purposes, the length of the data being hashed is
+ * fixed in length (at POOLWORDS words), so appending a bit count in
+ * the usual way is not cryptographically necessary.
+ */
#define USE_SHA
#ifdef USE_SHA
-#define SMALL_VERSION /* Optimize for space over time */
-
#define HASH_BUFFER_SIZE 5
+#define HASH_EXTRA_SIZE 80
#define HASH_TRANSFORM SHATransform
+/* Various size/speed tradeoffs are available. Choose 0..3. */
+#define SHA_CODE_SIZE 0
+
/*
- * SHA transform algorithm, taken from code written by Peter Gutman,
- * and apparently in the public domain.
+ * SHA transform algorithm, taken from code written by Peter Gutmann,
+ * and placed in the public domain.
*/
/* The SHA f()-functions. */
-#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */
-#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
-#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */
-#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
+#define f1(x,y,z) ( z ^ (x & (y^z)) ) /* Rounds 0-19: x ? y : z */
+#define f2(x,y,z) (x ^ y ^ z) /* Rounds 20-39: XOR */
+#define f3(x,y,z) ( (x & y) + (z & (x ^ y)) ) /* Rounds 40-59: majority */
+#define f4(x,y,z) (x ^ y ^ z) /* Rounds 60-79: XOR */
/* The SHA Mysterious Constants */
-#define K1 0x5A827999L /* Rounds 0-19 */
-#define K2 0x6ED9EBA1L /* Rounds 20-39 */
-#define K3 0x8F1BBCDCL /* Rounds 40-59 */
-#define K4 0xCA62C1D6L /* Rounds 60-79 */
+#define K1 0x5A827999L /* Rounds 0-19: sqrt(2) * 2^30 */
+#define K2 0x6ED9EBA1L /* Rounds 20-39: sqrt(3) * 2^30 */
+#define K3 0x8F1BBCDCL /* Rounds 40-59: sqrt(5) * 2^30 */
+#define K4 0xCA62C1D6L /* Rounds 60-79: sqrt(10) * 2^30 */
#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
-#define expand(W,i) ( W[ i & 15 ] = \
- ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
- W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
-
#define subRound(a, b, c, d, e, f, k, data) \
( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
-static void SHATransform(__u32 *digest, __u32 *data)
- {
+static void SHATransform(__u32 digest[85], __u32 const data[16])
+{
__u32 A, B, C, D, E; /* Local vars */
- __u32 eData[ 16 ]; /* Expanded data */
-#ifdef SMALL_VERSION
- int i;
__u32 TEMP;
-#endif
+ int i;
+#define W (digest + HASH_BUFFER_SIZE) /* Expanded data array */
+
+ /*
+ * Do the preliminary expansion of 16 to 80 words. Doing it
+ * out-of-line line this is faster than doing it in-line on
+ * register-starved machines like the x86, and not really any
+ * slower on real processors.
+ */
+ memcpy(W, data, 16*sizeof(__u32));
+ for (i = 0; i < 64; i++) {
+ TEMP = W[i] ^ W[i+2] ^ W[i+8] ^ W[i+13];
+ W[i+16] = ROTL(1, TEMP);
+ }
/* Set up first buffer and local data buffer */
A = digest[ 0 ];
@@ -725,112 +884,161 @@ static void SHATransform(__u32 *digest, __u32 *data)
C = digest[ 2 ];
D = digest[ 3 ];
E = digest[ 4 ];
- memcpy( eData, data, 16*sizeof(__u32));
-#ifdef SMALL_VERSION
+ /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
+#if SHA_CODE_SIZE == 0
/*
- * Approximately 50% of the speed of the optimized version, but
+ * Approximately 50% of the speed of the largest version, but
* takes up 1/16 the space. Saves about 6k on an i386 kernel.
*/
- for (i=0; i < 80; i++) {
+ for (i = 0; i < 80; i++) {
+ if (i < 40) {
if (i < 20)
- TEMP = f1(B, C, D) + K1;
- else if (i < 40)
- TEMP = f2(B, C, D) + K2;
- else if (i < 60)
- TEMP = f3(B, C, D) + K3;
+ TEMP = f1(B, C, D) + K1;
else
- TEMP = f4(B, C, D) + K4;
- TEMP += ROTL (5, A) + E +
- ((i > 15) ? expand(eData, i) : eData[i]);
- E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ TEMP = f2(B, C, D) + K2;
+ } else {
+ if (i < 60)
+ TEMP = f3(B, C, D) + K3;
+ else
+ TEMP = f4(B, C, D) + K4;
+ }
+ TEMP += ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
}
+#elif SHA_CODE_SIZE == 1
+ for (i = 0; i < 20; i++) {
+ TEMP = f1(B, C, D) + K1 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+ for (; i < 40; i++) {
+ TEMP = f2(B, C, D) + K2 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+ for (; i < 60; i++) {
+ TEMP = f3(B, C, D) + K3 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+ for (; i < 80; i++) {
+ TEMP = f4(B, C, D) + K4 + ROTL(5, A) + E + W[i];
+ E = D; D = C; C = ROTL(30, B); B = A; A = TEMP;
+ }
+#elif SHA_CODE_SIZE == 2
+ for (i = 0; i < 20; i += 5) {
+ subRound( A, B, C, D, E, f1, K1, W[ i ] );
+ subRound( E, A, B, C, D, f1, K1, W[ i+1 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ i+2 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ i+3 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ i+4 ] );
+ }
+ for (; i < 40; i += 5) {
+ subRound( A, B, C, D, E, f2, K2, W[ i ] );
+ subRound( E, A, B, C, D, f2, K2, W[ i+1 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ i+2 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ i+3 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ i+4 ] );
+ }
+ for (; i < 60; i += 5) {
+ subRound( A, B, C, D, E, f3, K3, W[ i ] );
+ subRound( E, A, B, C, D, f3, K3, W[ i+1 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ i+2 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ i+3 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ i+4 ] );
+ }
+ for (; i < 80; i += 5) {
+ subRound( A, B, C, D, E, f4, K4, W[ i ] );
+ subRound( E, A, B, C, D, f4, K4, W[ i+1 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ i+2 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ i+3 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ i+4 ] );
+ }
+#elif SHA_CODE_SIZE == 3 /* Really large version */
+ subRound( A, B, C, D, E, f1, K1, W[ 0 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 1 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 2 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 3 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 4 ] );
+ subRound( A, B, C, D, E, f1, K1, W[ 5 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 6 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 7 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 8 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 9 ] );
+ subRound( A, B, C, D, E, f1, K1, W[ 10 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 11 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 12 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 13 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 14 ] );
+ subRound( A, B, C, D, E, f1, K1, W[ 15 ] );
+ subRound( E, A, B, C, D, f1, K1, W[ 16 ] );
+ subRound( D, E, A, B, C, f1, K1, W[ 17 ] );
+ subRound( C, D, E, A, B, f1, K1, W[ 18 ] );
+ subRound( B, C, D, E, A, f1, K1, W[ 19 ] );
+
+ subRound( A, B, C, D, E, f2, K2, W[ 20 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 21 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 22 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 23 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 24 ] );
+ subRound( A, B, C, D, E, f2, K2, W[ 25 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 26 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 27 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 28 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 29 ] );
+ subRound( A, B, C, D, E, f2, K2, W[ 30 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 31 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 32 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 33 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 34 ] );
+ subRound( A, B, C, D, E, f2, K2, W[ 35 ] );
+ subRound( E, A, B, C, D, f2, K2, W[ 36 ] );
+ subRound( D, E, A, B, C, f2, K2, W[ 37 ] );
+ subRound( C, D, E, A, B, f2, K2, W[ 38 ] );
+ subRound( B, C, D, E, A, f2, K2, W[ 39 ] );
+
+ subRound( A, B, C, D, E, f3, K3, W[ 40 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 41 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 42 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 43 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 44 ] );
+ subRound( A, B, C, D, E, f3, K3, W[ 45 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 46 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 47 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 48 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 49 ] );
+ subRound( A, B, C, D, E, f3, K3, W[ 50 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 51 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 52 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 53 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 54 ] );
+ subRound( A, B, C, D, E, f3, K3, W[ 55 ] );
+ subRound( E, A, B, C, D, f3, K3, W[ 56 ] );
+ subRound( D, E, A, B, C, f3, K3, W[ 57 ] );
+ subRound( C, D, E, A, B, f3, K3, W[ 58 ] );
+ subRound( B, C, D, E, A, f3, K3, W[ 59 ] );
+
+ subRound( A, B, C, D, E, f4, K4, W[ 60 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 61 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 62 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 63 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 64 ] );
+ subRound( A, B, C, D, E, f4, K4, W[ 65 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 66 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 67 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 68 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 69 ] );
+ subRound( A, B, C, D, E, f4, K4, W[ 70 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 71 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 72 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 73 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 74 ] );
+ subRound( A, B, C, D, E, f4, K4, W[ 75 ] );
+ subRound( E, A, B, C, D, f4, K4, W[ 76 ] );
+ subRound( D, E, A, B, C, f4, K4, W[ 77 ] );
+ subRound( C, D, E, A, B, f4, K4, W[ 78 ] );
+ subRound( B, C, D, E, A, f4, K4, W[ 79 ] );
#else
- /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
- subRound( A, B, C, D, E, f1, K1, eData[ 0 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 1 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 2 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 3 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 4 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 5 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 6 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 7 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 8 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 9 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 10 ] );
- subRound( E, A, B, C, D, f1, K1, eData[ 11 ] );
- subRound( D, E, A, B, C, f1, K1, eData[ 12 ] );
- subRound( C, D, E, A, B, f1, K1, eData[ 13 ] );
- subRound( B, C, D, E, A, f1, K1, eData[ 14 ] );
- subRound( A, B, C, D, E, f1, K1, eData[ 15 ] );
- subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) );
- subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) );
- subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) );
- subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) );
-
- subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) );
- subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) );
- subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) );
- subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) );
- subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) );
- subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) );
-
- subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) );
- subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) );
- subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) );
- subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) );
- subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) );
- subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) );
-
- subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) );
- subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) );
- subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) );
- subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) );
- subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) );
- subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) );
-#endif /* SMALL_VERSION */
+#error Illegal SHA_CODE_SIZE
+#endif
/* Build message digest */
digest[ 0 ] += A;
@@ -838,7 +1046,10 @@ static void SHATransform(__u32 *digest, __u32 *data)
digest[ 2 ] += C;
digest[ 3 ] += D;
digest[ 4 ] += E;
- }
+
+ /* W is wiped by the caller */
+#undef W
+}
#undef ROTL
#undef f1
@@ -849,11 +1060,12 @@ static void SHATransform(__u32 *digest, __u32 *data)
#undef K2
#undef K3
#undef K4
-#undef expand
#undef subRound
-#else
+#else /* !USE_SHA - Use MD5 */
+
#define HASH_BUFFER_SIZE 4
+#define HASH_EXTRA_SIZE 0
#define HASH_TRANSFORM MD5Transform
/*
@@ -881,8 +1093,7 @@ static void SHATransform(__u32 *digest, __u32 *data)
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
-static void MD5Transform(__u32 buf[4],
- __u32 const in[16])
+static void MD5Transform(__u32 buf[HASH_BUFFER_SIZE], __u32 const in[16])
{
__u32 a, b, c, d;
@@ -971,10 +1182,10 @@ static void MD5Transform(__u32 buf[4],
#undef F4
#undef MD5STEP
-#endif
+#endif /* !USE_SHA */
-#if POOLWORDS % 16
+#if POOLWORDS % 16 != 0
#error extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
#endif
/*
@@ -987,8 +1198,8 @@ static ssize_t extract_entropy(struct random_bucket *r, char * buf,
size_t nbytes, int to_user)
{
ssize_t ret, i;
- __u32 tmp[HASH_BUFFER_SIZE];
- char *cp,*dp;
+ __u32 tmp[HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+ __u32 x;
add_timer_randomness(r, &extract_timer_state, nbytes);
@@ -1016,31 +1227,33 @@ static ssize_t extract_entropy(struct random_bucket *r, char * buf,
#endif
for (i = 0; i < POOLWORDS; i += 16)
HASH_TRANSFORM(tmp, r->pool+i);
- /* Modify pool so next hash will produce different results */
- add_entropy_word(r, tmp[0]);
- add_entropy_word(r, tmp[1]);
- add_entropy_word(r, tmp[2]);
- add_entropy_word(r, tmp[3]);
-#ifdef USE_SHA
- add_entropy_word(r, tmp[4]);
-#endif
- /*
- * Run the hash transform one more time, since we want
- * to add at least minimal obscuring of the inputs to
- * add_entropy_word().
- */
- HASH_TRANSFORM(tmp, r->pool);
/*
- * In case the hash function has some recognizable
- * output pattern, we fold it in half.
+ * The following code does two separate things that happen
+ * to both work two words at a time, so are convenient
+ * to do together.
+ *
+ * First, this feeds the output back into the pool so
+ * that the next call will return different results.
+ * Any perturbation of the pool's state would do, even
+ * changing one bit, but this mixes the pool nicely.
+ *
+ * Second, this folds the output in half to hide the data
+ * fed back into the pool from the user and further mask
+ * any patterns in the hash output. (The exact folding
+ * pattern is not important; the one used here is quick.)
*/
- cp = (char *) tmp;
- dp = cp + (HASH_BUFFER_SIZE*sizeof(__u32)) - 1;
- for (i=0; i < HASH_BUFFER_SIZE*sizeof(__u32)/2; i++) {
- *cp ^= *dp;
- cp++; dp--;
+ for (i = 0; i < HASH_BUFFER_SIZE/2; i++) {
+ x = tmp[i + (HASH_BUFFER_SIZE+1)/2];
+ add_entropy_words(r, tmp[i], x);
+ tmp[i] ^= x;
}
+#if HASH_BUFFER_SIZE & 1 /* There's a middle word to deal with */
+ x = tmp[HASH_BUFFER_SIZE/2];
+ add_entropy_words(r, x, (__u32)buf);
+ x ^= (x >> 16); /* Fold it in half */
+ ((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x;
+#endif
/* Copy data to destination buffer */
i = MIN(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2);
@@ -1055,11 +1268,11 @@ static ssize_t extract_entropy(struct random_bucket *r, char * buf,
nbytes -= i;
buf += i;
add_timer_randomness(r, &extract_timer_state, nbytes);
- if (to_user && need_resched)
+ if (to_user && current->need_resched)
schedule();
}
- /* Wipe data from memory */
+ /* Wipe data just returned from memory */
memset(tmp, 0, sizeof(tmp));
return ret;
@@ -1105,8 +1318,7 @@ random_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
}
n = extract_entropy(&random_state, buf, n, 1);
if (n < 0) {
- if (count == 0)
- retval = n;
+ retval = n;
break;
}
count += n;
@@ -1154,33 +1366,36 @@ static ssize_t
random_write(struct file * file, const char * buffer,
size_t count, loff_t *ppos)
{
- ssize_t i, bytes, ret = 0;
+ int ret = 0;
+ size_t bytes;
+ unsigned i;
__u32 buf[16];
const char *p = buffer;
- ssize_t c = count;
+ size_t c = count;
while (c > 0) {
bytes = MIN(c, sizeof(buf));
bytes -= copy_from_user(&buf, p, bytes);
if (!bytes) {
- if (!ret)
- ret = -EFAULT;
+ ret = -EFAULT;
break;
}
c -= bytes;
p += bytes;
- ret += bytes;
- i = (bytes+sizeof(__u32)-1) / sizeof(__u32);
- while (i--)
- add_entropy_word(&random_state, buf[i]);
+ i = (unsigned)((bytes-1) / (2 * sizeof(__u32)));
+ do {
+ add_entropy_words(&random_state, buf[2*i], buf[2*i+1]);
+ } while (i--);
}
- if (ret > 0) {
+ if (p == buffer) {
+ return (ssize_t)ret;
+ } else {
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
mark_inode_dirty(file->f_dentry->d_inode);
+ return (ssize_t)(p - buffer);
}
- return ret;
}
static int
@@ -1344,19 +1559,17 @@ struct file_operations urandom_fops = {
#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
-
-/* FF, GG and HH are MD4 transformations for rounds 1, 2 and 3 */
-/* Rotation is separate from addition to prevent recomputation */
-#define FF(a, b, c, d, x, s) \
- {(a) += F ((b), (c), (d)) + (x); \
- (a) = ROTL ((s), (a));}
-#define GG(a, b, c, d, x, s) \
- {(a) += G ((b), (c), (d)) + (x) + 013240474631UL; \
- (a) = ROTL ((s), (a));}
-#define HH(a, b, c, d, x, s) \
- {(a) += H ((b), (c), (d)) + (x) + 015666365641UL; \
- (a) = ROTL ((s), (a));}
+/*
+ * The generic round function. The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s) \
+ (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
/*
* Basic cut-down MD4 transform. Returns only 32 bits of result.
@@ -1366,39 +1579,100 @@ static __u32 halfMD4Transform (__u32 const buf[4], __u32 const in[8])
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
- FF (a, b, c, d, in[ 0], 3);
- FF (d, a, b, c, in[ 1], 7);
- FF (c, d, a, b, in[ 2], 11);
- FF (b, c, d, a, in[ 3], 19);
- FF (a, b, c, d, in[ 4], 3);
- FF (d, a, b, c, in[ 5], 7);
- FF (c, d, a, b, in[ 6], 11);
- FF (b, c, d, a, in[ 7], 19);
+ ROUND(F, a, b, c, d, in[0] + K1, 3);
+ ROUND(F, d, a, b, c, in[1] + K1, 7);
+ ROUND(F, c, d, a, b, in[2] + K1, 11);
+ ROUND(F, b, c, d, a, in[3] + K1, 19);
+ ROUND(F, a, b, c, d, in[4] + K1, 3);
+ ROUND(F, d, a, b, c, in[5] + K1, 7);
+ ROUND(F, c, d, a, b, in[6] + K1, 11);
+ ROUND(F, b, c, d, a, in[7] + K1, 19);
/* Round 2 */
- GG (a, b, c, d, in[ 0], 3);
- GG (d, a, b, c, in[ 4], 5);
- GG (c, d, a, b, in[ 1], 9);
- GG (b, c, d, a, in[ 5], 13);
- GG (a, b, c, d, in[ 2], 3);
- GG (d, a, b, c, in[ 6], 5);
- GG (c, d, a, b, in[ 3], 9);
- GG (b, c, d, a, in[ 7], 13);
+ ROUND(G, a, b, c, d, in[1] + K2, 3);
+ ROUND(G, d, a, b, c, in[3] + K2, 5);
+ ROUND(G, c, d, a, b, in[5] + K2, 9);
+ ROUND(G, b, c, d, a, in[7] + K2, 13);
+ ROUND(G, a, b, c, d, in[0] + K2, 3);
+ ROUND(G, d, a, b, c, in[2] + K2, 5);
+ ROUND(G, c, d, a, b, in[4] + K2, 9);
+ ROUND(G, b, c, d, a, in[6] + K2, 13);
/* Round 3 */
- HH (a, b, c, d, in[ 0], 3);
- HH (d, a, b, c, in[ 4], 9);
- HH (c, d, a, b, in[ 2], 11);
- HH (b, c, d, a, in[ 6], 15);
- HH (a, b, c, d, in[ 1], 3);
- HH (d, a, b, c, in[ 5], 9);
- HH (c, d, a, b, in[ 3], 11);
- HH (b, c, d, a, in[ 7], 15);
+ ROUND(H, a, b, c, d, in[3] + K3, 3);
+ ROUND(H, d, a, b, c, in[7] + K3, 9);
+ ROUND(H, c, d, a, b, in[2] + K3, 11);
+ ROUND(H, b, c, d, a, in[6] + K3, 15);
+ ROUND(H, a, b, c, d, in[1] + K3, 3);
+ ROUND(H, d, a, b, c, in[5] + K3, 9);
+ ROUND(H, c, d, a, b, in[0] + K3, 11);
+ ROUND(H, b, c, d, a, in[4] + K3, 15);
return buf[1] + b; /* "most hashed" word */
/* Alternative: return sum of all words? */
}
+#if 0 /* May be needed for IPv6 */
+
+static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
+{
+ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ ROUND(F, a, b, c, d, in[ 0] + K1, 3);
+ ROUND(F, d, a, b, c, in[ 1] + K1, 7);
+ ROUND(F, c, d, a, b, in[ 2] + K1, 11);
+ ROUND(F, b, c, d, a, in[ 3] + K1, 19);
+ ROUND(F, a, b, c, d, in[ 4] + K1, 3);
+ ROUND(F, d, a, b, c, in[ 5] + K1, 7);
+ ROUND(F, c, d, a, b, in[ 6] + K1, 11);
+ ROUND(F, b, c, d, a, in[ 7] + K1, 19);
+ ROUND(F, a, b, c, d, in[ 8] + K1, 3);
+ ROUND(F, d, a, b, c, in[ 9] + K1, 7);
+ ROUND(F, c, d, a, b, in[10] + K1, 11);
+ ROUND(F, b, c, d, a, in[11] + K1, 19);
+
+ /* Round 2 */
+ ROUND(G, a, b, c, d, in[ 1] + K2, 3);
+ ROUND(G, d, a, b, c, in[ 3] + K2, 5);
+ ROUND(G, c, d, a, b, in[ 5] + K2, 9);
+ ROUND(G, b, c, d, a, in[ 7] + K2, 13);
+ ROUND(G, a, b, c, d, in[ 9] + K2, 3);
+ ROUND(G, d, a, b, c, in[11] + K2, 5);
+ ROUND(G, c, d, a, b, in[ 0] + K2, 9);
+ ROUND(G, b, c, d, a, in[ 2] + K2, 13);
+ ROUND(G, a, b, c, d, in[ 4] + K2, 3);
+ ROUND(G, d, a, b, c, in[ 6] + K2, 5);
+ ROUND(G, c, d, a, b, in[ 8] + K2, 9);
+ ROUND(G, b, c, d, a, in[10] + K2, 13);
+
+ /* Round 3 */
+ ROUND(H, a, b, c, d, in[ 3] + K3, 3);
+ ROUND(H, d, a, b, c, in[ 7] + K3, 9);
+ ROUND(H, c, d, a, b, in[11] + K3, 11);
+ ROUND(H, b, c, d, a, in[ 2] + K3, 15);
+ ROUND(H, a, b, c, d, in[ 6] + K3, 3);
+ ROUND(H, d, a, b, c, in[10] + K3, 9);
+ ROUND(H, c, d, a, b, in[ 1] + K3, 11);
+ ROUND(H, b, c, d, a, in[ 5] + K3, 15);
+ ROUND(H, a, b, c, d, in[ 9] + K3, 3);
+ ROUND(H, d, a, b, c, in[ 0] + K3, 9);
+ ROUND(H, c, d, a, b, in[ 4] + K3, 11);
+ ROUND(H, b, c, d, a, in[ 8] + K3, 15);
+
+ return buf[1] + b; /* "most hashed" word */
+ /* Alternative: return sum of all words? */
+}
+#endif
+
+#undef ROUND
+#undef F
+#undef G
+#undef H
+#undef K1
+#undef K2
+#undef K3
+
/* This should not be decreased so low that ISNs wrap too fast. */
#define REKEY_INTERVAL 300
#define HASH_BITS 24
@@ -1417,8 +1691,7 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
*/
do_gettimeofday(&tv); /* We need the usecs below... */
- if (!rekey_time ||
- (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
+ if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
rekey_time = tv.tv_sec;
/* First three words are overwritten below. */
get_random_bytes(&secret+3, sizeof(secret)-12);
@@ -1439,13 +1712,13 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
secret[2]=(sport << 16) + dport;
seq = (halfMD4Transform(secret+8, secret) &
- ((1<<HASH_BITS)-1)) + (count << HASH_BITS);
+ ((1<<HASH_BITS)-1)) + count;
/*
* As close as possible to RFC 793, which
- * suggests using a 250kHz clock.
- * Further reading shows this assumes 2Mb/s networks.
- * For 10Mb/s ethernet, a 1MHz clock is appropriate.
+ * suggests using a 250 kHz clock.
+ * Further reading shows this assumes 2 Mb/s networks.
+ * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
* That's funny, Linux has one built in! Use it!
* (Networks are faster now - should this be increased?)
*/
@@ -1463,53 +1736,97 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
* Dan Bernstein and Eric Schenk.
*
* For linux I implement the 1 minute counter by looking at the jiffies clock.
- * The count is passed in as a parameter;
- *
+ * The count is passed in as a parameter, so this code doesn't much care.
*/
-__u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr,
- __u16 sport, __u16 dport, __u32 sseq, __u32 count)
+
+#define COOKIEBITS 24 /* Upper bits store count */
+#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+
+static int syncookie_init = 0;
+static __u32 syncookie_secret[2][16-3+HASH_BUFFER_SIZE];
+
+__u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
+ __u16 dport, __u32 sseq, __u32 count, __u32 data)
{
- static int is_init = 0;
- static __u32 secret[2][16];
- __u32 tmp[16];
- __u32 seq;
+ __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+ __u32 seq;
/*
- * Pick two random secret the first time we open a TCP connection.
+ * Pick two random secrets the first time we need a cookie.
*/
- if (is_init == 0) {
- get_random_bytes(&secret[0], sizeof(secret[0]));
- get_random_bytes(&secret[1], sizeof(secret[1]));
- is_init = 1;
+ if (syncookie_init == 0) {
+ get_random_bytes(syncookie_secret, sizeof(syncookie_secret));
+ syncookie_init = 1;
}
/*
* Compute the secure sequence number.
* The output should be:
- * MD5(sec1,saddr,sport,daddr,dport,sec1) + their sequence number
- * + (count * 2^24)
- * + (MD5(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24).
- * Where count increases every minute by 1.
+ * HASH(sec1,saddr,sport,daddr,dport,sec1) + sseq + (count * 2^24)
+ * + (HASH(sec2,saddr,sport,daddr,dport,count,sec2) % 2^24).
+ * Where sseq is their sequence number and count increases every
+ * minute by 1.
+ * As an extra hack, we add a small "data" value that encodes the
+ * MSS into the second hash value.
*/
- memcpy(tmp, secret[0], sizeof(tmp));
- tmp[8]=saddr;
- tmp[9]=daddr;
- tmp[10]=(sport << 16) + dport;
- HASH_TRANSFORM(tmp, tmp);
- seq = tmp[1];
-
- memcpy(tmp, secret[1], sizeof(tmp));
- tmp[8]=saddr;
- tmp[9]=daddr;
- tmp[10]=(sport << 16) + dport;
- tmp[11]=count; /* minute counter */
- HASH_TRANSFORM(tmp, tmp);
-
- seq += sseq + (count << 24) + (tmp[1] & 0x00ffffff);
+ memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0]));
+ tmp[0]=saddr;
+ tmp[1]=daddr;
+ tmp[2]=(sport << 16) + dport;
+ HASH_TRANSFORM(tmp+16, tmp);
+ seq = tmp[17] + sseq + (count << COOKIEBITS);
+
+ memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1]));
+ tmp[0]=saddr;
+ tmp[1]=daddr;
+ tmp[2]=(sport << 16) + dport;
+ tmp[3] = count; /* minute counter */
+ HASH_TRANSFORM(tmp+16, tmp);
+
+ /* Add in the second hash and the data */
+ return seq + ((tmp[17] + data) & COOKIEMASK);
+}
- /* Zap lower 3 bits to leave room for the MSS representation */
- return (seq & 0xfffff8);
+/*
+ * This retrieves the small "data" value from the syncookie.
+ * If the syncookie is bad, the data returned will be out of
+ * range. This must be checked by the caller.
+ *
+ * The count value used to generate the cookie must be within
+ * "maxdiff" if the current (passed-in) "count". The return value
+ * is (__u32)-1 if this test fails.
+ */
+__u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr, __u16 sport,
+ __u16 dport, __u32 sseq, __u32 count, __u32 maxdiff)
+{
+ __u32 tmp[16 + HASH_BUFFER_SIZE + HASH_EXTRA_SIZE];
+ __u32 diff;
+
+ if (syncookie_init == 0)
+ return (__u32)-1; /* Well, duh! */
+
+ /* Strip away the layers from the cookie */
+ memcpy(tmp+3, syncookie_secret[0], sizeof(syncookie_secret[0]));
+ tmp[0]=saddr;
+ tmp[1]=daddr;
+ tmp[2]=(sport << 16) + dport;
+ HASH_TRANSFORM(tmp+16, tmp);
+ cookie -= tmp[17] + sseq;
+ /* Cookie is now reduced to (count * 2^24) ^ (hash % 2^24) */
+
+ diff = (count - (cookie >> COOKIEBITS)) & ((__u32)-1 >> COOKIEBITS);
+ if (diff >= maxdiff)
+ return (__u32)-1;
+
+ memcpy(tmp+3, syncookie_secret[1], sizeof(syncookie_secret[1]));
+ tmp[0] = saddr;
+ tmp[1] = daddr;
+ tmp[2] = (sport << 16) + dport;
+ tmp[3] = count - diff; /* minute counter */
+ HASH_TRANSFORM(tmp+16, tmp);
+
+ return (cookie - tmp[17]) & COOKIEMASK; /* Leaving the data behind */
}
#endif
@@ -1532,7 +1849,7 @@ static inline unsigned long long get_clock_cnt(void)
{
unsigned long low, high;
__asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high));
- return (((unsigned long long) high << 31) | low);
+ return (((unsigned long long) high << 32) | low);
}
__initfunc(static void
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index cb4e9d498..20e818ce6 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -48,6 +48,9 @@
#if (LINUX_VERSION_CODE > 66304)
#define NEW_MODULES
+#ifdef LOCAL_ROCKET_H /* We're building standalone */
+#define MODULE
+#endif
#endif
#ifdef NEW_MODULES
@@ -81,6 +84,9 @@
#include <linux/ioport.h>
#ifdef ENABLE_PCI
#include <linux/pci.h>
+#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
+#include <linux/bios32.h>
+#endif
#endif
#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
#include <linux/init.h>
@@ -89,12 +95,17 @@
#endif
#include "rocket_int.h"
+#ifdef LOCAL_ROCKET_H
+#include "rocket.h"
+#include "version.h"
+#else
#include <linux/rocket.h>
-
-#define ROCKET_VERSION "1.14a"
-#define ROCKET_DATE "19-Jul-97"
+#define ROCKET_VERSION "1.14b"
+#define ROCKET_DATE "29-Jun-98"
+#endif /* LOCAL_ROCKET_H */
#define ROCKET_PARANOIA_CHECK
+#define ROCKET_SOFT_FLOW
#undef ROCKET_DEBUG_OPEN
#undef ROCKET_DEBUG_INTR
@@ -177,9 +188,30 @@ static unsigned long time_stat_long = 0;
static unsigned long time_counter = 0;
#endif
+#if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
+MODULE_AUTHOR("Theodore Ts'o");
+MODULE_DESCRIPTION("Comtrol Rocketport driver");
+MODULE_PARM(board1, "i");
+MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
+MODULE_PARM(board2, "i");
+MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
+MODULE_PARM(board3, "i");
+MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
+MODULE_PARM(board4, "i");
+MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
+MODULE_PARM(controller, "i");
+MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
+MODULE_PARM(support_low_speed, "i");
+MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud");
+#endif
+
/*
* Provide backwards compatibility for kernels prior to 2.1.8.
*/
+#if (LINUX_VERSION_CODE < 0x20000)
+typedef dev_t kdev_t;
+#endif
+
#if (LINUX_VERSION_CODE < 131336)
int copy_from_user(void *to, const void *from_user, unsigned long len)
{
@@ -202,6 +234,12 @@ int copy_to_user(void *to_user, const void *from, unsigned long len)
memcpy_tofs(to_user, from, len);
return 0;
}
+
+static inline int signal_pending(struct task_struct *p)
+{
+ return (p->signal & (~p->blocked != 0));
+}
+
#else
#include <asm/uaccess.h>
#endif
@@ -720,6 +758,27 @@ static void configure_r_port(struct r_port *info)
info->intmask |= DELTA_CD;
restore_flags(flags);
}
+
+ /*
+ * Handle software flow control in the board
+ */
+#ifdef ROCKET_SOFT_FLOW
+ if (I_IXON(info->tty)) {
+ sEnTxSoftFlowCtl(cp);
+ if (I_IXANY(info->tty)) {
+ sEnIXANY(cp);
+ } else {
+ sDisIXANY(cp);
+ }
+ sSetTxXONChar(cp, START_CHAR(info->tty));
+ sSetTxXOFFChar(cp, STOP_CHAR(info->tty));
+ } else {
+ sDisTxSoftFlowCtl(cp);
+ sDisIXANY(cp);
+ sClrTxXOFF(cp);
+ }
+#endif
+
/*
* Set up ignore/read mask words
*/
@@ -728,7 +787,7 @@ static void configure_r_port(struct r_port *info)
info->read_status_mask |= STMFRAMEH | STMPARITYH;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= STMBREAKH;
-
+
/*
* Characters to ignore
*/
@@ -751,7 +810,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
{
struct wait_queue wait = { current, NULL };
int retval;
- int do_clocal = 0;
+ int do_clocal = 0, extra_count = 0;
unsigned long flags;
/*
@@ -820,8 +879,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
info->line, info->count);
#endif
save_flags(flags); cli();
- if (!tty_hung_up_p(filp))
+ if (!tty_hung_up_p(filp)) {
+ extra_count = 1;
info->count--;
+ }
restore_flags(flags);
info->blocked_open++;
while (1) {
@@ -857,7 +918,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
cli();
- if (!tty_hung_up_p(filp))
+ if (extra_count)
info->count++;
restore_flags(flags);
info->blocked_open--;
@@ -1315,7 +1376,12 @@ static int set_config(struct r_port * info, struct rocket_config * new_info)
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- if (!capable(CAP_SYS_ADMIN)) {
+#ifdef CAP_SYS_ADMIN
+ if (!capable(CAP_SYS_ADMIN))
+#else
+ if (!suser())
+#endif
+ {
if ((new_serial.flags & ~ROCKET_USR_MASK) !=
(info->flags & ~ROCKET_USR_MASK))
return -EPERM;
@@ -1754,7 +1820,6 @@ static int rp_write(struct tty_struct * tty, int from_user,
save_flags(flags);
while (1) {
- cli();
if (info->tty == 0) {
restore_flags(flags);
goto end;
@@ -1778,10 +1843,10 @@ static int rp_write(struct tty_struct * tty, int from_user,
/* In case we got pre-empted */
if (info->tty == 0)
goto end_intr;
- c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1,
- XMIT_BUF_SIZE - info->xmit_head));
-
}
+ cli();
+ c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1,
+ XMIT_BUF_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, b, c);
info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE-1);
info->xmit_cnt += c;
@@ -1868,6 +1933,35 @@ static void rp_flush_buffer(struct tty_struct *tty)
}
#ifdef ENABLE_PCI
+#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
+/* For compatibility */
+static struct pci_dev *pci_find_slot(char bus, char device_fn)
+{
+ unsigned short vendor_id, device_id;
+ int ret, error;
+ static struct pci_dev ret_struct;
+
+ error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID,
+ &vendor_id);
+ ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID,
+ &device_id);
+ if (error == 0)
+ error = ret;
+
+ if (error) {
+ printk("PCI RocketPort error: %s not initializing due to error"
+ "reading configuration space\n",
+ pcibios_strerror(error));
+ return(0);
+ }
+
+ memset(&ret_struct, 0, sizeof(ret_struct));
+ ret_struct.device = device_id;
+
+ return &ret_struct;
+}
+#endif
+
__initfunc(int register_PCI(int i, char bus, char device_fn))
{
int num_aiops, aiop, max_num_aiops, num_chan, chan;
@@ -1875,8 +1969,23 @@ __initfunc(int register_PCI(int i, char bus, char device_fn))
char *str;
CONTROLLER_t *ctlp;
struct pci_dev *dev = pci_find_slot(bus, device_fn);
+#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
+ int ret;
+ unsigned int port;
+#endif
+ if (!dev)
+ return 0;
+
+#if (LINUX_VERSION_CODE >= 0x020163) /* 2.1.99 */
rcktpt_io_addr[i] = dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+#else
+ ret = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
+ &port);
+ if (ret)
+ return 0;
+ rcktpt_io_addr[i] = port & PCI_BASE_ADDRESS_IO_MASK;
+#endif
switch(dev->device) {
case PCI_DEVICE_ID_RP4QUAD:
str = "Quadcable";
@@ -1902,6 +2011,18 @@ __initfunc(int register_PCI(int i, char bus, char device_fn))
str = "32";
max_num_aiops = 4;
break;
+ case PCI_DEVICE_ID_RPP4:
+ str = "Plus Quadcable";
+ max_num_aiops = 1;
+ break;
+ case PCI_DEVICE_ID_RPP8:
+ str = "Plus Octacable";
+ max_num_aiops = 1;
+ break;
+ case PCI_DEVICE_ID_RP8M:
+ str = "8-port Modem";
+ max_num_aiops = 1;
+ break;
default:
str = "(unknown/unsupported)";
max_num_aiops = 0;
@@ -1936,20 +2057,48 @@ __initfunc(static int init_PCI(int boards_found))
int i, count = 0;
for(i=0; i < (NUM_BOARDS - boards_found); i++) {
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA,
- i, &bus, &device_fn))
+ if (!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn))
+ if (register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if (!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8J, i, &bus, &device_fn))
+ if (register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8OCTA, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8INTF, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP16INTF, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP32INTF, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8J, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF,
- i, &bus, &device_fn))
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RPP4, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF,
- i, &bus, &device_fn))
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RPP8, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF,
- i, &bus, &device_fn))
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8M, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
}
@@ -2073,7 +2222,7 @@ __initfunc(int rp_init(void))
isa_boards_found++;
}
#ifdef ENABLE_PCI
- if (pci_present()) {
+ if (pcibios_present()) {
if(isa_boards_found < NUM_BOARDS)
pci_boards_found = init_PCI(isa_boards_found);
} else {
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 8b2ea2212..604e8733b 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -483,6 +483,18 @@ Call: sDisCTSFlowCtl(ChP)
}
/***************************************************************************
+Function: sDisIXANY
+Purpose: Disable IXANY Software Flow Control
+Call: sDisIXANY(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sDisIXANY(ChP) \
+{ \
+ (ChP)->R[0x0e] = 0x86; \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \
+}
+
+/***************************************************************************
Function: DisParity
Purpose: Disable parity
Call: sDisParity(ChP)
@@ -573,6 +585,18 @@ Call: sEnCTSFlowCtl(ChP)
}
/***************************************************************************
+Function: sEnIXANY
+Purpose: Enable IXANY Software Flow Control
+Call: sEnIXANY(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sEnIXANY(ChP) \
+{ \
+ (ChP)->R[0x0e] = 0x21; \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \
+}
+
+/***************************************************************************
Function: EnParity
Purpose: Enable parity
Call: sEnParity(ChP)
@@ -647,6 +671,18 @@ Call: sEnTransmit(ChP)
}
/***************************************************************************
+Function: sEnTxSoftFlowCtl
+Purpose: Enable Tx Software Flow Control
+Call: sEnTxSoftFlowCtl(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sEnTxSoftFlowCtl(ChP) \
+{ \
+ (ChP)->R[0x06] = 0xc5; \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \
+}
+
+/***************************************************************************
Function: sGetAiopIntStatus
Purpose: Get the AIOP interrupt status
Call: sGetAiopIntStatus(CtlP,AiopNum)
@@ -985,6 +1021,32 @@ Call: sSetStop2(ChP)
}
/***************************************************************************
+Function: sSetTxXOFFChar
+Purpose: Set the Tx XOFF flow control character
+Call: sSetTxXOFFChar(ChP,Ch)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Byte_t Ch; The value to set the Tx XOFF character to
+*/
+#define sSetTxXOFFChar(ChP,CH) \
+{ \
+ (ChP)->R[0x07] = (CH); \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \
+}
+
+/***************************************************************************
+Function: sSetTxXONChar
+Purpose: Set the Tx XON flow control character
+Call: sSetTxXONChar(ChP,Ch)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Byte_t Ch; The value to set the Tx XON character to
+*/
+#define sSetTxXONChar(ChP,CH) \
+{ \
+ (ChP)->R[0x0b] = (CH); \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x08]); \
+}
+
+/***************************************************************************
Function: sStartRxProcessor
Purpose: Start a channel's receive processor
Call: sStartRxProcessor(ChP)
@@ -1133,17 +1195,25 @@ struct r_port {
#undef PCI_DEVICE_ID_RP32INTF
#endif
-#define PCI_VENDOR_ID_RP 0x11fe
-#define PCI_DEVICE_ID_RP32INTF 0x0001
-#define PCI_DEVICE_ID_RP8INTF 0x0002
-#define PCI_DEVICE_ID_RP16INTF 0x0003
-#define PCI_DEVICE_ID_RP8OCTA 0x0005
+#define PCI_VENDOR_ID_RP 0x11fe
+#define PCI_DEVICE_ID_RP32INTF 0x0001
+#define PCI_DEVICE_ID_RP8INTF 0x0002
+#define PCI_DEVICE_ID_RP16INTF 0x0003
+#define PCI_DEVICE_ID_RP8OCTA 0x0005
-#ifndef RP4QUAD
-#define PCI_DEVICE_ID_RP4QUAD 0x0004
+#ifndef PCI_DEVICE_ID_RP4QUAD
+#define PCI_DEVICE_ID_RP4QUAD 0x0004
#endif
-#ifndef RP8J
-#define PCI_DEVICE_ID_RP8J 0x0006
+#ifndef PCI_DEVICE_ID_RP8J
+#define PCI_DEVICE_ID_RP8J 0x0006
#endif
-
+#ifndef PCI_DEVICE_ID_RPP4
+#define PCI_DEVICE_ID_RPP4 0x000A
+#endif
+#ifndef PCI_DEVICE_ID_RPP8
+#define PCI_DEVICE_ID_RPP8 0x000B
+#endif
+#ifndef PCI_DEVICE_ID_RP8M
+#define PCI_DEVICE_ID_RP8M 0x000C
+#endif
diff --git a/drivers/char/rsf16fmi.h b/drivers/char/rsf16fmi.h
new file mode 100644
index 000000000..b71e35bdd
--- /dev/null
+++ b/drivers/char/rsf16fmi.h
@@ -0,0 +1,13 @@
+/* SF16FMI FMRadio include file.
+ * (c) 1998 Petr Vandrovec
+ *
+ * Not in include/linux/ because there's no need for anyone
+ * to know about these details, I reckon.
+ */
+
+#ifndef __RSF16FMI_H
+#define __RSF16FMI_H
+
+int radiosf16fmi_init(void);
+
+#endif /* __RSF16FMI_H */
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index b0c8148b5..b7c117c31 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -135,11 +135,8 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
wake_up_interruptible(&rtc_wait);
- if (rtc_status & RTC_TIMER_ON) {
- del_timer(&rtc_irq_timer);
- rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
- add_timer(&rtc_irq_timer);
- }
+ if (rtc_status & RTC_TIMER_ON)
+ mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
}
/*
@@ -597,9 +594,7 @@ void rtc_dropped_irq(unsigned long data)
unsigned long flags;
printk(KERN_INFO "rtc: lost some interrupts at %ldHz.\n", rtc_freq);
- del_timer(&rtc_irq_timer);
- rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
- add_timer(&rtc_irq_timer);
+ mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
save_flags(flags);
cli();
diff --git a/drivers/char/rtrack.c b/drivers/char/rtrack.c
deleted file mode 100644
index efe01046a..000000000
--- a/drivers/char/rtrack.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/* radiotrack (radioreveal) driver for Linux radio support
- * (c) 1997 M. Kirkwood
- */
-/* TODO: Allow for more than one of these foolish entities :-) */
-
-/* Notes on the hardware (reverse engineered from other peoples'
- * reverse engineering of AIMS' code :-)
- *
- * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
- *
- * The signal strength query is unsurprisingly inaccurate. And it seems
- * to indicate that (on my card, at least) the frequency setting isn't
- * too great. (I have to tune up .025MHz from what the freq should be
- * to get a report that the thing is tuned.)
- *
- * Volume control is (ugh) analogue:
- * out(port, start_increasing_volume);
- * wait(a_wee_while);
- * out(port, stop_changing_the_volume);
- *
- */
-
-#include <linux/config.h>
-#include <linux/radio.h>
-#include <linux/ioport.h>
-
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "rtrack.h"
-
-/* Let's just be a bit careful here, shall we? */
-#if (CONFIG_RADIO_RTRACK_PORT != 0x20f) && (CONFIG_RADIO_RTRACK_PORT != 0x30f)
-#error Invalid port specified for RadioTrack
-#endif
-
-/* local prototypes */
-void outbits(int bits, int data, int port);
-void decvol(int port);
-void incvol(int port);
-void mute(int port);
-void unmute(int port);
-
-/* public structurey-type things */
-int rt_port = CONFIG_RADIO_RTRACK_PORT;
-
-struct radio_cap rt_cap = {
- 0, /* device index (not dealt with here) */
- RADIO_TYPE_RTRACK, /* type */
- 1, /* number of bandwidths */
- 0, 10 /* volmin, volmax */
-};
-
-/* we only get one band/protocol with radiotrack */
-struct radio_band rt_band = {
- 0, /* device index */
- 0, /* bandwidth "index" */
- RADIO_PROTOCOL_FM,
- RADIO_BAND_FM_STD,
- RADIO_FM_FRTOINT(88.0), /* freq range */
- RADIO_FM_FRTOINT(108.0),
- 0,1 /* sig strength range */
-};
-
-/* p'raps these should become struct radio_ops and struct radio_status? */
-struct radio_device rt_dev = {
- &rt_cap,
- &rt_band,
- &rt_setvol,
- 0, /* curvol */
- &rt_setband,
- 0, /* curband */
- &rt_setfreq,
- 0, /* curfreq */
- &rt_getsigstr,
- NULL, /* next (to be filled in later) */
- &rt_port /* misc */
-};
-
-
-void radiotrack_init()
-{
-int dev_num, i;
-
-/* XXX - probe here?? - XXX */
-
-/* try to grab the i/o port */
- if(check_region(rt_port,2)) {
- printk("rtrack.c: port 0x%x already used\n", rt_port);
- return;
- }
-
- request_region(rt_port,2,"rtrack");
-
- dev_num = radio_add_device(&rt_dev);
-/* initialise the card */
- /* set the volume very low */
- for(i=rt_cap.volmax; i>rt_cap.volmin; i--)
- decvol(rt_port);
- rt_dev.curvol = rt_cap.volmin;
-}
-
-
-int rt_setvol(struct radio_device *dev, int vol)
-{
-int port, i;
-
- if(vol == dev->curvol)
- return 0;
-
- port = *(int*)(dev->misc);
- if(vol == 0)
- mute(port);
-
- if(vol > dev->curvol)
- for(i = dev->curvol; i < vol; i++)
- incvol(port);
- else
- for(i = dev->curvol; i > vol; i--)
- decvol(port);
-
- if(dev->curvol == 0)
- unmute(port);
-
- return 0;
-}
-
-
-int rt_setband(struct radio_device *dev, int band)
-{
-/* we know in advance that we only have one band, and
- * the wrapper checks the validity of all the inputs
- */
- return 0;
-}
-
-int rt_setfreq(struct radio_device *dev, int freq)
-{
-int myport = *(int*)(dev->misc);
-
- outbits(16, RTRACK_ENCODE(freq), myport);
- outbits(8, 0xa0, myport);
-/* XXX - get rid of this once setvol is implemented properly - XXX */
-/* these insist on turning the thing on. not sure I approve... */
- udelay(1000);
- outb(0, myport);
- outb(0xc8, myport);
-
- return 0;
-}
-
-int rt_getsigstr(struct radio_device *dev)
-{
-int res;
-int myport = *(int*)(dev->misc);
-
- outb(0xf8, myport);
- udelay(200000);
- res = (int)inb(myport);
- udelay(10000);
- outb(0xe8, myport);
- if(res == 0xfd)
- return 1;
- else
- return 0;
-}
-
-
-/* local things */
-void outbits(int bits, int data, int port)
-{
- while(bits--) {
- if(data & 1) {
- outw(5, port);
- outw(5, port);
- outw(7, port);
- outw(7, port);
- } else {
- outw(1, port);
- outw(1, port);
- outw(3, port);
- outw(3, port);
- }
- data>>=1;
- }
-}
-
-void decvol(int port)
-{
- outb(0x48, port);
- udelay(100000);
- outb(0xc8, port);
-}
-
-void incvol(int port)
-{
- outb(0x88, port);
- udelay(100000);
- outb(0xc8, port);
-}
-
-void mute(int port)
-{
- outb(0, port);
- outb(0xc0, port);
-}
-
-void unmute(int port)
-{
- outb(0, port);
- outb(0xc8, port);
-}
diff --git a/drivers/char/rtrack.h b/drivers/char/rtrack.h
deleted file mode 100644
index b5a9bc124..000000000
--- a/drivers/char/rtrack.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* RadioTrack (RadioReveal) include file.
- * (c) 1997 M. Kirkwood
- *
- * Not in include/linux/ because there's no need for anyone
- * to know about these details, I reckon.
- */
-
-#ifndef __RTRACK_H
-#define __RTRACK_H
-
-#include <linux/radio.h>
-
-void radiotrack_init(void);
-int rt_setvol(struct radio_device *dev, int vol);
-int rt_setband(struct radio_device *dev, int vol);
-int rt_setfreq(struct radio_device *dev, int vol);
-int rt_getsigstr(struct radio_device *dev);
-
-/* frequency encoding stuff... */
-/* we have to careful not to introduce fp stuff here */
-#define RTRACK_ENCODE(x) (((((x)*2)/5)-(40*88))+0xf6c)
-#define RTRACK_DECODE(x) (((((x)-0xf6c)+(40*88))*5)/2)
-/* we shouldn't actually need the decode macro (or the excessive bracketing :-) */
-
-#endif /* __RTRACK_H */
diff --git a/drivers/char/saa5249.c b/drivers/char/saa5249.c
new file mode 100644
index 000000000..252fcabbe
--- /dev/null
+++ b/drivers/char/saa5249.c
@@ -0,0 +1,707 @@
+/*
+ * Cleaned up to use existing videodev interface and allow the idea
+ * of multiple teletext decoders on the video4linux iface. Changed i2c
+ * to cover addressing clashes on device busses. It's also rebuilt so
+ * you can add arbitary multiple teletext devices to Linux video4linux
+ * now (well 32 anyway).
+ *
+ * Alan Cox <Alan.Cox@linux.org>
+ *
+ * The original driver was heavily modified to match the i2c interface
+ * It was truncated to use the WinTV boards, too.
+ *
+ * Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
+ *
+ * $Id: saa5249.c,v 1.1 1998/03/30 22:23:23 alan Exp $
+ *
+ * Derived From
+ *
+ * vtx.c:
+ * This is a loadable character-device-driver for videotext-interfaces
+ * (aka teletext). Please check the Makefile/README for a list of supported
+ * interfaces.
+ *
+ * Copyright (c) 1994-97 Martin Buck <martin-2.buck@student.uni-ulm.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <stdarg.h>
+#include <linux/i2c.h>
+#include <linux/videotext.h>
+#include <linux/videodev.h>
+
+#define VTX_VER_MAJ 1
+#define VTX_VER_MIN 7
+
+
+
+#define NUM_DAUS 4
+#define NUM_BUFS 8
+#define IF_NAME "SAA5249"
+
+static const int disp_modes[8][3] =
+{
+ { 0x46, 0x03, 0x03 }, /* DISPOFF */
+ { 0x46, 0xcc, 0xcc }, /* DISPNORM */
+ { 0x44, 0x0f, 0x0f }, /* DISPTRANS */
+ { 0x46, 0xcc, 0x46 }, /* DISPINS */
+ { 0x44, 0x03, 0x03 }, /* DISPOFF, interlaced */
+ { 0x44, 0xcc, 0xcc }, /* DISPNORM, interlaced */
+ { 0x44, 0x0f, 0x0f }, /* DISPTRANS, interlaced */
+ { 0x44, 0xcc, 0x46 } /* DISPINS, interlaced */
+};
+
+
+
+#define PAGE_WAIT 30 /* Time in jiffies between requesting page and */
+ /* checking status bits */
+#define PGBUF_EXPIRE 1500 /* Time in jiffies to wait before retransmitting */
+ /* page regardless of infobits */
+typedef struct {
+ u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */
+ u8 laststat[10]; /* Last value of infobits for DAU */
+ u8 sregs[7]; /* Page-request registers */
+ unsigned long expire; /* Time when page will be expired */
+ unsigned clrfound : 1; /* VTXIOCCLRFOUND has been called */
+ unsigned stopped : 1; /* VTXIOCSTOPDAU has been called */
+} vdau_t;
+
+struct saa5249_device
+{
+ vdau_t vdau[NUM_DAUS]; /* Data for virtual DAUs (the 5249 only has one */
+ /* real DAU, so we have to simulate some more) */
+ int vtx_use_count;
+ int is_searching[NUM_DAUS];
+ int disp_mode;
+ int virtual_mode;
+ struct i2c_bus *bus;
+};
+
+
+#define CCTWR 34 /* I²C write/read-address of vtx-chip */
+#define CCTRD 35
+#define NOACK_REPEAT 10 /* Retry access this many times on failure */
+#define CLEAR_DELAY 5 /* Time in jiffies required to clear a page */
+#define I2C_TIMEOUT 300 /* open/close/SDA-check timeout in jiffies */
+#define READY_TIMEOUT 3 /* Time in jiffies to wait for ready signal of I²C-bus interface */
+#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */
+#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */
+
+#define VTX_DEV_MINOR 0
+
+/* General defines and debugging support */
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define RESCHED \
+ do { \
+ if (current->need_resched) \
+ schedule(); \
+ } while (0)
+
+static struct video_device saa_template; /* Declared near bottom */
+
+/*
+ * We do most of the hard work when we become a device on the i2c.
+ */
+
+static int saa5249_attach(struct i2c_device *device)
+{
+ int pgbuf;
+ int err;
+ struct video_device *vd;
+ struct saa5249_device *t;
+ /* Only attach these chips to the BT848 bus for now */
+
+ if(device->bus->id!=I2C_BUSID_BT848)
+ return -EINVAL;
+
+ printk(KERN_DEBUG "saa5249_attach: bus %p\n", device->bus);
+ strcpy(device->name, IF_NAME);
+
+ /*
+ * Now create a video4linux device
+ */
+
+ vd=(struct video_device *)kmalloc(sizeof(struct video_device), GFP_KERNEL);
+ if(vd==NULL)
+ return -ENOMEM;
+
+ memcpy(vd, &saa_template, sizeof(*vd));
+
+ /*
+ * Attach an saa5249 device
+ */
+
+ t=(struct saa5249_device *)kmalloc(sizeof(struct saa5249_device), GFP_KERNEL);
+ if(t==NULL)
+ {
+ kfree(vd);
+ return -ENOMEM;
+ }
+ for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
+ {
+ memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+ memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
+ memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
+ t->vdau[pgbuf].expire = 0;
+ t->vdau[pgbuf].clrfound = TRUE;
+ t->vdau[pgbuf].stopped = TRUE;
+ t->is_searching[pgbuf] = FALSE;
+ }
+ vd->priv=t;
+ device->data=vd;
+
+ /*
+ * Register it
+ */
+
+ if((err=video_register_device(vd, VFL_TYPE_VTX))<0)
+ {
+ kfree(t);
+ kfree(vd);
+ return err;
+ }
+ t->bus = device->bus;
+ return 0;
+}
+
+static int saa5249_detach(struct i2c_device *device)
+{
+ struct video_device *vd=device->data;
+ printk(KERN_DEBUG "saa5249_detach\n");
+ video_unregister_device(vd);
+ kfree(vd->priv);
+ kfree(vd);
+ return 0;
+}
+
+static int saa5249_command(struct i2c_device *device,
+ unsigned int cmd, void *arg)
+{
+ printk(KERN_DEBUG "saa5249_command\n");
+ return -EINVAL;
+}
+
+/* new I2C driver support */
+
+static struct i2c_driver i2c_driver_videotext =
+{
+ IF_NAME, /* name */
+ I2C_DRIVERID_VIDEOTEXT, /* in i2c.h */
+ 34, 35, /* Addr range */
+ saa5249_attach,
+ saa5249_detach,
+ saa5249_command
+};
+
+/*
+ * Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
+ * delay may be longer.
+ */
+
+static void jdelay(unsigned long delay)
+{
+ sigset_t oldblocked = current->blocked;
+
+ spin_lock_irq(&current->sigmask_lock);
+ sigfillset(&current->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + delay;
+ schedule();
+
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = oldblocked;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+}
+
+
+/* Send arbitrary number of bytes to I²C-bus. Start & stop handshaking is done by this routine.
+ * adr should be address of I²C-device, varargs-list of values to send must be terminated by -1
+ * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
+ */
+
+static int i2c_senddata(struct saa5249_device *t, int adr, ...)
+{
+ int val, loop;
+ va_list argp;
+
+ for (loop = 0; loop <= NOACK_REPEAT; loop++)
+ {
+ i2c_start(t->bus);
+ if (i2c_sendbyte(t->bus, adr, 0) != 0)
+ goto loopend;
+
+ va_start(argp, adr);
+ while ((val = va_arg(argp, int)) != -1)
+ {
+ if (val < 0 || val > 255)
+ {
+ printk(KERN_ERR "vtx: internal error in i2c_senddata\n");
+ break;
+ }
+ if (i2c_sendbyte(t->bus, val, 0) != 0)
+ goto loopend;
+ }
+ va_end(argp);
+ i2c_stop(t->bus);
+ return 0;
+loopend:
+ i2c_stop(t->bus);
+ }
+ va_end(argp);
+ return -1;
+}
+
+
+/* Send count number of bytes from buffer buf to I²C-device adr. Start & stop handshaking is
+ * done by this routine. If uaccess is TRUE, data is read from user-space with get_user.
+ * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
+ */
+
+static int i2c_sendbuf(struct saa5249_device *t, int adr, int reg, int count, u8 *buf, int uaccess)
+{
+ int pos, loop;
+ u8 val;
+
+ for (loop = 0; loop <= NOACK_REPEAT; loop++)
+ {
+ i2c_start(t->bus);
+ if (i2c_sendbyte(t->bus, adr, 0) != 0 || i2c_sendbyte(t->bus, reg, 0) != 0)
+ goto loopend;
+ for (pos = 0; pos < count; pos++)
+ {
+ /* FIXME: FAULT WITH CLI/SPINLOCK ?? */
+ if (uaccess)
+ get_user(val, buf + pos);
+ else
+ val = buf[pos];
+ if (i2c_sendbyte(t->bus, val, 0) != 0)
+ goto loopend;
+ RESCHED;
+ }
+ i2c_stop(t->bus);
+ return 0;
+loopend:
+ i2c_stop(t->bus);
+ }
+ return -1;
+}
+
+
+/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
+ * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
+ * sending of data. If uaccess is TRUE, data is written to user-space with put_user.
+ * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
+ */
+
+static int i2c_getdata(struct saa5249_device *t, int adr, int count, u8 *buf, int uaccess)
+{
+ int pos, loop, val;
+
+ for (loop = 0; loop <= NOACK_REPEAT; loop++)
+ {
+ i2c_start(t->bus);
+ if (i2c_sendbyte(t->bus, adr, 1) != 0)
+ goto loopend;
+ for (pos = 0; pos < count; pos++)
+ {
+ val = i2c_readbyte(t->bus, (pos==count-1) ? 1 : 0);
+ if (uaccess)
+ put_user(val, buf + pos);
+ else
+ buf[pos] = val;
+ RESCHED;
+ }
+ i2c_stop(t->bus);
+ return 0;
+loopend:
+ i2c_stop(t->bus);
+ }
+ return -1;
+}
+
+
+/*
+ * Standard character-device-driver functions
+ */
+
+static int saa5249_ioctl(struct video_device *vd, unsigned int cmd, void *arg)
+{
+ struct saa5249_device *t=vd->priv;
+ static int virtual_mode = FALSE;
+
+ switch(cmd)
+ {
+ case VTXIOCGETINFO:
+ {
+ vtx_info_t info;
+ info.version_major = VTX_VER_MAJ;
+ info.version_minor = VTX_VER_MIN;
+ info.numpages = NUM_DAUS;
+ /*info.cct_type = CCT_TYPE;*/
+ if(copy_to_user((void*)arg, &info, sizeof(vtx_info_t)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case VTXIOCCLRPAGE:
+ {
+ vtx_pagereq_t req;
+
+ if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
+ return -EFAULT;
+ if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
+ return -EINVAL;
+ memset(t->vdau[req.pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+ t->vdau[req.pgbuf].clrfound = TRUE;
+ return 0;
+ }
+
+ case VTXIOCCLRFOUND:
+ {
+ vtx_pagereq_t req;
+
+ if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
+ return -EFAULT;
+ if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
+ return -EINVAL;
+ t->vdau[req.pgbuf].clrfound = TRUE;
+ return 0;
+ }
+
+ case VTXIOCPAGEREQ:
+ {
+ vtx_pagereq_t req;
+ if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
+ return -EFAULT;
+ if (!(req.pagemask & PGMASK_PAGE))
+ req.page = 0;
+ if (!(req.pagemask & PGMASK_HOUR))
+ req.hour = 0;
+ if (!(req.pagemask & PGMASK_MINUTE))
+ req.minute = 0;
+ if (req.page < 0 || req.page > 0x8ff) /* 7FF ?? */
+ return -EINVAL;
+ req.page &= 0x7ff;
+ if (req.hour < 0 || req.hour > 0x3f || req.minute < 0 || req.minute > 0x7f ||
+ req.pagemask < 0 || req.pagemask >= PGMASK_MAX || req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
+ return -EINVAL;
+ t->vdau[req.pgbuf].sregs[0] = (req.pagemask & PG_HUND ? 0x10 : 0) | (req.page / 0x100);
+ t->vdau[req.pgbuf].sregs[1] = (req.pagemask & PG_TEN ? 0x10 : 0) | ((req.page / 0x10) & 0xf);
+ t->vdau[req.pgbuf].sregs[2] = (req.pagemask & PG_UNIT ? 0x10 : 0) | (req.page & 0xf);
+ t->vdau[req.pgbuf].sregs[3] = (req.pagemask & HR_TEN ? 0x10 : 0) | (req.hour / 0x10);
+ t->vdau[req.pgbuf].sregs[4] = (req.pagemask & HR_UNIT ? 0x10 : 0) | (req.hour & 0xf);
+ t->vdau[req.pgbuf].sregs[5] = (req.pagemask & MIN_TEN ? 0x10 : 0) | (req.minute / 0x10);
+ t->vdau[req.pgbuf].sregs[6] = (req.pagemask & MIN_UNIT ? 0x10 : 0) | (req.minute & 0xf);
+ t->vdau[req.pgbuf].stopped = FALSE;
+ t->vdau[req.pgbuf].clrfound = TRUE;
+ t->is_searching[req.pgbuf] = TRUE;
+ return 0;
+ }
+
+ case VTXIOCGETSTAT:
+ {
+ vtx_pagereq_t req;
+ u8 infobits[10];
+ vtx_pageinfo_t info;
+ int a;
+
+ if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
+ return -EFAULT;
+ if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
+ return -EINVAL;
+ if (!t->vdau[req.pgbuf].stopped)
+ {
+ if (i2c_senddata(t, CCTWR, 2, 0, -1) ||
+ i2c_sendbuf(t, CCTWR, 3, sizeof(t->vdau[0].sregs), t->vdau[req.pgbuf].sregs, FALSE) ||
+ i2c_senddata(t, CCTWR, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
+ i2c_senddata(t, CCTWR, 2, 0, t->vdau[req.pgbuf].sregs[0] | 8, -1) ||
+ i2c_senddata(t, CCTWR, 8, 0, 25, 0, -1))
+ return -EIO;
+ jdelay(PAGE_WAIT);
+ if (i2c_getdata(t, CCTRD, 10, infobits, FALSE))
+ return -EIO;
+
+ 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))
+ { /* 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))
+ return -EIO;
+ t->vdau[req.pgbuf].expire = jiffies + PGBUF_EXPIRE;
+ memset(t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
+ if (t->virtual_mode)
+ {
+ /* Packet X/24 */
+ if (i2c_senddata(t, CCTWR, 8, 0, 0x20, 0, -1) ||
+ i2c_getdata(t, CCTRD, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40, FALSE))
+ return -EIO;
+ /* Packet X/27/0 */
+ if (i2c_senddata(t, CCTWR, 8, 0, 0x21, 0, -1) ||
+ i2c_getdata(t, CCTRD, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40, FALSE))
+ return -EIO;
+ /* Packet 8/30/0...8/30/15
+ * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
+ * so we should undo this here.
+ */
+ if (i2c_senddata(t, CCTWR, 8, 0, 0x22, 0, -1) ||
+ i2c_getdata(t, CCTRD, 40, t->vdau[req.pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40, FALSE))
+ return -EIO;
+ }
+ t->vdau[req.pgbuf].clrfound = FALSE;
+ memcpy(t->vdau[req.pgbuf].laststat, infobits, sizeof(infobits));
+ }
+ else
+ {
+ memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits));
+ }
+ }
+ else
+ {
+ memcpy(infobits, t->vdau[req.pgbuf].laststat, sizeof(infobits));
+ }
+
+ info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
+ if (info.pagenum < 0x100)
+ info.pagenum += 0x800;
+ info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
+ info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
+ info.charset = ((infobits[7] >> 1) & 7);
+ info.delete = !!(infobits[3] & 8);
+ info.headline = !!(infobits[5] & 4);
+ info.subtitle = !!(infobits[5] & 8);
+ info.supp_header = !!(infobits[6] & 1);
+ info.update = !!(infobits[6] & 2);
+ info.inter_seq = !!(infobits[6] & 4);
+ info.dis_disp = !!(infobits[6] & 8);
+ info.serial = !!(infobits[7] & 1);
+ info.notfound = !!(infobits[8] & 0x10);
+ info.pblf = !!(infobits[9] & 0x20);
+ info.hamming = 0;
+ for (a = 0; a <= 7; a++)
+ {
+ if (infobits[a] & 0xf0)
+ {
+ info.hamming = 1;
+ break;
+ }
+ }
+ if (t->vdau[req.pgbuf].clrfound)
+ info.notfound = 1;
+ if(copy_to_user(req.buffer, &info, sizeof(vtx_pageinfo_t)))
+ return -EFAULT;
+ if (!info.hamming && !info.notfound)
+ {
+ t->is_searching[req.pgbuf] = FALSE;
+ }
+ return 0;
+ }
+
+ case VTXIOCGETPAGE:
+ {
+ vtx_pagereq_t req;
+ int start, end;
+
+ if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
+ return -EFAULT;
+ if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS || req.start < 0 ||
+ req.start > req.end || req.end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
+ return -EINVAL;
+ if(copy_to_user(req.buffer, &t->vdau[req.pgbuf].pgbuf[req.start], req.end - req.start + 1))
+ return -EFAULT;
+
+ /*
+ * Always read the time directly from SAA5249
+ */
+
+ if (req.start <= 39 && req.end >= 32)
+ {
+ start = MAX(req.start, 32);
+ end = MIN(req.end, 39);
+ if (i2c_senddata(t, CCTWR, 8, 0, 0, start, -1) ||
+ i2c_getdata(t, CCTRD, end - start + 1, req.buffer + start - req.start, TRUE))
+ return -EIO;
+ }
+ /* Insert the current header if DAU is still searching for a page */
+ if (req.start <= 31 && req.end >= 7 && t->is_searching[req.pgbuf])
+ {
+ start = MAX(req.start, 7);
+ end = MIN(req.end, 31);
+ if (i2c_senddata(t, CCTWR, 8, 0, 0, start, -1) ||
+ i2c_getdata(t, CCTRD, end - start + 1, req.buffer + start - req.start, TRUE))
+ return -EIO;
+ }
+ return 0;
+ }
+
+ case VTXIOCSTOPDAU:
+ {
+ vtx_pagereq_t req;
+
+ if(copy_from_user(&req, (void*)arg, sizeof(vtx_pagereq_t)))
+ return -EFAULT;
+ if (req.pgbuf < 0 || req.pgbuf >= NUM_DAUS)
+ return -EINVAL;
+ t->vdau[req.pgbuf].stopped = TRUE;
+ t->is_searching[req.pgbuf] = FALSE;
+ return 0;
+ }
+
+ case VTXIOCPUTPAGE:
+ case VTXIOCSETDISP:
+ case VTXIOCPUTSTAT:
+ return 0;
+
+ case VTXIOCCLRCACHE:
+ {
+ if (i2c_senddata(t ,CCTWR, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, CCTWR, 11,
+ ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
+ ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', -1))
+ return -EIO;
+ if (i2c_senddata(t, CCTWR, 3, 0x20, -1))
+ return -EIO;
+ jdelay(10 * CLEAR_DELAY); /* I have no idea how long we have to wait here */
+ return 0;
+ }
+
+ case VTXIOCSETVIRT:
+ {
+ /* The SAA5249 has virtual-row reception turned on always */
+ t->virtual_mode = (int)arg;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+
+static int saa5249_open(struct video_device *vd, int nb)
+{
+ struct saa5249_device *t=vd->priv;
+ int pgbuf;
+
+ printk("t=%p\n",t);
+ if (t->bus==NULL)
+ return -ENODEV;
+
+ printk("Do i2c %p\n",t->bus);
+ if (i2c_senddata(t, CCTWR, 0, 0, -1) || /* Select R11 */
+ /* Turn off parity checks (we do this ourselves) */
+ i2c_senddata(t, CCTWR, 1, disp_modes[t->disp_mode][0], 0, -1) ||
+ /* Display TV-picture, no virtual rows */
+ i2c_senddata(t, CCTWR, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */
+
+ {
+ return -EIO;
+ }
+
+ printk("clean\n");
+ for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++)
+ {
+ memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
+ memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
+ memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
+ t->vdau[pgbuf].expire = 0;
+ t->vdau[pgbuf].clrfound = TRUE;
+ t->vdau[pgbuf].stopped = TRUE;
+ t->is_searching[pgbuf] = FALSE;
+ }
+ t->virtual_mode=FALSE;
+ printk("Go\n");
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+
+
+static void saa5249_release(struct video_device *vd)
+{
+ struct saa5249_device *t=vd->priv;
+ i2c_senddata(t, CCTWR, 1, 0x20, -1); /* Turn off CCT */
+ i2c_senddata(t, CCTWR, 5, 3, 3, -1); /* Turn off TV-display */
+ MOD_DEC_USE_COUNT;
+ return;
+}
+
+static long saa5249_write(struct video_device *v, const char *buf, unsigned long l, int nb)
+{
+ return -EINVAL;
+}
+
+static long saa5249_read(struct video_device *v, char *buf, unsigned long l, int nb)
+{
+ return -EINVAL;
+}
+
+static struct video_device saa_template=
+{
+ IF_NAME,
+ VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */
+ VID_HARDWARE_SAA5249,
+ saa5249_open,
+ saa5249_release,
+ saa5249_read,
+ saa5249_write,
+ saa5249_ioctl,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0
+};
+
+/*
+ * Routines for loadable modules
+ */
+
+int init_module(void)
+{
+ printk(KERN_INFO "SAA5249 driver (" IF_NAME " interface) for VideoText version %d.%d\n",
+ VTX_VER_MAJ, VTX_VER_MIN);
+ i2c_register_driver(&i2c_driver_videotext);
+ return 0;
+}
+
+
+void cleanup_module(void)
+{
+ i2c_unregister_driver(&i2c_driver_videotext);
+}
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 0a326a55d..3910d0e30 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -22,6 +22,7 @@
#include <linux/vt_kern.h>
#include <linux/consolemap.h>
+#include <linux/console_struct.h>
#include <linux/selection.h>
#ifndef MIN
@@ -41,8 +42,6 @@ static int sel_end;
static int sel_buffer_lth = 0;
static char *sel_buffer = NULL;
-#define sel_pos(n) inverse_translate(scrw2glyph(screen_word(sel_cons, n, 1)))
-
/* clear_selection, highlight and highlight_pointer can be called
from interrupt (via scrollback/front) */
@@ -58,6 +57,12 @@ highlight_pointer(const int where) {
complement_pos(sel_cons, where);
}
+static unsigned char
+sel_pos(int n)
+{
+ return inverse_translate(vc_cons[sel_cons].d, screen_glyph(sel_cons, n));
+}
+
/* remove the current selection highlight, if any,
from the console holding the selection. */
void
@@ -91,12 +96,11 @@ static inline int inword(const unsigned char c) {
/* set inwordLut contents. Invoked by ioctl(). */
int sel_loadlut(const unsigned long arg)
{
- int err;
+ int err = -EFAULT;
- err = copy_from_user(inwordLut, (u32 *)(arg+4), 32);
- if (err)
- return -EFAULT;
- return 0;
+ if (!copy_from_user(inwordLut, (u32 *)(arg+4), 32))
+ err = 0;
+ return err;
}
/* does screen address p correspond to character at LH/RH edge of screen? */
@@ -108,10 +112,7 @@ static inline int atedge(const int p, int size_row)
/* constrain v such that v <= u */
static inline unsigned short limit(const unsigned short v, const unsigned short u)
{
-/* gcc miscompiles the ?: operator, so don't use it.. */
- if (v > u)
- return u;
- return v;
+ return (v > u) ? u : v;
}
/* set the current selection. Invoked by ioctl() or by kernel code. */
@@ -120,15 +121,11 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
int sel_mode, new_sel_start, new_sel_end, spc;
char *bp, *obp;
int i, ps, pe;
- unsigned long num_lines, num_columns, size_row;
+ unsigned int currcons = fg_console;
do_unblank_screen();
poke_blanked_console();
- num_lines = get_video_num_lines(fg_console);
- num_columns = get_video_num_columns(fg_console);
- size_row = get_video_size_row(fg_console);
-
{ unsigned short *args, xs, ys, xe, ye;
args = (unsigned short *)(arg + 1);
@@ -150,12 +147,12 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
sel_mode = *args;
}
xs--; ys--; xe--; ye--;
- xs = limit(xs, num_columns - 1);
- ys = limit(ys, num_lines - 1);
- xe = limit(xe, num_columns - 1);
- ye = limit(ye, num_lines - 1);
- ps = ys * size_row + (xs << 1);
- pe = ye * size_row + (xe << 1);
+ xs = limit(xs, video_num_columns - 1);
+ ys = limit(ys, video_num_lines - 1);
+ xe = limit(xe, video_num_columns - 1);
+ ye = limit(ye, video_num_lines - 1);
+ ps = ys * video_size_row + (xs << 1);
+ pe = ye * video_size_row + (xe << 1);
if (sel_mode == 4) {
/* useful for screendump without selection highlights */
@@ -195,7 +192,7 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
(!spc && !inword(sel_pos(ps))))
break;
new_sel_start = ps;
- if (!(ps % size_row))
+ if (!(ps % video_size_row))
break;
}
spc = isspace(sel_pos(pe));
@@ -205,14 +202,14 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
(!spc && !inword(sel_pos(pe))))
break;
new_sel_end = pe;
- if (!((pe + 2) % size_row))
+ if (!((pe + 2) % video_size_row))
break;
}
break;
case 2: /* line-by-line selection */
- new_sel_start = ps - ps % size_row;
- new_sel_end = pe + size_row
- - pe % size_row - 2;
+ new_sel_start = ps - ps % video_size_row;
+ new_sel_end = pe + video_size_row
+ - pe % video_size_row - 2;
break;
case 3:
highlight_pointer(pe);
@@ -226,9 +223,11 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
- !atedge(new_sel_end, size_row) && isspace(sel_pos(new_sel_end))) {
+ !atedge(new_sel_end, video_size_row) &&
+ isspace(sel_pos(new_sel_end))) {
for (pe = new_sel_end + 2; ; pe += 2)
- if (!isspace(sel_pos(pe)) || atedge(pe, size_row))
+ if (!isspace(sel_pos(pe)) ||
+ atedge(pe, video_size_row))
break;
if (isspace(sel_pos(pe)))
new_sel_end = pe;
@@ -259,21 +258,23 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
sel_start = new_sel_start;
sel_end = new_sel_end;
- if (sel_buffer)
- kfree(sel_buffer);
- sel_buffer = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
- if (!sel_buffer) {
- printk("selection: kmalloc() failed\n");
+ /* Allocate a new buffer before freeing the old one ... */
+ bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
+ if (!bp) {
+ printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection();
return -ENOMEM;
}
+ if (sel_buffer)
+ kfree(sel_buffer);
+ sel_buffer = bp;
- obp = bp = sel_buffer;
+ obp = bp;
for (i = sel_start; i <= sel_end; i += 2) {
*bp = sel_pos(i);
if (!isspace(*bp++))
obp = bp;
- if (! ((i + 2) % size_row)) {
+ if (! ((i + 2) % video_size_row)) {
/* strip trailing blanks from line and add newline,
unless non-space at end of line. */
if (obp != bp) {
@@ -287,31 +288,29 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user)
return 0;
}
-/* Insert the contents of the selection buffer into the queue of the
- tty associated with the current console. Invoked by ioctl(). */
+/* Insert the contents of the selection buffer into the
+ * queue of the tty associated with the current console.
+ * Invoked by ioctl().
+ */
int paste_selection(struct tty_struct *tty)
{
- struct wait_queue wait = { current, NULL };
- char *bp = sel_buffer;
- int c = sel_buffer_lth;
- int l;
struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
+ int pasted = 0, count;
+ struct wait_queue wait = { current, NULL };
- if (!bp || !c)
- return 0;
poke_blanked_console();
add_wait_queue(&vt->paste_wait, &wait);
- do {
+ while (sel_buffer && sel_buffer_lth > pasted) {
current->state = TASK_INTERRUPTIBLE;
if (test_bit(TTY_THROTTLED, &tty->flags)) {
schedule();
continue;
}
- l = MIN(c, tty->ldisc.receive_room(tty));
- tty->ldisc.receive_buf(tty, bp, 0, l);
- c -= l;
- bp += l;
- } while (c);
+ count = sel_buffer_lth - pasted;
+ count = MIN(count, tty->ldisc.receive_room(tty));
+ tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
+ pasted += count;
+ }
remove_wait_queue(&vt->paste_wait, &wait);
current->state = TASK_RUNNING;
return 0;
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index b5e41a2d2..c25e24057 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -64,7 +64,7 @@
* ever possible.
*/
-#define SERIAL_PARANOIA_CHECK
+#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
@@ -156,7 +156,7 @@
#endif
static char *serial_name = "Serial driver";
-static char *serial_version = "4.25";
+static char *serial_version = "4.26";
static DECLARE_TASK_QUEUE(tq_serial);
@@ -852,13 +852,14 @@ static void rs_timer(void)
static unsigned long last_strobe = 0;
struct async_struct *info;
unsigned int i;
+ unsigned long flags;
if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
for (i=1; i < NR_IRQS; i++) {
info = IRQ_ports[i];
if (!info)
continue;
- cli();
+ save_flags(flags); cli();
#ifdef CONFIG_SERIAL_SHARE_IRQ
if (info->next_port) {
do {
@@ -876,7 +877,7 @@ static void rs_timer(void)
} else
#endif /* CONFIG_SERIAL_SHARE_IRQ */
rs_interrupt_single(i, NULL, NULL);
- sti();
+ restore_flags(flags);
}
}
last_strobe = jiffies;
@@ -884,13 +885,13 @@ static void rs_timer(void)
timer_active |= 1 << RS_TIMER;
if (IRQ_ports[0]) {
- cli();
+ save_flags(flags); cli();
#ifdef CONFIG_SERIAL_SHARE_IRQ
rs_interrupt(0, NULL, NULL);
#else
rs_interrupt_single(0, NULL, NULL);
#endif
- sti();
+ restore_flags(flags);
timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
}
@@ -1523,12 +1524,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
static void rs_flush_buffer(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
-
+ unsigned long flags;
+
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return;
- cli();
+ save_flags(flags); cli();
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- sti();
+ restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
@@ -1565,6 +1567,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
static void rs_throttle(struct tty_struct * tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
@@ -1581,14 +1584,15 @@ static void rs_throttle(struct tty_struct * tty)
if (tty->termios->c_cflag & CRTSCTS)
info->MCR &= ~UART_MCR_RTS;
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
static void rs_unthrottle(struct tty_struct * tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
+ unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
@@ -1607,9 +1611,9 @@ static void rs_unthrottle(struct tty_struct * tty)
}
if (tty->termios->c_cflag & CRTSCTS)
info->MCR |= UART_MCR_RTS;
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
/*
@@ -1678,10 +1682,16 @@ 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.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
+ (new_serial.type < PORT_UNKNOWN) ||
+ (new_serial.type > PORT_MAX)) {
return -EINVAL;
}
+ if ((new_serial.type != state->type) ||
+ (new_serial.xmit_fifo_size <= 0))
+ new_serial.xmit_fifo_size =
+ uart_config[state->type].dfl_xmit_fifo_size;
+
/* Make sure address is not already in use */
if (new_serial.type) {
for (i = 0 ; i < NR_PORTS; i++)
@@ -1730,9 +1740,6 @@ static int set_serial_info(struct async_struct * info,
check_and_exit:
if (!state->port || !state->type)
return 0;
- if (state->type != old_state.type)
- info->xmit_fifo_size = state->xmit_fifo_size =
- uart_config[state->type].dfl_xmit_fifo_size;
if (state->flags & ASYNC_INITIALIZED) {
if (((old_state.flags & ASYNC_SPD_MASK) !=
(state->flags & ASYNC_SPD_MASK)) ||
@@ -1767,10 +1774,11 @@ static int get_lsr_info(struct async_struct * info, unsigned int *value)
{
unsigned char status;
unsigned int result;
+ unsigned long flags;
- cli();
+ save_flags(flags); cli();
status = serial_in(info, UART_LSR);
- sti();
+ restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
return put_user(result,value);
}
@@ -1780,11 +1788,12 @@ static int get_modem_info(struct async_struct * info, unsigned int *value)
{
unsigned char control, status;
unsigned int result;
+ unsigned long flags;
control = info->MCR;
- cli();
+ save_flags(flags); cli();
status = serial_in(info, UART_MSR);
- sti();
+ restore_flags(flags);
result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
#ifdef TIOCM_OUT1
@@ -1803,6 +1812,7 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
{
int error;
unsigned int arg;
+ unsigned long flags;
error = get_user(arg, value);
if (error)
@@ -1849,9 +1859,9 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
default:
return -EINVAL;
}
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
return 0;
}
@@ -1868,7 +1878,9 @@ static int do_autoconfig(struct async_struct * info)
shutdown(info);
autoconfig(info->state);
- if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
+ if ((info->state->flags & ASYNC_AUTO_IRQ) &&
+ (info->state->port != 0) &&
+ (info->state->type != PORT_UNKNOWN))
info->state->irq = detect_uart_irq(info->state);
retval = startup(info);
@@ -2022,7 +2034,8 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
struct async_struct * info = (struct async_struct *)tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct *p_cuser; /* user space */
-
+ unsigned long flags;
+
if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
@@ -2074,18 +2087,18 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- cli();
+ save_flags(flags); cli();
/* note the counters on entry */
cprev = info->state->icount;
- sti();
+ restore_flags(flags);
while (1) {
interruptible_sleep_on(&info->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
- cli();
+ save_flags(flags); cli();
cnow = info->state->icount; /* atomic copy */
- sti();
+ restore_flags(flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
@@ -2106,9 +2119,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
* RI where only 0->1 is counted.
*/
case TIOCGICOUNT:
- cli();
+ save_flags(flags); cli();
cnow = info->state->icount;
- sti();
+ restore_flags(flags);
p_cuser = (struct serial_icounter_struct *) arg;
error = put_user(cnow.cts, &p_cuser->cts);
if (error) return error;
@@ -2118,6 +2131,26 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
if (error) return error;
error = put_user(cnow.dcd, &p_cuser->dcd);
if (error) return error;
+ error = put_user(cnow.rx, &p_cuser->rx);
+ if (error) return error;
+ error = put_user(cnow.tx, &p_cuser->tx);
+ if (error) return error;
+ error = put_user(cnow.frame, &p_cuser->frame);
+ if (error) return error;
+ error = put_user(cnow.overrun, &p_cuser->overrun);
+ if (error) return error;
+ error = put_user(cnow.parity, &p_cuser->parity);
+ if (error) return error;
+ error = put_user(cnow.brk, &p_cuser->brk);
+ if (error) return error;
+ error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
+ if (error) return error;
+ return 0;
+
+ case TIOCSERGWILD:
+ case TIOCSERSWILD:
+ /* "setserial -W" is called in Debian boot */
+ printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
return 0;
default:
@@ -2129,7 +2162,8 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
-
+ unsigned long flags;
+
if ( (tty->termios->c_cflag == old_termios->c_cflag)
&& ( RELEVANT_IFLAG(tty->termios->c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
@@ -2141,9 +2175,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
if ((old_termios->c_cflag & CBAUD) &&
!(tty->termios->c_cflag & CBAUD)) {
info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
/* Handle transition away from B0 status */
@@ -2154,9 +2188,9 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->MCR |= UART_MCR_RTS;
}
- cli();
+ save_flags(flags); cli();
serial_out(info, UART_MCR, info->MCR);
- sti();
+ restore_flags(flags);
}
/* Handle turning off CRTSCTS */
@@ -2306,6 +2340,9 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (info->state->type == PORT_UNKNOWN)
return;
+ if (info->xmit_fifo_size == 0)
+ return; /* Just in case.... */
+
orig_jiffies = jiffies;
/*
* Set the check interval to be 1/5 of the estimated time to
@@ -2377,7 +2414,8 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
struct wait_queue wait = { current, NULL };
struct serial_state *state = info->state;
int retval;
- int do_clocal = 0;
+ int do_clocal = 0, extra_count = 0;
+ unsigned long flags;
/*
* If the device is in the middle of being closed, then block
@@ -2447,19 +2485,21 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready before block: ttys%d, count = %d\n",
state->line, state->count);
#endif
- cli();
- if (!tty_hung_up_p(filp))
+ save_flags(flags); cli();
+ if (!tty_hung_up_p(filp)) {
+ extra_count = 1;
state->count--;
- sti();
+ }
+ restore_flags(flags);
info->blocked_open++;
while (1) {
- cli();
+ save_flags(flags); cli();
if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
(tty->termios->c_cflag & CBAUD))
serial_out(info, UART_MCR,
serial_inp(info, UART_MCR) |
(UART_MCR_DTR | UART_MCR_RTS));
- sti();
+ restore_flags(flags);
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
@@ -2490,7 +2530,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
}
current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
+ if (extra_count)
state->count++;
info->blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
@@ -2549,12 +2589,15 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
int retval, line;
unsigned long page;
+ MOD_INC_USE_COUNT;
line = MINOR(tty->device) - tty->driver.minor_start;
if ((line < 0) || (line >= NR_PORTS))
return -ENODEV;
retval = get_async_struct(line, &info);
if (retval)
return retval;
+ tty->driver_data = info;
+ info->tty = tty;
if (serial_paranoia_check(info, tty->device, "rs_open"))
return -ENODEV;
@@ -2562,8 +2605,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
info->state->count);
#endif
- tty->driver_data = info;
- info->tty = tty;
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
if (!tmp_buf) {
@@ -2598,7 +2639,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
if (retval)
return retval;
- MOD_INC_USE_COUNT;
retval = block_til_ready(tty, filp, info);
if (retval) {
#ifdef SERIAL_DEBUG_OPEN
@@ -2641,6 +2681,7 @@ static inline int line_info(char *buf, struct serial_state *state)
struct async_struct *info = state->info, scr_info;
char stat_buf[30], control, status;
int ret;
+ unsigned long flags;
ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
state->line, uart_config[state->type].name,
@@ -2663,10 +2704,10 @@ static inline int line_info(char *buf, struct serial_state *state)
info->quot = 0;
info->tty = 0;
}
- cli();
+ save_flags(flags); cli();
status = serial_in(info, UART_MSR);
control = info ? info->MCR : serial_in(info, UART_MCR);
- sti();
+ restore_flags(flags);
stat_buf[0] = 0;
stat_buf[1] = 0;
@@ -2713,12 +2754,13 @@ static inline int line_info(char *buf, struct serial_state *state)
int rs_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
- int i, len = 0;
+ int i, len = 0, l;
off_t begin = 0;
len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
for (i = 0; i < NR_PORTS && len < 4000; i++) {
- len += line_info(page + len, &rs_table[i]);
+ l = line_info(page + len, &rs_table[i]);
+ len += l;
if (len+begin > off+count)
goto done;
if (len+begin < off) {
@@ -2764,10 +2806,11 @@ static _INLINE_ void show_serial_version(void)
#endif
#ifdef CONFIG_SERIAL_SHARE_IRQ
printk(" SHARE_IRQ");
-#endif
#define SERIAL_OPT
+#endif
#ifdef CONFIG_SERIAL_DETECT_IRQ
printk(" DETECT_IRQ");
+#define SERIAL_OPT
#endif
#ifdef SERIAL_OPT
printk(" enabled\n");
@@ -2788,7 +2831,7 @@ static unsigned detect_uart_irq (struct serial_state * state)
{
int irq;
unsigned long irqs;
- unsigned char save_mcr;
+ unsigned char save_mcr, save_ier;
struct async_struct scr_info; /* serial_{in,out} because HUB6 */
#ifdef CONFIG_SERIAL_MANY_PORTS
@@ -2812,15 +2855,30 @@ static unsigned detect_uart_irq (struct serial_state * state)
/* forget possible initially masked and pending IRQ */
probe_irq_off(probe_irq_on());
save_mcr = serial_inp(&scr_info, UART_MCR);
-
+ save_ier = serial_inp(&scr_info, UART_IER);
serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
+
irqs = probe_irq_on();
serial_outp(&scr_info, UART_MCR, 0);
- udelay (1);
+ udelay (10);
+ if (state->flags & ASYNC_FOURPORT) {
+ serial_outp(&scr_info, UART_MCR,
+ UART_MCR_DTR | UART_MCR_RTS);
+ } else {
+ serial_outp(&scr_info, UART_MCR,
+ UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
+ }
+ serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */
+ (void)serial_inp(&scr_info, UART_LSR);
+ (void)serial_inp(&scr_info, UART_RX);
+ (void)serial_inp(&scr_info, UART_IIR);
+ (void)serial_inp(&scr_info, UART_MSR);
+ serial_outp(&scr_info, UART_TX, 0xFF);
+ udelay (20);
irq = probe_irq_off(irqs);
serial_outp(&scr_info, UART_MCR, save_mcr);
-
+ serial_outp(&scr_info, UART_IER, save_ier);
#ifdef CONFIG_SERIAL_MANY_PORTS
if (state->flags & ASYNC_FOURPORT)
outb_p(save_ICP, ICP);
@@ -2888,11 +2946,9 @@ static void autoconfig(struct serial_state * state)
if (!(state->flags & ASYNC_SKIP_TEST)) {
scratch = serial_inp(info, UART_MCR);
serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
- scratch2 = serial_inp(info, UART_MSR);
serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
status1 = serial_inp(info, UART_MSR) & 0xF0;
serial_outp(info, UART_MCR, scratch);
- serial_outp(info, UART_MSR, scratch2);
if (status1 != 0x90) {
restore_flags(flags);
return;
@@ -3105,12 +3161,9 @@ __initfunc(int rs_init(void))
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
state->irq = irq_cannonicalize(state->irq);
- if (check_region(state->port,8)) {
- state->type = PORT_UNKNOWN;
+ if (check_region(state->port,8))
continue;
- }
- if ( (state->type == PORT_UNKNOWN)
- && (state->flags & ASYNC_BOOT_AUTOCONF))
+ if (state->flags & ASYNC_BOOT_AUTOCONF)
autoconfig(state);
}
/*
@@ -3252,13 +3305,13 @@ void cleanup_module(void)
/*
* Wait for transmitter & holding register to empty
*/
-static inline void wait_for_xmitr(struct async_struct *info)
+static inline void wait_for_xmitr(struct serial_state *ser)
{
int lsr;
unsigned int tmout = 1000000;
do {
- lsr = serial_inp(info, UART_LSR);
+ lsr = inb(ser->port + UART_LSR);
if (--tmout == 0) break;
} while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
}
@@ -3273,36 +3326,28 @@ static void serial_console_write(struct console *co, const char *s,
struct serial_state *ser;
int ier;
unsigned i;
- struct async_struct scr_info; /* serial_{in,out} because HUB6 */
ser = rs_table + co->index;
- scr_info.magic = SERIAL_MAGIC;
- scr_info.port = ser->port;
- scr_info.flags = ser->flags;
-#ifdef CONFIG_HUB6
- scr_info.hub6 = state->hub6;
-#endif
-
/*
* First save the IER then disable the interrupts
*/
- ier = serial_inp(&scr_info, UART_IER);
- serial_outp(&scr_info, UART_IER, 0x00);
+ ier = inb(ser->port + UART_IER);
+ outb(0x00, ser->port + UART_IER);
/*
* Now, do each character
*/
for (i = 0; i < count; i++, s++) {
- wait_for_xmitr(&scr_info);
+ wait_for_xmitr(ser);
/*
* Send the character out.
* If a LF, also do CR...
*/
- serial_outp(&scr_info, UART_TX, *s);
+ outb(*s, ser->port + UART_TX);
if (*s == 10) {
- wait_for_xmitr(&scr_info);
- serial_outp(&scr_info, UART_TX, 13);
+ wait_for_xmitr(ser);
+ outb(13, ser->port + UART_TX);
}
}
@@ -3310,8 +3355,8 @@ static void serial_console_write(struct console *co, const char *s,
* Finally, Wait for transmitter & holding register to empty
* and restore the IER
*/
- wait_for_xmitr(&scr_info);
- serial_outp(&scr_info, UART_IER, ier);
+ wait_for_xmitr(ser);
+ outb(ier, ser->port + UART_IER);
}
/*
@@ -3323,33 +3368,26 @@ static int serial_console_wait_key(struct console *co)
int ier;
int lsr;
int c;
- struct async_struct scr_info; /* serial_{in,out} because HUB6 */
ser = rs_table + co->index;
- scr_info.magic = SERIAL_MAGIC;
- scr_info.port = ser->port;
- scr_info.flags = ser->flags;
-#ifdef CONFIG_HUB6
- scr_info.hub6 = state->hub6;
-#endif
/*
* First save the IER then disable the interrupts so
* that the real driver for the port does not get the
* character.
*/
- ier = serial_inp(&scr_info, UART_IER);
- serial_outp(&scr_info, UART_IER, 0x00);
+ ier = inb(ser->port + UART_IER);
+ outb(0x00, ser->port + UART_IER);
do {
- lsr = serial_inp(&scr_info, UART_LSR);
+ lsr = inb(ser->port + UART_LSR);
} while (!(lsr & UART_LSR_DR));
- c = serial_inp(&scr_info, UART_RX);
+ c = inb(ser->port + UART_RX);
/*
* Restore the interrupts
*/
- serial_outp(&scr_info, UART_IER, ier);
+ outb(ier, ser->port + UART_IER);
return c;
}
@@ -3375,7 +3413,6 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
int cflag = CREAD | HUPCL | CLOCAL;
int quot = 0;
char *s;
- struct async_struct scr_info; /* serial_{in,out} because HUB6 */
if (options) {
baud = simple_strtoul(options, NULL, 10);
@@ -3439,12 +3476,6 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
* Divisor, bytesize and parity
*/
ser = rs_table + co->index;
- scr_info.magic = SERIAL_MAGIC;
- scr_info.port = ser->port;
- scr_info.flags = ser->flags;
-#ifdef CONFIG_HUB6
- scr_info.hub6 = state->hub6;
-#endif
quot = ser->baud_base / baud;
cval = cflag & (CSIZE | CSTOPB);
#if defined(__powerpc__) || defined(__alpha__)
@@ -3461,17 +3492,17 @@ __initfunc(static int serial_console_setup(struct console *co, char *options))
* Disable UART interrupts, set DTR and RTS high
* and set speed.
*/
- serial_outp(&scr_info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
- serial_outp(&scr_info, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(&scr_info, UART_DLM, quot >> 8); /* MS of divisor */
- serial_outp(&scr_info, UART_LCR, cval); /* reset DLAB */
- serial_outp(&scr_info, UART_IER, 0);
- serial_outp(&scr_info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+ outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */
+ outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */
+ outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */
+ outb(cval, ser->port + UART_LCR); /* reset DLAB */
+ outb(0, ser->port + UART_IER);
+ outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
/*
* If we read 0xff from the LSR, there is no UART here.
*/
- if (serial_inp(&scr_info, UART_LSR) == 0xff)
+ if (inb(ser->port + UART_LSR) == 0xff)
return -1;
return 0;
}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 06795e07a..7239923ec 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -46,6 +46,8 @@
#include <linux/ioport.h>
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
+
#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -142,7 +144,7 @@ static int stl_nrbrds = sizeof(stl_brdconf) / sizeof(stlconf_t);
*/
static char *stl_drvtitle = "Stallion Multiport Serial Driver";
static char *stl_drvname = "stallion";
-static char *stl_drvversion = "5.4.5";
+static char *stl_drvversion = "5.4.6";
static char *stl_serialname = "ttyE";
static char *stl_calloutname = "cue";
@@ -1082,7 +1084,6 @@ static int stl_write(struct tty_struct *tty, int from_user, const unsigned char
{
stlport_t *portp;
unsigned int len, stlen;
- unsigned long flags;
unsigned char *chbuf;
char *head, *tail;
@@ -1114,12 +1115,9 @@ static int stl_write(struct tty_struct *tty, int from_user, const unsigned char
(tail - head - 1);
count = MIN(len, count);
- save_flags(flags);
- cli();
down(&stl_tmpwritesem);
copy_from_user(stl_tmpwritebuf, chbuf, count);
up(&stl_tmpwritesem);
- restore_flags(flags);
chbuf = &stl_tmpwritebuf[0];
}
@@ -2005,7 +2003,6 @@ static void stl_echpci64intr(stlbrd_t *brdp)
/*
* Service an off-level request for some channel.
*/
-
static void stl_offintr(void *private)
{
stlport_t *portp;
@@ -2020,10 +2017,12 @@ static void stl_offintr(void *private)
if (portp == (stlport_t *) NULL)
return;
+
tty = portp->tty;
if (tty == (struct tty_struct *) NULL)
return;
+ lock_kernel();
if (test_bit(ASYI_TXLOW, &portp->istate)) {
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
@@ -2045,6 +2044,7 @@ static void stl_offintr(void *private)
}
}
}
+ unlock_kernel();
}
/*****************************************************************************/
@@ -2193,7 +2193,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
}
/*
- * Everything looks OK, so lets go ahead and probe for the hardware.
+ * Everything looks OK, so let's go ahead and probe for the hardware.
*/
brdp->clk = CD1400_CLK;
brdp->isr = stl_eiointr;
@@ -2568,7 +2568,7 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *dev)
#endif
/*
- * We have all resources from the board, so lets setup the actual
+ * We have all resources from the board, so let's setup the actual
* board structure now.
*/
switch (brdtype) {
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index a518f6b6a..c70ec0e1f 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -19,8 +19,10 @@
#include <linux/reboot.h>
#include <linux/sysrq.h>
#include <linux/kbd_kern.h>
+#include <linux/quotaops.h>
+#include <linux/smp_lock.h>
+
#include <asm/ptrace.h>
-#include <asm/smp_lock.h>
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
@@ -188,7 +190,7 @@ static void go_sync(kdev_t dev, int remount_flag)
printk("R/O\n");
return;
}
- quota_off(dev, -1);
+ DQUOT_OFF(dev);
fsync_dev(dev);
flags = MS_RDONLY;
if (sb->s_op && sb->s_op->remount_fs) {
diff --git a/drivers/char/tga.c b/drivers/char/tga.c
deleted file mode 100644
index 7bab07023..000000000
--- a/drivers/char/tga.c
+++ /dev/null
@@ -1,1169 +0,0 @@
-/*
- * linux/drivers/char/tga.c
- *
- * Copyright (C) 1995 Jay Estabrook
- */
-
-/*
- * tga.c
- *
- * This module exports the console io support for DEC's TGA
- */
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/console.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/console_struct.h>
-
-extern struct console vt_console_driver;
-
-/* TGA hardware description (minimal) */
-/*
- * Offsets within Memory Space
- */
-#define TGA_ROM_OFFSET 0x0000000
-#define TGA_REGS_OFFSET 0x0100000
-#define TGA_8PLANE_FB_OFFSET 0x0200000
-#define TGA_24PLANE_FB_OFFSET 0x0804000
-#define TGA_24PLUSZ_FB_OFFSET 0x1004000
-
-#define TGA_PLANEMASK_REG 0x0028
-#define TGA_MODE_REG 0x0030
-#define TGA_RASTEROP_REG 0x0034
-#define TGA_DEEP_REG 0x0050
-#define TGA_PIXELMASK_REG 0x005c
-#define TGA_CURSOR_BASE_REG 0x0060
-#define TGA_HORIZ_REG 0x0064
-#define TGA_VERT_REG 0x0068
-#define TGA_BASE_ADDR_REG 0x006c
-#define TGA_VALID_REG 0x0070
-#define TGA_CURSOR_XY_REG 0x0074
-#define TGA_INTR_STAT_REG 0x007c
-#define TGA_RAMDAC_SETUP_REG 0x00c0
-#define TGA_BLOCK_COLOR0_REG 0x0140
-#define TGA_BLOCK_COLOR1_REG 0x0144
-#define TGA_CLOCK_REG 0x01e8
-#define TGA_RAMDAC_REG 0x01f0
-#define TGA_CMD_STAT_REG 0x01f8
-
-/*
- * useful defines for managing the BT485 on the 8-plane TGA
- */
-#define BT485_READ_BIT 0x01
-#define BT485_WRITE_BIT 0x00
-
-#define BT485_ADDR_PAL_WRITE 0x00
-#define BT485_DATA_PAL 0x02
-#define BT485_PIXEL_MASK 0x04
-#define BT485_ADDR_PAL_READ 0x06
-#define BT485_ADDR_CUR_WRITE 0x08
-#define BT485_DATA_CUR 0x0a
-#define BT485_CMD_0 0x0c
-#define BT485_ADDR_CUR_READ 0x0e
-#define BT485_CMD_1 0x10
-#define BT485_CMD_2 0x12
-#define BT485_STATUS 0x14
-#define BT485_CMD_3 0x14
-#define BT485_CUR_RAM 0x16
-#define BT485_CUR_LOW_X 0x18
-#define BT485_CUR_HIGH_X 0x1a
-#define BT485_CUR_LOW_Y 0x1c
-#define BT485_CUR_HIGH_Y 0x1e
-
-/*
- * useful defines for managing the BT463 on the 24-plane TGAs
- */
-#define BT463_ADDR_LO 0x0
-#define BT463_ADDR_HI 0x1
-#define BT463_REG_ACC 0x2
-#define BT463_PALETTE 0x3
-
-#define BT463_CUR_CLR_0 0x0100
-#define BT463_CUR_CLR_1 0x0101
-
-#define BT463_CMD_REG_0 0x0201
-#define BT463_CMD_REG_1 0x0202
-#define BT463_CMD_REG_2 0x0203
-
-#define BT463_READ_MASK_0 0x0205
-#define BT463_READ_MASK_1 0x0206
-#define BT463_READ_MASK_2 0x0207
-#define BT463_READ_MASK_3 0x0208
-
-#define BT463_BLINK_MASK_0 0x0209
-#define BT463_BLINK_MASK_1 0x020a
-#define BT463_BLINK_MASK_2 0x020b
-#define BT463_BLINK_MASK_3 0x020c
-
-#define BT463_WINDOW_TYPE_BASE 0x0300
-
-/*
- * built-in font management constants
- *
- * NOTE: the built-in font is 8x16, and the video resolution
- * is 640x480 @ 60Hz.
- * This means we could put 30 rows of text on the screen (480/16).
- * However, we wish to make then TGA look just like a VGA, as the
- * default, so, we pad the character to 8x18, and leave some scan
- * lines at the bottom unused.
- */
-#define TGA_F_WIDTH 8
-#define TGA_F_HEIGHT 16
-#define TGA_F_HEIGHT_PADDED 18
-
-int tga_type;
-unsigned long tga_mem_base;
-unsigned long tga_fb_base;
-unsigned long tga_regs_base;
-unsigned int tga_bpp, tga_fb_width, tga_fb_height, tga_fb_stride;
-
-static unsigned int fb_offset_presets[4] __initdata = {
- TGA_8PLANE_FB_OFFSET,
- TGA_24PLANE_FB_OFFSET,
- 0xffffffff,
- TGA_24PLUSZ_FB_OFFSET
-};
-
-static unsigned int deep_presets[4] __initdata = {
- 0x00014000,
- 0x0001440d,
- 0xffffffff,
- 0x0001441d
-};
-
-static unsigned int rasterop_presets[4] __initdata = {
- 0x00000003,
- 0x00000303,
- 0xffffffff,
- 0x00000303
-};
-
-static unsigned int mode_presets[4] __initdata = {
- 0x00002000,
- 0x00002300,
- 0xffffffff,
- 0x00002300
-};
-
-static unsigned int base_addr_presets[4] __initdata = {
- 0x00000000,
- 0x00000001,
- 0xffffffff,
- 0x00000001
-};
-
-#define TGA_WRITE_REG(v,r) \
- { writel((v), tga_regs_base+(r)); mb(); }
-
-#define TGA_READ_REG(r) readl(tga_regs_base+(r))
-
-#define BT485_WRITE(v,r) \
- TGA_WRITE_REG((r),TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG(((v)&0xff)|((r)<<8),TGA_RAMDAC_REG);
-
-#define BT463_LOAD_ADDR(a) \
- TGA_WRITE_REG(BT463_ADDR_LO<<2, TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG((BT463_ADDR_LO<<10)|((a)&0xff), TGA_RAMDAC_REG); \
- TGA_WRITE_REG(BT463_ADDR_HI<<2, TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG((BT463_ADDR_HI<<10)|(((a)>>8)&0xff), TGA_RAMDAC_REG);
-
-#define BT463_WRITE(m,a,v) \
- BT463_LOAD_ADDR((a)); \
- TGA_WRITE_REG(((m)<<2),TGA_RAMDAC_SETUP_REG); \
- TGA_WRITE_REG(((m)<<10)|((v)&0xff),TGA_RAMDAC_REG);
-
-extern char tga_builtin_font[];
-
-void tga_init_video(void);
-void tga_clear_screen(void);
-
-void
-set_palette (void)
-{
- int i, j;
-
- if (console_blanked || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
- return;
-
-
- if (tga_type == 0) { /* 8-plane */
- BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE);
- TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
-
- for (i = 0; i < 16; i++) {
- j = color_table[i];
- TGA_WRITE_REG(default_red[j]|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_grn[j]|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_blu[j]|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
- }
- } else {
- BT463_LOAD_ADDR(0x0000);
- TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
-
- for (i = 0; i < 16; i++) {
- j = color_table[i];
- TGA_WRITE_REG(default_red[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_grn[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_blu[j]|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- }
- }
-}
-
-void
-__set_origin(unsigned short offset)
-{
- /*
- * should not be called, but if so, do nothing...
- */
-}
-
-/*
- * Hide the cursor from view, during blanking, usually...
- */
-void
-hide_cursor(void)
-{
- unsigned long flags;
- save_flags(flags); cli();
-
- if (tga_type == 0) {
- BT485_WRITE(0x20, BT485_CMD_2);
- } else {
- TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
- }
-
- restore_flags(flags);
-}
-
-void
-set_cursor(int currcons)
-{
- unsigned int idx, xt, yt, row, col;
- unsigned long flags;
-
- if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
- return;
-
- if (__real_origin != __origin)
- __set_origin(__real_origin);
-
- save_flags(flags); cli();
-
- if (deccm) {
- idx = (pos - video_mem_base) >> 1;
- col = idx % 80;
- row = (idx - col) / 80;
-
- if (tga_type == 0) { /* 8-plane */
-
- xt = col * TGA_F_WIDTH + 64;
- yt = row * TGA_F_HEIGHT_PADDED + 64;
-
- /* make sure it's enabled */
- BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */
-
- BT485_WRITE(xt, BT485_CUR_LOW_X);
- BT485_WRITE((xt >> 8), BT485_CUR_HIGH_X);
- BT485_WRITE(yt, BT485_CUR_LOW_Y);
- BT485_WRITE((yt >> 8), BT485_CUR_HIGH_Y);
-
- } else {
-
- xt = col * TGA_F_WIDTH + 144;
- yt = row * TGA_F_HEIGHT_PADDED + 35;
-
- TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */
- TGA_WRITE_REG(xt | (yt << 12), TGA_CURSOR_XY_REG);
- }
-
- } else
- hide_cursor();
- restore_flags(flags);
-}
-
-__initfunc(unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc))
-{
- can_do_color = 1;
-
- /*
- * fake the screen memory with some CPU memory
- */
- video_mem_base = kmem_start;
- kmem_start += video_screen_size;
- video_mem_term = kmem_start;
-
- video_type = VIDEO_TYPE_TGAC;
-
- *display_desc = "TGA";
-
- return kmem_start;
-}
-
-__initfunc(void
-con_type_init_finish(void))
-{
-}
-
-/*
- * NOTE: get_scrmem() and set_scrmem() are here only because
- * the VGA version of set_scrmem() has some direct VGA references.
- */
-void
-get_scrmem(int currcons)
-{
- memcpyw((unsigned short *)vc_scrbuf[currcons],
- (unsigned short *)origin, video_screen_size);
- origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
- scr_end = video_mem_end = video_mem_start + video_screen_size;
- pos = origin + y*video_size_row + (x<<1);
-}
-
-void
-set_scrmem(int currcons, long offset)
-{
- if (video_mem_term - video_mem_base < offset + video_screen_size)
- offset = 0; /* strange ... */
- memcpyw((unsigned short *)(video_mem_base + offset),
- (unsigned short *) origin, video_screen_size);
- video_mem_start = video_mem_base;
- video_mem_end = video_mem_term;
- origin = video_mem_base + offset;
- scr_end = origin + video_screen_size;
- pos = origin + y*video_size_row + (x<<1);
-}
-
-/*
- * PIO_FONT support.
- *
- * for now, we will use/allow *only* our built-in font...
- */
-int
-set_get_font(char * arg, int set, int ch512)
-{
- return -EINVAL;
-}
-
-/*
- * Adjust the screen to fit a font of a certain height
- *
- * Returns < 0 for error, 0 if nothing changed, and the number
- * of lines on the adjusted console if changed.
- *
- * for now, we only support the built-in font...
- */
-int
-con_adjust_height(unsigned long fontheight)
-{
- return -EINVAL;
-}
-
-/* NOTE:
- * this is here, and not in console.c, because the VGA version
- * tests the controller type to see if color can be done. We *KNOW*
- * that we can do color on the TGA... :-)
- *
- * FIXME? maybe the init codes for VGA and TGA could set
- * a flag for (in)ability to do colormap set/get???
- */
-
-int
-set_get_cmap(unsigned char * arg, int set) {
- int i;
-
- i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
- if (i)
- return i;
-
- for (i=0; i<16; i++) {
- if (set) {
- get_user(default_red[i], arg++) ;
- get_user(default_grn[i], arg++) ;
- get_user(default_blu[i], arg++) ;
- } else {
- put_user (default_red[i], arg++) ;
- put_user (default_grn[i], arg++) ;
- put_user (default_blu[i], arg++) ;
- }
- }
- if (set) {
- for (i=0; i<MAX_NR_CONSOLES; i++)
- if (vc_cons_allocated(i)) {
- int j, k ;
- for (j=k=0; j<16; j++) {
- vc_cons[i].d->vc_palette[k++] = default_red[j];
- vc_cons[i].d->vc_palette[k++] = default_grn[j];
- vc_cons[i].d->vc_palette[k++] = default_blu[j];
- }
- }
- set_palette() ;
- }
-
- return 0;
-}
-
-/*
- * dummy routines for the VESA blanking code, which is VGA only,
- * so we don't have to carry that stuff around for the TGA...
- */
-void vesa_powerdown(void)
-{
-}
-void vesa_blank(void)
-{
-}
-void vesa_unblank(void)
-{
-}
-void set_vesa_blanking(const unsigned long arg)
-{
-}
-
-
-/*
- * See if we have a TGA card.
- * Just a placeholder at the moment, because of the strange
- * way the TGA card is initialized. This has to be enabled when
- * the kernel initializes PCI devices before the console.
- */
-__initfunc(int con_is_present(void))
-{
-#if 0
- unsigned char pci_bus, pci_devfn;
- int status;
-
- status = pcibios_find_device (PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA,
- 0, &pci_bus, &pci_devfn);
- return (status == PCIBIOS_DEVICE_NOT_FOUND) ? 0 : 1;
-#endif
- return 1;
-}
-
-/*
- * video init code, called from within the PCI bus probing code;
- * when TGA console is configured, at the end of the probing code,
- * we call here to look for a TGA device, and proceed...
- */
-__initfunc(void
-tga_console_init(void))
-{
- struct pci_dev *dev;
-
- /*
- * first, find the TGA among the PCI devices...
- */
- if (! (dev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL))) {
- /* PANIC!!! */
- printk("tga_console_init: TGA not found!!! :-(\n");
- return;
- }
-
- /*
- * read BASE_REG_0 for memory address
- */
- tga_mem_base = dev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
-#ifdef DEBUG
- printk("tga_console_init: mem_base 0x%lx\n", tga_mem_base);
-#endif /* DEBUG */
-
- tga_type = (readl(tga_mem_base) >> 12) & 0x0f;
- if (tga_type != 0 && tga_type != 1 && tga_type != 3) {
- printk("TGA type (0x%x) unrecognized!\n", tga_type);
- return;
- }
- tga_init_video();
- tga_clear_screen();
-
- /*
- * FINALLY, we can register TGA as console (whew!)
- */
-#ifdef CONFIG_VT_CONSOLE
- register_console(&vt_console_driver);
-#endif
-}
-
-unsigned char PLLbits[7] __initdata = { 0x80, 0x04, 0x00, 0x24, 0x44, 0x80, 0xb8 };
-
-const unsigned long bt485_cursor_source[64] __initdata = {
- 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
- 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
- 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
- 0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,0x00000000000000ff,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
-
-const unsigned int bt463_cursor_source[256] __initdata = {
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
-
-__initfunc(void
-tga_init_video(void))
-{
- int i, j, temp;
- unsigned char *cbp;
-
- tga_regs_base = (tga_mem_base + TGA_REGS_OFFSET);
- tga_fb_base = (tga_mem_base + fb_offset_presets[tga_type]);
-
- /* first, disable video timing */
- TGA_WRITE_REG(0x03, TGA_VALID_REG); /* SCANNING and BLANK */
-
- /* write the DEEP register */
- while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
- continue;
-
- mb();
- TGA_WRITE_REG(deep_presets[tga_type], TGA_DEEP_REG);
- while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
- continue;
- mb();
-
- /* write some more registers */
- TGA_WRITE_REG(rasterop_presets[tga_type], TGA_RASTEROP_REG);
- TGA_WRITE_REG(mode_presets[tga_type], TGA_MODE_REG);
- TGA_WRITE_REG(base_addr_presets[tga_type], TGA_BASE_ADDR_REG);
-
- /* write the PLL for 640x480 @ 60Hz */
- for (i = 0; i <= 6; i++) {
- for (j = 0; j <= 7; j++) {
- temp = (PLLbits[i] >> (7-j)) & 1;
- if (i == 6 && j == 7)
- temp |= 2;
- TGA_WRITE_REG(temp, TGA_CLOCK_REG);
- }
- }
-
- /* write some more registers */
- TGA_WRITE_REG(0xffffffff, TGA_PLANEMASK_REG);
- TGA_WRITE_REG(0xffffffff, TGA_PIXELMASK_REG);
- TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR0_REG);
- TGA_WRITE_REG(0x12345678, TGA_BLOCK_COLOR1_REG);
-
- /* init video timing regs for 640x480 @ 60 Hz */
- TGA_WRITE_REG(0x018608a0, TGA_HORIZ_REG);
- TGA_WRITE_REG(0x084251e0, TGA_VERT_REG);
-
- if (tga_type == 0) { /* 8-plane */
-
- tga_bpp = 1;
-
- /* init BT485 RAMDAC registers */
- BT485_WRITE(0xa2, BT485_CMD_0);
- BT485_WRITE(0x01, BT485_ADDR_PAL_WRITE);
- BT485_WRITE(0x14, BT485_CMD_3); /* cursor 64x64 */
- BT485_WRITE(0x40, BT485_CMD_1);
- BT485_WRITE(0x22, BT485_CMD_2); /* WIN cursor type */
- BT485_WRITE(0xff, BT485_PIXEL_MASK);
-
- /* fill palette registers */
- BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE);
- TGA_WRITE_REG(BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
-
- for (i = 0; i < 16; i++) {
- j = color_table[i];
- TGA_WRITE_REG(default_red[j]|(BT485_DATA_PAL<<8),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_grn[j]|(BT485_DATA_PAL<<8),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_blu[j]|(BT485_DATA_PAL<<8),
- TGA_RAMDAC_REG);
- }
- for (i = 0; i < 240*3; i += 4) {
- TGA_WRITE_REG(0x55|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT485_DATA_PAL<<8), TGA_RAMDAC_REG);
- }
-
- /* initialize RAMDAC cursor colors */
- BT485_WRITE(0, BT485_ADDR_CUR_WRITE);
-
- BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */
- BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */
- BT485_WRITE(0xaa, BT485_DATA_CUR); /* overscan WHITE */
-
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 1 BLACK */
-
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 2 BLACK */
-
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */
- BT485_WRITE(0x00, BT485_DATA_CUR); /* color 3 BLACK */
-
- /* initialize RAMDAC cursor RAM */
- BT485_WRITE(0x00, BT485_ADDR_PAL_WRITE);
- cbp = (unsigned char *)bt485_cursor_source;
- for (i = 0; i < 512; i++) {
- BT485_WRITE(*cbp++, BT485_CUR_RAM);
- }
- for (i = 0; i < 512; i++) {
- BT485_WRITE(0xff, BT485_CUR_RAM);
- }
-
- } else { /* 24-plane or 24plusZ */
-
- tga_bpp = 4;
-
- TGA_WRITE_REG(0x01, TGA_VALID_REG); /* SCANNING */
-
- /*
- * init some registers
- */
- BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
- BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
- BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2, 0x40);
-
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_2, 0xff);
- BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_3, 0x0f);
-
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00);
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00);
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00);
- BT463_WRITE(BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00);
-
- /*
- * fill the palette
- */
- BT463_LOAD_ADDR(0x0000);
- TGA_WRITE_REG((BT463_PALETTE<<2), TGA_RAMDAC_REG);
-
- for (i = 0; i < 16; i++) {
- j = color_table[i];
- TGA_WRITE_REG(default_red[j]|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_grn[j]|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(default_blu[j]|(BT463_PALETTE<<10),
- TGA_RAMDAC_REG);
- }
- for (i = 0; i < 512*3; i += 4) {
- TGA_WRITE_REG(0x55|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_PALETTE<<10), TGA_RAMDAC_REG);
- }
-
- /*
- * fill window type table after start of vertical retrace
- */
- while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01))
- continue;
- TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG);
- mb();
- while (!(TGA_READ_REG(TGA_INTR_STAT_REG) & 0x01))
- continue;
- TGA_WRITE_REG(0x01, TGA_INTR_STAT_REG);
-
- BT463_LOAD_ADDR(BT463_WINDOW_TYPE_BASE);
- TGA_WRITE_REG((BT463_REG_ACC<<2), TGA_RAMDAC_SETUP_REG);
-
- for (i = 0; i < 16; i++) {
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x01|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x80|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- }
-
- /*
- * init cursor colors
- */
- BT463_LOAD_ADDR(BT463_CUR_CLR_0);
-
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* background */
-
- TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */
- TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */
- TGA_WRITE_REG(0xff|(BT463_REG_ACC<<10), TGA_RAMDAC_REG); /* foreground */
-
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
- TGA_WRITE_REG(0x00|(BT463_REG_ACC<<10), TGA_RAMDAC_REG);
-
- /*
- * finally, init the cursor shape
- */
- temp = tga_fb_base - 1024; /* this assumes video starts at base
- and base is beyond memory start*/
-
- for (i = 0; i < 256; i++) {
- writel(bt463_cursor_source[i], temp + i*4);
- }
- TGA_WRITE_REG(temp & 0x000fffff, TGA_CURSOR_BASE_REG);
- }
-
- /* finally, enable video scan & cursor
- (and pray for the monitor... :-) */
- TGA_WRITE_REG(0x05, TGA_VALID_REG); /* SCANNING and CURSOR */
-
- /* oh, and set the globals describing the resolution... :-) */
- tga_fb_width = 640 * tga_bpp;
- tga_fb_height = 480;
- tga_fb_stride = tga_fb_width / sizeof(int);
-}
-
-__initfunc(void
-tga_clear_screen(void))
-{
- register int i, j;
- register unsigned int *dst;
-
- dst = (unsigned int *) ((unsigned long)tga_fb_base);
- for (i = 0; i < tga_fb_height; i++, dst += tga_fb_stride) {
- for (j = 0; j < tga_fb_stride; j++) {
- writel(0, (dst+j));
- }
- }
-
- /* also clear out the "shadow" screen memory */
- memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base));
-}
-
-/*
- * tga_blitc
- *
- * Displays an ASCII character at a specified character cell
- * position.
- *
- * Called from scr_writew() when the destination is
- * the "shadow" screen
- */
-static unsigned int
-fontmask_bits[16] = {
- 0x00000000,
- 0xff000000,
- 0x00ff0000,
- 0xffff0000,
- 0x0000ff00,
- 0xff00ff00,
- 0x00ffff00,
- 0xffffff00,
- 0x000000ff,
- 0xff0000ff,
- 0x00ff00ff,
- 0xffff00ff,
- 0x0000ffff,
- 0xff00ffff,
- 0x00ffffff,
- 0xffffffff
-};
-
-int
-tga_blitc(unsigned int charattr, unsigned long addr)
-{
- int row, col, temp, c, attrib;
- register unsigned int fgmask, bgmask, data, rowbits;
- register unsigned int *dst;
- register unsigned char *font_row;
- register int i, j, stride;
-
- c = charattr & 0x00ff;
- attrib = (charattr >> 8) & 0x00ff;
-
- /*
- * extract foreground and background indices
- * NOTE: we always treat blink/underline bits as color for now...
- */
- fgmask = attrib & 0x0f;
- bgmask = (attrib >> 4) & 0x0f;
-
- i = (c & 0xff) << 4; /* NOTE: assumption of 16 bytes per character bitmap */
-
- /*
- * calculate (row,col) from addr and video_mem_base
- */
- temp = (addr - video_mem_base) >> 1;
- col = temp % 80;
- row = (temp - col) / 80;
-
- /*
- * calculate destination address
- */
- dst = (unsigned int *) ( (unsigned long)tga_fb_base
- + ( row * tga_fb_width * TGA_F_HEIGHT_PADDED )
- + ( col * TGA_F_WIDTH * tga_bpp) );
-
- font_row = (unsigned char *)&tga_builtin_font[i];
- stride = tga_fb_stride;
-
- if (tga_type == 0) { /* 8-plane */
-
- fgmask = fgmask << 8 | fgmask;
- fgmask |= fgmask << 16;
- bgmask = bgmask << 8 | bgmask;
- bgmask |= bgmask << 16;
-
- for ( j = 0; j < TGA_F_HEIGHT_PADDED; j++ ) {
- if (j < TGA_F_HEIGHT) {
- rowbits = font_row[j];
- } else {
- /* dup the last n rows only if char > 0x7f */
- if (c & 0x80)
- rowbits = font_row[j-(TGA_F_HEIGHT_PADDED-TGA_F_HEIGHT)];
- else
- rowbits = 0;
- }
- data = fontmask_bits[(rowbits>>4)&0xf];
- data = (data & fgmask) | (~data & bgmask);
- writel(data, dst);
- data = fontmask_bits[rowbits&0xf];
- data = (data & fgmask) | (~data & bgmask);
- writel(data, (dst+1));
- dst += stride;
- }
- } else { /* 24-plane */
-
- fgmask = (default_red[fgmask] << 16) |
- (default_grn[fgmask] << 8) |
- (default_blu[fgmask] << 0);
- bgmask = (default_red[bgmask] << 16) |
- (default_grn[bgmask] << 8) |
- (default_blu[bgmask] << 0);
-
- for ( i = 0; i < TGA_F_HEIGHT_PADDED; i++ ) {
- if (i < TGA_F_HEIGHT) {
- rowbits = font_row[i];
- } else {
- /* dup the last n rows only if char > 0x7f */
- if (c & 0x80)
- rowbits = font_row[i-(TGA_F_HEIGHT_PADDED-TGA_F_HEIGHT)];
- else
- rowbits = 0;
- }
- data = 1 << (TGA_F_WIDTH - 1);
- for (j = 0; j < TGA_F_WIDTH; j++, data >>= 1) {
- if (rowbits & data)
- writel(fgmask, (dst+j));
- else
- writel(bgmask, (dst+j));
- }
- dst += stride;
- }
- }
- return (0);
-}
-
-/*
- * font table of displayable characters.
- */
-char tga_builtin_font[]={
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
-0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,
-0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,
-0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00,
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00,
-0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00,
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index bf2e642c4..a26ce1311 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -65,6 +65,7 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
+#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/devpts_fs.h>
#include <linux/file.h>
@@ -80,6 +81,7 @@
#include <linux/proc_fs.h>
#endif
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -107,6 +109,10 @@ struct termios tty_std_termios; /* for the benefit of tty drivers */
struct tty_driver *tty_drivers = NULL; /* linked list of tty drivers */
struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */
+#ifdef CONFIG_UNIX98_PTYS
+extern struct tty_driver ptm_driver[]; /* Unix98 pty masters; for /dev/ptmx */
+#endif
+
/*
* redirect is the pseudo-tty that console output
* is redirected to if asked by TIOCCONS.
@@ -123,6 +129,10 @@ static int tty_release(struct inode *, struct file *);
static int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(struct file * filp, int on);
+#ifdef CONFIG_8xx
+extern long console_8xx_init(void);
+extern int rs_8xx_init(void);
+#endif /* CONFIG_8xx */
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -367,17 +377,24 @@ static struct file_operations hung_up_tty_fops = {
NULL /* hung_up_tty_fasync */
};
+/*
+ * This can be called through the "tq_scheduler"
+ * task-list. That is process synchronous, but
+ * doesn't hold any locks, so we need to make
+ * sure we have the appropriate locks for what
+ * we're doing..
+ */
void do_tty_hangup(void *data)
{
struct tty_struct *tty = (struct tty_struct *) data;
struct file * filp;
struct task_struct *p;
- unsigned long flags;
if (!tty)
return;
-
- save_flags(flags); cli();
+
+ /* inuse_filps is protected by the single kernel lock */
+ lock_kernel();
check_tty_count(tty, "do_tty_hangup");
for (filp = inuse_filps; filp; filp = filp->f_next) {
@@ -396,13 +413,21 @@ void do_tty_hangup(void *data)
filp->f_op = &hung_up_tty_fops;
}
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
- if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
+ /* FIXME! What are the locking issues here? This may me overdoing things.. */
+ {
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ restore_flags(flags);
+ }
+
wake_up_interruptible(&tty->write_wait);
wake_up_interruptible(&tty->read_wait);
@@ -445,7 +470,7 @@ void do_tty_hangup(void *data)
tty->ctrl_status = 0;
if (tty->driver.hangup)
(tty->driver.hangup)(tty);
- restore_flags(flags);
+ unlock_kernel();
}
void tty_hangup(struct tty_struct * tty)
@@ -455,7 +480,7 @@ void tty_hangup(struct tty_struct * tty)
printk("%s hangup...\n", tty_name(tty, buf));
#endif
- queue_task(&tty->tq_hangup, &tq_timer);
+ queue_task(&tty->tq_hangup, &tq_scheduler);
}
void tty_vhangup(struct tty_struct * tty)
@@ -629,7 +654,7 @@ static inline ssize_t do_tty_write(
ret = -ERESTARTSYS;
if (signal_pending(current))
break;
- if (need_resched)
+ if (current->need_resched)
schedule();
}
if (written) {
@@ -1022,6 +1047,10 @@ static void release_dev(struct file * filp)
}
}
#endif
+
+ if (tty->driver.close)
+ tty->driver.close(tty, filp);
+
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
* any waiters on tty->read_wait or tty->write_wait. We test the
@@ -1079,9 +1108,6 @@ static void release_dev(struct file * filp)
* block, so it's safe to proceed with closing.
*/
- if (tty->driver.close)
- tty->driver.close(tty, filp);
-
if (pty_master) {
if (--o_tty->count < 0) {
printk("release_dev: bad pty slave count (%d) for %s\n",
@@ -1153,6 +1179,7 @@ static void release_dev(struct file * filp)
* Make sure that the tty's task queue isn't activated.
*/
run_task_queue(&tq_timer);
+ run_task_queue(&tq_scheduler);
/*
* The release_mem function takes care of the details of clearing
@@ -1208,34 +1235,32 @@ retry_open:
device = c->device(c);
noctty = 1;
}
+#ifdef CONFIG_UNIX98_PTYS
if (device == PTMX_DEV) {
/* find a free pty. */
- struct tty_driver *driver = tty_drivers;
- int minor, line;
-
- /* find the pty driver */
- for (driver=tty_drivers; driver; driver=driver->next)
- if (driver->major == PTY_MASTER_MAJOR)
- break;
- if (!driver) return -ENODEV;
-
- /* find a minor device that is not in use. */
- for (minor=driver->minor_start;
- minor<driver->minor_start+driver->num;
- minor++) {
- device = MKDEV(driver->major, minor);
- retval = init_dev(device, &tty);
- if (retval==0) break; /* success! */
+ int major, minor;
+ struct tty_driver *driver;
+
+ /* find a device that is not in use. */
+ retval = -1;
+ for ( major = 0 ; major < UNIX98_NR_MAJORS ; major++ ) {
+ driver = &ptm_driver[major];
+ for (minor = driver->minor_start ;
+ minor < driver->minor_start + driver->num ;
+ minor++) {
+ device = MKDEV(driver->major, minor);
+ if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */
+ }
}
- if (minor==driver->minor_start+driver->num) /* no success */
- return -EIO; /* no free ptys */
-
+ return -EIO; /* no free ptys */
+ ptmx_found:
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
- line = minor - driver->minor_start;
- devpts_pty_new(line, MKDEV(driver->other->major, line+driver->other->minor_start));
+ minor -= driver->minor_start;
+ devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
noctty = 1;
goto init_dev_done;
}
+#endif
retval = init_dev(device, &tty);
if (retval)
@@ -1962,7 +1987,11 @@ long console_init(long kmem_start, long kmem_end)
memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS);
tty_std_termios.c_iflag = ICRNL | IXON;
tty_std_termios.c_oflag = OPOST | ONLCR;
+#if CONFIG_COBALT_SERIAL
+ tty_std_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL;
+#else
tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL;
+#endif
tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN;
@@ -2046,14 +2075,19 @@ __initfunc(int tty_init(void))
if (tty_register_driver(&dev_console_driver))
panic("Couldn't register /dev/tty0 driver\n");
+#ifndef CONFIG_COBALT_MICRO_SERVER
kbd_init();
#endif
+#endif
#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
espserial_init();
#endif
#ifdef CONFIG_SERIAL
rs_init();
#endif
+#ifdef CONFIG_MAC_SERIAL
+ macserial_init();
+#endif
#ifdef CONFIG_ROCKETPORT
rp_init();
#endif
@@ -2078,6 +2112,9 @@ __initfunc(int tty_init(void))
#ifdef CONFIG_SPECIALIX
specialix_init();
#endif
+#ifdef CONFIG_8xx
+ rs_8xx_init();
+#endif /* CONFIG_8xx */
pty_init();
#ifdef CONFIG_VT
vcs_init();
diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c
index a942985c2..9eb3d3944 100644
--- a/drivers/char/tuner.c
+++ b/drivers/char/tuner.c
@@ -7,13 +7,13 @@
#include <linux/errno.h>
#include <linux/malloc.h>
-#include "i2c.h"
+#include <linux/i2c.h>
#include <linux/videodev.h>
#include "tuner.h"
-int debug = 0; /* insmod parameter */
-int type = 0; /* tuner type */
+static int debug = 0; /* insmod parameter */
+static int type = 0; /* tuner type */
#define dprintk if (debug) printk
@@ -243,10 +243,12 @@ struct i2c_driver i2c_driver_tuner =
tuner_command
};
+EXPORT_NO_SYMBOLS;
+
#ifdef MODULE
int init_module(void)
#else
-int msp3400c_init(void)
+int i2c_tuner_init(void)
#endif
{
i2c_register_driver(&i2c_driver_tuner);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index c0a4dc151..30de4d39b 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -7,7 +7,8 @@
* [minor: N]
*
* /dev/vcsaN: idem, but including attributes, and prefixed with
- * the 4 bytes lines,columns,x,y (as screendump used to give)
+ * the 4 bytes lines,columns,x,y (as screendump used to give).
+ * Attribute/character pair is in native endianity.
* [minor: N+128]
*
* This replaces screendump and part of selection, so that the system
@@ -20,8 +21,6 @@
* - making it shorter - scr_readw are macros which expand in PRETTY long code
*/
-#include <linux/config.h>
-
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
@@ -31,42 +30,29 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/vt_kern.h>
+#include <linux/console_struct.h>
#include <linux/selection.h>
#include <asm/uaccess.h>
+#include <asm/byteorder.h>
#undef attr
#undef org
#undef addr
#define HEADER_SIZE 4
-static unsigned short
-func_scr_readw(unsigned short *org)
-{
-return scr_readw( org );
-}
-
-static void
-func_scr_writew(unsigned short val, unsigned short *org)
-{
-scr_writew( val, org );
-}
-
static int
vcs_size(struct inode *inode)
{
int size;
-#ifdef CONFIG_FB_CONSOLE
- int cons = MINOR(inode->i_rdev) & 127;
-
- if (cons == 0)
- cons = fg_console;
+ int currcons = MINOR(inode->i_rdev) & 127;
+ if (currcons == 0)
+ currcons = fg_console;
else
- cons--;
- if (!vc_cons_allocated(cons))
+ currcons--;
+ if (!vc_cons_allocated(currcons))
return -ENXIO;
-#endif
- size = get_video_num_lines(cons) * get_video_num_columns(cons);
+ size = video_num_lines * video_num_columns;
if (MINOR(inode->i_rdev) & 128)
size = 2*size + HEADER_SIZE;
@@ -94,7 +80,7 @@ static long long vcs_lseek(struct file *file, long long offset, int orig)
return file->f_pos;
}
-#define RETURN( x ) { enable_bh( CONSOLE_BH ); return x; }
+#define RETURN(x) { enable_bh(CONSOLE_BH); return x; }
static ssize_t
vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
@@ -107,7 +93,7 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
attr = (currcons & 128);
currcons = (currcons & 127);
- disable_bh( CONSOLE_BH );
+ disable_bh(CONSOLE_BH);
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
@@ -128,12 +114,12 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
if (!attr) {
org = screen_pos(currcons, p, viewed);
while (count-- > 0)
- put_user(func_scr_readw(org++) & 0xff, buf++);
+ put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
} else {
if (p < HEADER_SIZE) {
char header[HEADER_SIZE];
- header[0] = (char) get_video_num_lines(currcons);
- header[1] = (char) get_video_num_columns(currcons);
+ header[0] = (char) video_num_lines;
+ header[1] = (char) video_num_columns;
getconsxy(currcons, header+2);
while (p < HEADER_SIZE && count > 0)
{ count--; put_user(header[p++], buf++); }
@@ -142,15 +128,23 @@ vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
p -= HEADER_SIZE;
org = screen_pos(currcons, p/2, viewed);
if ((p & 1) && count > 0)
- { count--; put_user(func_scr_readw(org++) >> 8, buf++); }
+#ifdef __BIG_ENDIAN
+ { count--; put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++); }
+#else
+ { count--; put_user(vcs_scr_readw(currcons, org++) >> 8, buf++); }
+#endif
}
while (count > 1) {
- put_user(func_scr_readw(org++), (unsigned short *) buf);
+ put_user(vcs_scr_readw(currcons, org++), (unsigned short *) buf);
buf += 2;
count -= 2;
}
if (count > 0)
- put_user(func_scr_readw(org) & 0xff, buf++);
+#ifdef __BIG_ENDIAN
+ put_user(vcs_scr_readw(currcons, org) >> 8, buf++);
+#else
+ put_user(vcs_scr_readw(currcons, org) & 0xff, buf++);
+#endif
}
read = buf - buf0;
*ppos += read;
@@ -165,11 +159,11 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
long p = *ppos;
long viewed, attr, size, written;
const char *buf0;
- unsigned short *org = NULL;
+ u16 *org0 = NULL, *org = NULL;
attr = (currcons & 128);
currcons = (currcons & 127);
- disable_bh( CONSOLE_BH );
+ disable_bh(CONSOLE_BH);
if (currcons == 0) {
currcons = fg_console;
viewed = 1;
@@ -188,12 +182,12 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
buf0 = buf;
if (!attr) {
- org = screen_pos(currcons, p, viewed);
+ org0 = org = screen_pos(currcons, p, viewed);
while (count > 0) {
unsigned char c;
count--;
get_user(c, (const unsigned char*)buf++);
- func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
org++;
}
} else {
@@ -206,35 +200,41 @@ vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
putconsxy(currcons, header+2);
}
if (count > 0) {
- p -= HEADER_SIZE;
- org = screen_pos(currcons, p/2, viewed);
+ p -= HEADER_SIZE;
+ org0 = org = screen_pos(currcons, p/2, viewed);
if ((p & 1) && count > 0) {
char c;
count--;
get_user(c,buf++);
- func_scr_writew((c << 8) |
- (func_scr_readw(org) & 0xff), org);
+#ifdef __BIG_ENDIAN
+ vcs_scr_writew(currcons, c |
+ (vcs_scr_readw(currcons, org) & 0xff00), org);
+#else
+ vcs_scr_writew(currcons, (c << 8) |
+ (vcs_scr_readw(currcons, org) & 0xff), org);
+#endif
org++;
}
}
while (count > 1) {
unsigned short w;
get_user(w, (const unsigned short *) buf);
- func_scr_writew(w, org++);
+ vcs_scr_writew(currcons, w, org++);
buf += 2;
count -= 2;
}
if (count > 0) {
unsigned char c;
get_user(c, (const unsigned char*)buf++);
- func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
+#ifdef __BIG_ENDIAN
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org);
+#else
+ vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
+#endif
}
}
-#ifdef CONFIG_FB_CONSOLE
- if (currcons == fg_console)
- /* Horribly inefficient if count < screen size. */
- update_screen(currcons);
-#endif
+ if (org0)
+ update_region(currcons, (unsigned long)(org0), org-org0);
written = buf - buf0;
*ppos += written;
RETURN( written );
diff --git a/drivers/char/vesa_blank.c b/drivers/char/vesa_blank.c
deleted file mode 100644
index eb957180b..000000000
--- a/drivers/char/vesa_blank.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * vesa_blank.c
- *
- * Exported functions:
- * void vesa_blank(void);
- * void vesa_unblank(void);
- * void vesa_powerdown(void);
- * void set_vesa_blanking(const unsigned long arg);
- *
- * Not all hardware reacts well to this code - activate at your own risk.
- * Activation is done using a sufficiently recent version of setterm
- * or using a tiny C program like the following.
- *
------------------------------------------------------------------------
-|#include <stdio.h>
-|#include <linux/termios.h>
-|main(int argc, char *argv[]) {
-| int fd;
-| struct { char ten, onoff; } arg;
-|
-| if (argc != 2) {
-| fprintf(stderr, "usage: setvesablank on|vsync|hsync|powerdown|off\n");
-| exit(1);
-| }
-| if ((fd = open("/dev/console", 0)) < 0)
-| fd = 0;
-| arg.ten = 10;
-| arg.onoff = 0;
-| if (!strcmp(argv[1], "on") || !strcmp(argv[1], "vsync"))
-| arg.onoff = 1;
-| else if (!strcmp(argv[1], "hsync"))
-| arg.onoff = 2;
-| else if (!strcmp(argv[1], "powerdown"))
-| arg.onoff = 3;
-| if (ioctl(fd, TIOCLINUX, &arg)) {
-| perror("setvesablank: TIOCLINUX");
-| exit(1);
-| }
-| exit(0);
-|}
------------------------------------------------------------------------
-*/
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/mm.h>
-
-extern unsigned short video_port_reg, video_port_val;
-
-/*
- * This file handles the VESA Power Saving Protocol that lets a
- * monitor be powered down whenever not needed for a longer time.
- * The VESA protocol defines:
- *
- * Mode/Status HSync VSync Video
- * -------------------------------------------
- * "On" on on active (mode 0)
- * "Suspend" {either} on off blank (mode 1)
- * { or } off on blank (mode 2)
- * "Off" off off blank (mode 3)
- *
- * Original code taken from the Power Management Utility (PMU) of
- * Huang shi chao, delivered together with many new monitor models
- * capable of the VESA Power Saving Protocol.
- *
- * Adapted to Linux by Christoph Rimek (chrimek@toppoint.de) 15-may-94.
- * A slightly adapted fragment of his README follows.
- *
- * Two-stage blanking by todd j. derr (tjd@barefoot.org) 10-oct-95.
-
-Patch (based on Linux Kernel revision 1.0) for handling the Power Saving
-feature of the new monitor generation. The code works on all these monitors
-(mine is a Smile 1506) and should run on *all* video adapter cards (change
-some i/o-addresses), although tested only on two different VGA-cards: a
-cheap Cirrus Logic (5428) and a miro Crystal 8S (S3-805).
-
-You can choose from two options:
-
-(1) Setting vesa_blanking_mode to 1 or 2.
- The code will save the current setting of your video adapters'
- register settings and then program the controller to turn off
- the vertical synchronization pulse (mode 1) or horizontal
- synchronization pulse (mode 2). Mode 1 should work with most
- monitors, but the VESA spec allows mode 2, so it's included for
- completeness. You may set this blanking interval in minutes by
- echoing the escape sequence 'ESC[9;interval]' to the terminal.
- By default this interval is set to 10 minutes.
-
- If you use one of these modes, you can also set a second interval
- by echoing the escape sequence 'ESC[14;interval]' to the terminal.
- The monitor will be turned off completely (mode 3) after being in
- suspend mode for the specified interval. An interval of 0 disables
- this feature which is the default.
-
- Both intervals may be set within the range of 0..60 minutes.
-
-(2) Setting vesa_blanking_mode to 3.
- If your monitor locally has an Off_Mode timer then you should not
- force your video card to send the OFF-signal - your monitor will
- power down by itself.
- If your monitor cannot handle this and needs the Off-signal directly,
- or if you like your monitor to power down immediately when the
- blank_timer times out, then you choose this option.
-
-On the other hand I'd recommend to not choose this second option unless
-it is absolutely necessary. Powering down a monitor to the Off_State with
-an approx. power consumption of 3-5 Watts is a rather strong action for
-the CRT and it should not be done every now and then. If the software only
-sends the signal to enter Standby mode, you have the chance to interfere
-before the monitor powers down. Do not set a too short period, if you love
-your hardware :-)) .
-
-By default vesa_blanking_mode is set to 0, thus not using any power saving
-features.
-*/
-
-#define seq_port_reg (0x3c4) /* Sequencer register select port */
-#define seq_port_val (0x3c5) /* Sequencer register value port */
-#define video_misc_rd (0x3cc) /* Video misc. read port */
-#define video_misc_wr (0x3c2) /* Video misc. write port */
-
-/* structure holding original VGA register settings */
-static struct {
- unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
- unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
- unsigned char CrtMiscIO; /* Miscellaneous register */
- unsigned char HorizontalTotal; /* CRT-Controller:00h */
- unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
- unsigned char StartHorizRetrace; /* CRT-Controller:04h */
- unsigned char EndHorizRetrace; /* CRT-Controller:05h */
- unsigned char Overflow; /* CRT-Controller:07h */
- unsigned char StartVertRetrace; /* CRT-Controller:10h */
- unsigned char EndVertRetrace; /* CRT-Controller:11h */
- unsigned char ModeControl; /* CRT-Controller:17h */
- unsigned char ClockingMode; /* Seq-Controller:01h */
-} vga;
-
-#define VESA_NO_BLANKING 0
-#define VESA_VSYNC_SUSPEND 1
-#define VESA_HSYNC_SUSPEND 2
-#define VESA_POWERDOWN (VESA_HSYNC_SUSPEND | VESA_VSYNC_SUSPEND)
-
-#define DEFAULT_VESA_BLANKING_MODE VESA_NO_BLANKING
-
-static int vesa_blanking_mode = DEFAULT_VESA_BLANKING_MODE;
-static int suspend_vesa_blanking_mode = DEFAULT_VESA_BLANKING_MODE;
-static int vesa_blanked = 0;
-
-/* routine to blank a vesa screen */
-void vesa_blank(void)
-{
- int mode;
-
- if((mode = vesa_blanking_mode) == 0)
- return;
-
- /* save original values of VGA controller registers */
- if(!vesa_blanked) {
- cli();
- vga.SeqCtrlIndex = inb_p(seq_port_reg);
- vga.CrtCtrlIndex = inb_p(video_port_reg);
- vga.CrtMiscIO = inb_p(video_misc_rd);
- sti();
-
- outb_p(0x00,video_port_reg); /* HorizontalTotal */
- vga.HorizontalTotal = inb_p(video_port_val);
- outb_p(0x01,video_port_reg); /* HorizDisplayEnd */
- vga.HorizDisplayEnd = inb_p(video_port_val);
- outb_p(0x04,video_port_reg); /* StartHorizRetrace */
- vga.StartHorizRetrace = inb_p(video_port_val);
- outb_p(0x05,video_port_reg); /* EndHorizRetrace */
- vga.EndHorizRetrace = inb_p(video_port_val);
- outb_p(0x07,video_port_reg); /* Overflow */
- vga.Overflow = inb_p(video_port_val);
- outb_p(0x10,video_port_reg); /* StartVertRetrace */
- vga.StartVertRetrace = inb_p(video_port_val);
- outb_p(0x11,video_port_reg); /* EndVertRetrace */
- vga.EndVertRetrace = inb_p(video_port_val);
- outb_p(0x17,video_port_reg); /* ModeControl */
- vga.ModeControl = inb_p(video_port_val);
- outb_p(0x01,seq_port_reg); /* ClockingMode */
- vga.ClockingMode = inb_p(seq_port_val);
- }
-
- /* assure that video is enabled */
- /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
- cli();
- outb_p(0x01,seq_port_reg);
- outb_p(vga.ClockingMode | 0x20,seq_port_val);
-
- /* test for vertical retrace in process.... */
- if ((vga.CrtMiscIO & 0x80) == 0x80)
- outb_p(vga.CrtMiscIO & 0xef,video_misc_wr);
-
- /*
- * Set <End of vertical retrace> to minimum (0) and
- * <Start of vertical Retrace> to maximum (incl. overflow)
- * Result: turn off vertical sync (VSync) pulse.
- */
- if (mode & VESA_VSYNC_SUSPEND) {
- outb_p(0x10,video_port_reg); /* StartVertRetrace */
- outb_p(0xff,video_port_val); /* maximum value */
- outb_p(0x11,video_port_reg); /* EndVertRetrace */
- outb_p(0x40,video_port_val); /* minimum (bits 0..3) */
- outb_p(0x07,video_port_reg); /* Overflow */
- outb_p(vga.Overflow | 0x84,video_port_val); /* bits 9,10 of */
- /* vert. retrace */
- }
-
- if (mode & VESA_HSYNC_SUSPEND) {
- /*
- * Set <End of horizontal retrace> to minimum (0) and
- * <Start of horizontal Retrace> to maximum
- * Result: turn off horizontal sync (HSync) pulse.
- */
- outb_p(0x04,video_port_reg); /* StartHorizRetrace */
- outb_p(0xff,video_port_val); /* maximum */
- outb_p(0x05,video_port_reg); /* EndHorizRetrace */
- outb_p(0x00,video_port_val); /* minimum (0) */
- }
-
- /* restore both index registers */
- outb_p(vga.SeqCtrlIndex,seq_port_reg);
- outb_p(vga.CrtCtrlIndex,video_port_reg);
- sti();
-
- vesa_blanked = mode;
-}
-
-/* routine to unblank a vesa screen */
-void vesa_unblank(void)
-{
- if (!vesa_blanked)
- return;
-
- /* restore original values of VGA controller registers */
- cli();
- outb_p(vga.CrtMiscIO,video_misc_wr);
-
- outb_p(0x00,video_port_reg); /* HorizontalTotal */
- outb_p(vga.HorizontalTotal,video_port_val);
- outb_p(0x01,video_port_reg); /* HorizDisplayEnd */
- outb_p(vga.HorizDisplayEnd,video_port_val);
- outb_p(0x04,video_port_reg); /* StartHorizRetrace */
- outb_p(vga.StartHorizRetrace,video_port_val);
- outb_p(0x05,video_port_reg); /* EndHorizRetrace */
- outb_p(vga.EndHorizRetrace,video_port_val);
- outb_p(0x07,video_port_reg); /* Overflow */
- outb_p(vga.Overflow,video_port_val);
- outb_p(0x10,video_port_reg); /* StartVertRetrace */
- outb_p(vga.StartVertRetrace,video_port_val);
- outb_p(0x11,video_port_reg); /* EndVertRetrace */
- outb_p(vga.EndVertRetrace,video_port_val);
- outb_p(0x17,video_port_reg); /* ModeControl */
- outb_p(vga.ModeControl,video_port_val);
- outb_p(0x01,seq_port_reg); /* ClockingMode */
- outb_p(vga.ClockingMode,seq_port_val);
-
- /* restore index/control registers */
- outb_p(vga.SeqCtrlIndex,seq_port_reg);
- outb_p(vga.CrtCtrlIndex,video_port_reg);
- sti();
-
- vesa_blanked = 0;
-}
-
-void set_vesa_blanking(const unsigned long arg)
-{
- unsigned char *argp = (unsigned char *)(arg + 1);
- unsigned int mode;
-
- if (verify_area(VERIFY_READ, argp, 1))
- return;
-
- get_user(mode, argp);
- vesa_blanking_mode = suspend_vesa_blanking_mode =
- ((mode <= VESA_POWERDOWN) ? mode : DEFAULT_VESA_BLANKING_MODE);
-}
-
-void vesa_powerdown(void)
-{
- if(vesa_blanking_mode == VESA_VSYNC_SUSPEND
- || vesa_blanking_mode == VESA_HSYNC_SUSPEND)
- {
- vesa_blanking_mode = VESA_POWERDOWN;
- vesa_blank();
- vesa_blanking_mode = suspend_vesa_blanking_mode;
- }
-}
diff --git a/drivers/char/vga.c b/drivers/char/vga.c
deleted file mode 100644
index 3c932ad7c..000000000
--- a/drivers/char/vga.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * linux/drivers/char/vga.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- * 1995 Jay Estabrook
- */
-
-/*
- * vga.c
- *
- * This module exports the console low-level io support for VGA
- *
- * 'int con_get_font(char *data)'
- * 'int con_set_font(char *data, int ch512)'
- * 'int con_adjust_height(int fontheight)'
- *
- * 'int con_get_cmap(char *)'
- * 'int con_set_cmap(char *)'
- *
- * 'int reset_palette(int currcons)'
- * 'void set_palette(void)'
- *
- * User definable mapping table and font loading by Eugene G. Crosser,
- * <crosser@pccross.msk.su>
- *
- * Improved loadable font/UTF-8 support by H. Peter Anvin
- * Feb-Sep 1995 <peter.anvin@linux.org>
- *
- * Colour palette handling, by Simon Tatham
- * 17-Jun-95 <sgt20@cam.ac.uk>
- *
- * if 512 char mode is already enabled don't re-enable it,
- * because it causes screen to flicker, by Mitja Horvat
- * 5-May-96 <mitja.horvat@guest.arnes.si>
- *
- * Use 2 outw instead of 4 outb_p to reduce erroneous text
- * flashing on RHS of screen during heavy console scrolling .
- * Oct 1996, Paul Gortmaker.
- *
- */
-
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-
-#ifdef __mips__
-#include <asm/bootinfo.h>
-#include <asm/sni.h>
-/*
- * The video control ports are mapped at virtual address
- * 0xe0200000 for the onboard S3 card
- */
-#define PORT_BASE video_port_base
-unsigned long video_port_base;
-#endif
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/console_struct.h>
-
-#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
-#define CAN_LOAD_PALETTE /* undefine if the user must not do this */
-
-#define dac_reg (0x3c8)
-#define dac_val (0x3c9)
-
-#ifdef __powerpc__
-#define VGA_OFFSET 0xC0000000;
-#else
-#define VGA_OFFSET 0x0
-#endif
-
-/*
- * By replacing the four outb_p with two back to back outw, we can reduce
- * the window of opportunity to see text mislocated to the RHS of the
- * console during heavy scrolling activity. However there is the remote
- * possibility that some pre-dinosaur hardware won't like the back to back
- * I/O. Since the Xservers get away with it, we should be able to as well.
- */
-static inline void write_vga(unsigned char reg, unsigned int val)
-{
-#ifndef SLOW_VGA
- unsigned int v1, v2;
-
- v1 = reg + (val & 0xff00);
- v2 = reg + 1 + ((val << 8) & 0xff00);
- outw(v1, video_port_reg);
- outw(v2, video_port_reg);
-#else
- outb_p(reg, video_port_reg);
- outb_p(val >> 8, video_port_val);
- outb_p(reg+1, video_port_reg);
- outb_p(val & 0xff, video_port_val);
-#endif
-}
-
-void
-set_palette (void)
-{
- int i, j ;
-
- if ((video_type != VIDEO_TYPE_VGAC && video_type != VIDEO_TYPE_PICA_S3
- && video_type != VIDEO_TYPE_SNI_RM)
- || console_blanked || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
- return ;
-
- for (i=j=0; i<16; i++) {
- outb_p (color_table[i], dac_reg) ;
- outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
- outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
- outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
- }
-}
-
-void
-__set_origin(unsigned short offset)
-{
- clear_selection();
-
- __origin = offset;
- write_vga(12, offset);
-}
-
-/*
- * Put the cursor just beyond the end of the display adaptor memory.
- */
-void
-hide_cursor(void)
-{
- /* This is inefficient, we could just put the cursor at 0xffff,
- but perhaps the delays due to the inefficiency are useful for
- some hardware... */
- write_vga(14, (video_mem_term - video_mem_base - 1)>>1);
-}
-
-void
-set_cursor(int currcons)
-{
- if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
- return;
- if (__real_origin != __origin)
- __set_origin(__real_origin);
- if (deccm) {
- write_vga(14, (pos - video_mem_base)>>1);
- } else
- hide_cursor();
-}
-
-__initfunc(int con_is_present(void))
-{
- unsigned short saved;
- unsigned short *p;
-
- /*
- * Find out if there is a graphics card present.
- * Are there smarter methods around?
- */
- p = (unsigned short *) video_mem_base;
- saved = scr_readw(p);
- scr_writew(0xAA55, p);
- if (scr_readw(p) != 0xAA55) {
- scr_writew(saved, p);
- return 0;
- }
- scr_writew(0x55AA, p);
- if (scr_readw(p) != 0x55AA) {
- scr_writew(saved, p);
- return 0;
- }
- scr_writew(saved, p);
- return 1;
-}
-
-__initfunc(unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc))
-{
-#ifdef CONFIG_ACER_PICA_61
- /*
- * This type of video is only available as 64bit on board display for
- * MIPS machines based on the PICA chipset. If the loader has detected
- * such a machine assume that we use that type of video.
- */
- if (mips_machgroup == MACH_GROUP_JAZZ
- && mips_machtype == MACH_ACER_PICA_61)
- {
- can_do_color = 1;
- video_port_base = 0xe0200000;
- video_port_reg = 0x3d4;
- video_port_val = 0x3d5;
- video_type = VIDEO_TYPE_PICA_S3;
- video_mem_base = mips_vram_base;
- video_mem_term = video_mem_base + 0x8000;
- *display_desc = "PICA-S3";
- /*
- * Don't request a region - the video ports are outside of
- * the normal port address range.
- * Initialize the cursor; the rest of the console code assumes
- * this has already been done by the BIOS ...
- */
- outb_p(10, video_port_reg);
- outb_p(14, video_port_val);
- outb_p(11, video_port_reg);
- outb_p(15, video_port_val);
- }
- else
-#endif
-#ifdef CONFIG_SNI_RM200_PCI
- if (mips_machgroup == MACH_GROUP_SNI_RM
- && mips_machtype == MACH_SNI_RM200_PCI)
- {
- can_do_color = 1;
- video_port_base = SNI_PORT_BASE;
- video_port_reg = 0x3d4;
- video_port_val = 0x3d5;
- video_type = VIDEO_TYPE_SNI_RM;
- video_mem_base = 0xb00b8000;
- video_mem_term = video_mem_base + 0x8000;
- *display_desc = "VGA+";
- /*
- * The SNI machine is pretty much a simple RISC PC; we
- * need to request the ports.
- */
- request_region(0x3c0,32,"vga+");
- }
- else
-#endif
- if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
- {
- video_mem_base = 0xb0000 + VGA_OFFSET;
- video_port_reg = 0x3b4;
- video_port_val = 0x3b5;
- if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
- {
- video_type = VIDEO_TYPE_EGAM;
- video_mem_term = 0xb8000 + VGA_OFFSET;
- *display_desc = "EGA+";
- request_region(0x3b0,16,"ega");
- }
- else
- {
- video_type = VIDEO_TYPE_MDA;
- video_mem_term = 0xb2000 + VGA_OFFSET;
- *display_desc = "*MDA";
- request_region(0x3b0,12,"mda");
- request_region(0x3bf, 1,"mda");
- }
- }
- else /* If not, it is color. */
- {
- can_do_color = 1;
- video_mem_term = 0xb8000 + VGA_OFFSET;
- video_port_reg = 0x3d4;
- video_port_val = 0x3d5;
- if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
- {
- int i ;
-
- video_mem_term = 0xc0000 + VGA_OFFSET;
-
- if (!ORIG_VIDEO_ISVGA) {
- video_type = VIDEO_TYPE_EGAC;
- *display_desc = "EGA";
- request_region(0x3c0,32,"ega");
- } else {
- video_type = VIDEO_TYPE_VGAC;
- *display_desc = "VGA+";
- request_region(0x3c0,32,"vga+");
-
-#ifdef VGA_CAN_DO_64KB
- /*
- * get 64K rather than 32K of video RAM.
- * This doesn't actually work on all "VGA"
- * controllers (it seems like setting MM=01
- * and COE=1 isn't necessarily a good idea)
- */
- video_mem_base = 0xa0000 + VGA_OFFSET;
- video_mem_term = 0xb0000 + VGA_OFFSET;
- outb_p (6, 0x3ce) ;
- outb_p (6, 0x3cf) ;
-#endif
-
- /*
- * Normalise the palette registers, to point
- * the 16 screen colours to the first 16
- * DAC entries.
- */
-
- for (i=0; i<16; i++) {
- inb_p (0x3da) ;
- outb_p (i, 0x3c0) ;
- outb_p (i, 0x3c0) ;
- }
- outb_p (0x20, 0x3c0) ;
-
- /* now set the DAC registers back to their
- * default values */
-
- for (i=0; i<16; i++) {
- outb_p (color_table[i], 0x3c8) ;
- outb_p (default_red[i], 0x3c9) ;
- outb_p (default_grn[i], 0x3c9) ;
- outb_p (default_blu[i], 0x3c9) ;
- }
- }
- }
- else
- {
- video_type = VIDEO_TYPE_CGA;
- video_mem_term = 0xba000 + VGA_OFFSET;
- *display_desc = "*CGA";
- request_region(0x3d4,2,"cga");
- }
- }
- return kmem_start;
-}
-
-__initfunc(void
-con_type_init_finish(void))
-{
-}
-
-void
-get_scrmem(int currcons)
-{
- memcpyw((unsigned short *)vc_scrbuf[currcons],
- (unsigned short *)origin, video_screen_size);
- origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
- scr_end = video_mem_end = video_mem_start + video_screen_size;
- pos = origin + y*video_size_row + (x<<1);
-}
-
-void
-set_scrmem(int currcons, long offset)
-{
-#ifdef CONFIG_HGA
- /* This works with XFree86 1.2, 1.3 and 2.0
- This code could be extended and made more generally useful if we could
- determine the actual video mode. It appears that this should be
- possible on a genuine Hercules card, but I (WM) haven't been able to
- read from any of the required registers on my clone card.
- */
- /* This code should work with Hercules and MDA cards. */
- if (video_type == VIDEO_TYPE_MDA)
- {
- if (vcmode == KD_TEXT)
- {
- /* Ensure that the card is in text mode. */
- int i;
- static char herc_txt_tbl[12] = {
- 0x61,0x50,0x52,0x0f,0x19,6,0x19,0x19,2,0x0d,0x0b,0x0c };
- outb_p(0, 0x3bf); /* Back to power-on defaults */
- outb_p(0, 0x3b8); /* Blank the screen, select page 0, etc */
- for ( i = 0 ; i < 12 ; i++ )
- {
- outb_p(i, 0x3b4);
- outb_p(herc_txt_tbl[i], 0x3b5);
- }
- }
-#define HGA_BLINKER_ON 0x20
-#define HGA_SCREEN_ON 8
- /* Make sure that the hardware is not blanked */
- outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8);
- }
-#endif CONFIG_HGA
-
- if (video_mem_term - video_mem_base < offset + video_screen_size)
- offset = 0; /* strange ... */
- memcpyw((unsigned short *)(video_mem_base + offset),
- (unsigned short *) origin, video_screen_size);
- video_mem_start = video_mem_base;
- video_mem_end = video_mem_term;
- origin = video_mem_base + offset;
- scr_end = origin + video_screen_size;
- pos = origin + y*video_size_row + (x<<1);
- has_wrapped = 0;
-}
-
-/*
- * PIO_FONT support.
- *
- * The font loading code goes back to the codepage package by
- * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
- * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
- * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
- *
- * Change for certain monochrome monitors by Yury Shevchuck
- * (sizif@botik.yaroslavl.su).
- */
-
-#define colourmap ((char *)(0xa0000))
-/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
- should use 0xA0000 for the bwmap as well.. */
-#define blackwmap ((char *)(0xa0000))
-#define cmapsz 8192
-#define attrib_port (0x3c0)
-#define seq_port_reg (0x3c4)
-#define seq_port_val (0x3c5)
-#define gr_port_reg (0x3ce)
-#define gr_port_val (0x3cf)
-
-int
-set_get_font(char * arg, int set, int ch512)
-{
-#ifdef CAN_LOAD_EGA_FONTS
- static int ch512enabled = 0;
- int i;
- char *charmap;
- int beg;
- unsigned short video_port_status = video_port_reg + 6;
- int font_select = 0x00;
-
- /* no use to "load" CGA... */
-
- if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_VGAC
- || video_type == VIDEO_TYPE_PICA_S3
- || video_type == VIDEO_TYPE_SNI_RM) {
- charmap = colourmap;
- beg = 0x0e;
-#ifdef VGA_CAN_DO_64KB
- if (video_type == VIDEO_TYPE_VGAC ||
- video_type == VIDEO_TYPE_PICA_S3 ||
- video_type == VIDEO_TYPE_SNI_RM)
- beg = 0x06;
-#endif
- } else if (video_type == VIDEO_TYPE_EGAM) {
- charmap = blackwmap;
- beg = 0x0a;
- } else
- return -EINVAL;
-
- if (arg)
- {
- i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg,
- ch512 ? 2*cmapsz : cmapsz);
- if (i)
- return i;
- }
- else
- ch512 = 0; /* Default font is always 256 */
-
-#ifdef BROKEN_GRAPHICS_PROGRAMS
- /*
- * All fonts are loaded in slot 0 (0:1 for 512 ch)
- */
-
- if (!arg)
- return -EINVAL; /* Return to default font not supported */
-
- video_font_is_default = 0;
- font_select = ch512 ? 0x04 : 0x00;
-#else
- /*
- * The default font is kept in slot 0 and is never touched.
- * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
- */
-
- if (set)
- {
- video_font_is_default = !arg;
- font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
- }
-
- if ( !video_font_is_default )
- charmap += 4*cmapsz;
-#endif
-
- cli();
- outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
- outb_p( 0x01, seq_port_val ); /* Synchronous reset */
- outb_p( 0x02, seq_port_reg );
- outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */
- outb_p( 0x04, seq_port_reg );
- outb_p( 0x07, seq_port_val ); /* Sequential addressing */
- outb_p( 0x00, seq_port_reg );
- outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */
-
- outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
- outb_p( 0x02, gr_port_val ); /* select map 2 */
- outb_p( 0x05, gr_port_reg );
- outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
- outb_p( 0x06, gr_port_reg );
- outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
- sti();
-
- if (arg)
- {
- if (set)
- for (i=0; i<cmapsz ; i++) {
- char c;
- get_user(c, arg + i);
- scr_writeb(c, charmap + i);
- }
- else
- for (i=0; i<cmapsz ; i++)
- put_user(scr_readb(charmap + i), arg + i);
-
-
- /*
- * In 512-character mode, the character map is not contiguous if
- * we want to remain EGA compatible -- which we do
- */
-
- if (ch512)
- {
- charmap += 2*cmapsz;
- arg += cmapsz;
- if (set)
- for (i=0; i<cmapsz ; i++) {
- char c;
- get_user(c, arg+i);
- scr_writeb(c, charmap+i);
- }
- else
- for (i=0; i<cmapsz ; i++)
- put_user(scr_readb(charmap+i), arg+i);
- }
- }
-
- cli();
- outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
- outb_p( 0x01, seq_port_val ); /* Synchronous reset */
- outb_p( 0x02, seq_port_reg );
- outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */
- outb_p( 0x04, seq_port_reg );
- outb_p( 0x03, seq_port_val ); /* odd-even addressing */
- if (set)
- {
- outb_p( 0x03, seq_port_reg ); /* Character Map Select */
- outb_p( font_select, seq_port_val );
- }
- outb_p( 0x00, seq_port_reg );
- outb_p( 0x03, seq_port_val ); /* clear synchronous reset */
-
- outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
- outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */
- outb_p( 0x05, gr_port_reg );
- outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
- outb_p( 0x06, gr_port_reg );
- outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */
-
- /* if 512 char mode is already enabled don't re-enable it. */
- if ((set)&&(ch512!=ch512enabled)) /* attribute controller */
- {
- ch512enabled=ch512;
- /* 256-char: enable intensity bit
- 512-char: disable intensity bit */
- inb_p( video_port_status ); /* clear address flip-flop */
- outb_p ( 0x12, attrib_port ); /* color plane enable register */
- outb_p ( ch512 ? 0x07 : 0x0f, attrib_port );
- /* Wilton (1987) mentions the following; I don't know what
- it means, but it works, and it appears necessary */
- inb_p( video_port_status );
- outb_p ( 0x20, attrib_port );
- }
- sti();
-
- return 0;
-#else
- return -EINVAL;
-#endif
-}
-
-/*
- * Adjust the screen to fit a font of a certain height
- *
- * Returns < 0 for error, 0 if nothing changed, and the number
- * of lines on the adjusted console if changed.
- */
-int
-con_adjust_height(unsigned long fontheight)
-{
- int rows, maxscan;
- unsigned char ovr, vde, fsr, curs, cure;
-
- if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC &&
- video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM &&
- video_type != VIDEO_TYPE_PICA_S3 &&
- video_type != VIDEO_TYPE_SNI_RM))
- return -EINVAL;
-
- if ( fontheight == video_font_height || fontheight == 0 )
- return 0;
-
- video_font_height = fontheight;
-
- rows = video_scan_lines/fontheight; /* Number of video rows we end up with */
- maxscan = rows*fontheight - 1; /* Scan lines to actually display-1 */
-
- /* Reprogram the CRTC for the new font size
- Note: the attempt to read the overflow register will fail
- on an EGA, but using 0xff for the previous value appears to
- be OK for EGA text modes in the range 257-512 scan lines, so I
- guess we don't need to worry about it.
-
- The same applies for the spill bits in the font size and cursor
- registers; they are write-only on EGA, but it appears that they
- are all don't care bits on EGA, so I guess it doesn't matter. */
-
- cli();
- outb_p( 0x07, video_port_reg ); /* CRTC overflow register */
- ovr = inb_p(video_port_val);
- outb_p( 0x09, video_port_reg ); /* Font size register */
- fsr = inb_p(video_port_val);
- outb_p( 0x0a, video_port_reg ); /* Cursor start */
- curs = inb_p(video_port_val);
- outb_p( 0x0b, video_port_reg ); /* Cursor end */
- cure = inb_p(video_port_val);
- sti();
-
- vde = maxscan & 0xff; /* Vertical display end reg */
- ovr = (ovr & 0xbd) + /* Overflow register */
- ((maxscan & 0x100) >> 7) +
- ((maxscan & 0x200) >> 3);
- fsr = (fsr & 0xe0) + (fontheight-1); /* Font size register */
- curs = (curs & 0xc0) + fontheight - (fontheight < 10 ? 2 : 3);
- cure = (cure & 0xe0) + fontheight - (fontheight < 10 ? 1 : 2);
-
- cli();
- outb_p( 0x07, video_port_reg ); /* CRTC overflow register */
- outb_p( ovr, video_port_val );
- outb_p( 0x09, video_port_reg ); /* Font size */
- outb_p( fsr, video_port_val );
- outb_p( 0x0a, video_port_reg ); /* Cursor start */
- outb_p( curs, video_port_val );
- outb_p( 0x0b, video_port_reg ); /* Cursor end */
- outb_p( cure, video_port_val );
- outb_p( 0x12, video_port_reg ); /* Vertical display limit */
- outb_p( vde, video_port_val );
- sti();
-
- if ( rows == video_num_lines ) {
- /* Change didn't affect number of lines -- no need to scare
- the rest of the world */
- return 0;
- }
-
- vc_resize(rows, 0); /* Adjust console size */
-
- return rows;
-}
-
-int
-set_get_cmap(unsigned char * arg, int set) {
-#ifdef CAN_LOAD_PALETTE
- int i;
-
- /* no use to set colourmaps in less than colour VGA */
-
- if (video_type != VIDEO_TYPE_PICA_S3 &&
- video_type != VIDEO_TYPE_SNI_RM &&
- video_type != VIDEO_TYPE_VGAC)
- return -EINVAL;
-
- i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
- if (i)
- return i;
-
- for (i=0; i<16; i++) {
- if (set) {
- get_user(default_red[i], arg++) ;
- get_user(default_grn[i], arg++) ;
- get_user(default_blu[i], arg++) ;
- } else {
- put_user (default_red[i], arg++) ;
- put_user (default_grn[i], arg++) ;
- put_user (default_blu[i], arg++) ;
- }
- }
- if (set) {
- for (i=0; i<MAX_NR_CONSOLES; i++)
- if (vc_cons_allocated(i)) {
- int j, k ;
- for (j=k=0; j<16; j++) {
- vc_cons[i].d->vc_palette[k++] = default_red[j];
- vc_cons[i].d->vc_palette[k++] = default_grn[j];
- vc_cons[i].d->vc_palette[k++] = default_blu[j];
- }
- }
- set_palette() ;
- }
-
- return 0;
-#else
- return -EINVAL;
-#endif
-}
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index e9566da53..868ba4eb9 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -27,6 +27,10 @@
#include <asm/uaccess.h>
#include <asm/system.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
#define VIDEO_NUM_DEVICES 256
@@ -38,6 +42,7 @@ static struct video_device *video_device[VIDEO_NUM_DEVICES];
#ifdef CONFIG_VIDEO_BT848
extern int init_bttv_cards(struct video_init *);
+extern int i2c_tuner_init(struct video_init *);
#endif
#ifdef CONFIG_VIDEO_SAA5249
extern int init_saa_5249(struct video_init *);
@@ -48,9 +53,19 @@ extern int init_colour_qcams(struct video_init *);
#ifdef CONFIG_VIDEO_BWQCAM
extern int init_bw_qcams(struct video_init *);
#endif
+#ifdef CONFIG_RADIO_AZTECH
+extern int aztech_init(struct video_init *);
+#endif
+#ifdef CONFIG_RADIO_RTRACK
+extern int rtrack_init(struct video_init *);
+#endif
+#ifdef CONFIG_RADIO_SF16FMI
+extern int fmi_init(struct video_init *);
+#endif
static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
+ {"i2c-tuner", i2c_tuner_init},
{"bttv", init_bttv_cards},
#endif
#ifdef CONFIG_VIDEO_SAA5249
@@ -65,6 +80,15 @@ static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_PMS
{"PMS", init_pms_cards},
#endif
+#ifdef CONFIG_RADIO_AZTECH
+ {"Aztech", aztech_init},
+#endif
+#ifdef CONFIG_RADIO_RTRACK
+ {"RTrack", rtrack_init},
+#endif
+#ifdef CONFIG_RADIO_SF16FMI
+ {"SF16FMI", fmi_init},
+#endif
{"end", NULL}
};
@@ -77,11 +101,13 @@ static ssize_t video_read(struct file *file,
char *buf, size_t count, loff_t *ppos)
{
struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ if(vfl->read)
+ return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return -EINVAL;
}
-
/*
* Write for now does nothing. No reason it shouldnt do overlay setting
* for some boards I guess..
@@ -91,7 +117,25 @@ static ssize_t video_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
- return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ if(vfl->write)
+ return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK);
+ else
+ return 0;
+}
+
+
+/*
+ * Poll to see if we're readable, can probably be used for timing on incoming
+ * frames, etc..
+ */
+
+static unsigned int video_poll(struct file *file, poll_table * wait)
+{
+ struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)];
+ if(vfl->poll)
+ return vfl->poll(vfl, file, wait);
+ else
+ return 0;
}
/*
@@ -108,8 +152,17 @@ static int video_open(struct inode *inode, struct file *file)
return -ENODEV;
vfl=video_device[minor];
- if(vfl==NULL)
- return -ENODEV;
+ 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)
return -EBUSY;
vfl->busy=1; /* In case vfl->open sleeps */
@@ -223,12 +276,15 @@ int video_register_device(struct video_device *vfd, int type)
/* The init call may sleep so we book the slot out
then call */
MOD_INC_USE_COUNT;
- err=vfd->initialize(vfd);
- if(err<0)
+ if(vfd->initialize)
{
- video_device[i]=NULL;
- MOD_DEC_USE_COUNT;
- return err;
+ err=vfd->initialize(vfd);
+ if(err<0)
+ {
+ video_device[i]=NULL;
+ MOD_DEC_USE_COUNT;
+ return err;
+ }
}
return 0;
}
@@ -255,7 +311,7 @@ static struct file_operations video_fops=
video_read,
video_write,
NULL, /* readdir */
- NULL, /* poll */
+ video_poll, /* poll */
video_ioctl,
video_mmap,
video_open,
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 360ca915f..01c973576 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -22,6 +22,7 @@
#include <linux/malloc.h>
#include <linux/major.h>
#include <linux/fs.h>
+#include <linux/config.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -31,6 +32,10 @@
#include <linux/kbd_diacr.h>
#include <linux/selection.h>
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+
char vt_dont_switch = 0;
extern struct tty_driver console_driver;
@@ -56,39 +61,9 @@ struct vt_struct *vt_cons[MAX_NR_CONSOLES];
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
#endif
-extern int getkeycode(unsigned int scancode);
-extern int setkeycode(unsigned int scancode, unsigned int keycode);
-extern void compute_shiftstate(void);
-extern void complete_change_console(unsigned int new_console);
-extern int vt_waitactive(int vt);
-extern void do_blank_screen(int nopowersave);
-
-extern unsigned int keymap_count;
-
-/*
- * routines to load custom translation table, EGA/VGA font and
- * VGA colour palette from console.c
- */
-extern int con_set_trans_old(unsigned char * table);
-extern int con_get_trans_old(unsigned char * table);
-extern int con_set_trans_new(unsigned short * table);
-extern int con_get_trans_new(unsigned short * table);
-extern void con_clear_unimap(struct unimapinit *ui);
-extern int con_set_unimap(ushort ct, struct unipair *list);
-extern int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
-extern void con_set_default_unimap(void);
-extern int con_set_font(char * fontmap, int ch512);
-extern int con_get_font(char * fontmap);
-extern int con_set_cmap(unsigned char *cmap);
-extern int con_get_cmap(unsigned char *cmap);
-extern void reset_palette(int currcons);
-extern void set_palette(void) ;
-extern int con_adjust_height(unsigned long fontheight);
-
-extern int video_mode_512ch;
-extern unsigned long video_font_height;
-extern unsigned long default_font_height;
-extern unsigned long video_scan_lines;
+unsigned int video_font_height;
+unsigned int default_font_height;
+unsigned int video_scan_lines;
/*
* these are the valid i/o ports we're allowed to change. they map all the
@@ -138,20 +113,19 @@ kd_size_changed(int row, int col)
}
/*
- * Generates sound of some count for some number of clock ticks
- * [count = 1193180 / frequency]
+ * Generates sound of some frequency for some number of clock ticks
*
* If freq is 0, will turn off sound, else will turn it on for that time.
* If msec is 0, will return immediately, else will sleep for msec time, then
* turn sound off.
*
- * We use the BEEP_TIMER vector since we're using the same method to
- * generate sound, and we'll overwrite any beep in progress. That may
- * be something to fix later, if we like.
- *
* We also return immediately, which is what was implied within the X
* comments - KDMKTONE doesn't put the process to sleep.
*/
+
+#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__)
+ || (defined(__mips__) && !defined(CONFIG_SGI))
+
static void
kd_nosound(unsigned long ignored)
{
@@ -192,13 +166,17 @@ _kd_mksound(unsigned int hz, unsigned int ticks)
return;
}
-#ifdef CONFIG_SGI
-void _kd_nullsound(unsigned int hz, unsigned int ticks) { }
-void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_nullsound;
#else
-void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
+
+void
+_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+}
+
#endif
+void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
+
#define i (tmp.kb_index)
#define s (tmp.kb_table)
@@ -247,9 +225,12 @@ do_kdsk_ioctl(int cmd, struct kbentry *user_kbe, int perm, struct kbd_struct *kb
if (kbd->kbdmode != VC_UNICODE)
return -EINVAL;
+ /* ++Geert: non-PC keyboards may generate keycode zero */
+#if !defined(__mc68000__) && !defined(__powerpc__)
/* assignment to entry 0 only tests validity of args */
if (!i)
break;
+#endif
if (!(key_map = key_maps[s])) {
int j;
@@ -401,44 +382,42 @@ do_kdgkb_ioctl(int cmd, struct kbsentry *user_kdgkb, int perm)
static inline int
do_fontx_ioctl(int cmd, struct consolefontdesc *user_cfd, int perm)
{
- int nchar;
struct consolefontdesc cfdarg;
- int i = 0;
+ struct console_font_op op;
+ int i;
if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc)))
return -EFAULT;
- if (vt_cons[fg_console]->vc_mode != KD_TEXT)
- return -EINVAL;
switch (cmd) {
case PIO_FONTX:
if (!perm)
return -EPERM;
- if ( cfdarg.charcount == 256 ||
- cfdarg.charcount == 512 ) {
- i = con_set_font(cfdarg.chardata,
- cfdarg.charcount == 512);
- if (i)
- return i;
- i = con_adjust_height(cfdarg.charheight);
- return (i <= 0) ? i : kd_size_changed(i, 0);
- } else
- return -EINVAL;
- case GIO_FONTX:
- i = cfdarg.charcount;
- cfdarg.charcount = nchar = video_mode_512ch ? 512 : 256;
- cfdarg.charheight = video_font_height;
- __copy_to_user(user_cfd, &cfdarg,
- sizeof(struct consolefontdesc));
- if ( cfdarg.chardata )
- {
- if ( i < nchar )
- return -ENOMEM;
- return con_get_font(cfdarg.chardata);
- } else
- return 0;
+ op.op = KD_FONT_OP_SET;
+ op.flags = KD_FONT_FLAG_OLD;
+ op.width = 8;
+ op.height = cfdarg.charheight;
+ op.charcount = cfdarg.charcount;
+ op.data = cfdarg.chardata;
+ return con_font_op(fg_console, &op);
+ case GIO_FONTX: {
+ op.op = KD_FONT_OP_GET;
+ op.flags = KD_FONT_FLAG_OLD;
+ op.width = 8;
+ op.height = cfdarg.charheight;
+ op.charcount = cfdarg.charcount;
+ op.data = cfdarg.chardata;
+ i = con_font_op(fg_console, &op);
+ if (i)
+ return i;
+ cfdarg.charheight = op.height;
+ cfdarg.charcount = op.charcount;
+ if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
+ return -EFAULT;
+ return 0;
+ }
}
- return 0;
+ return -EINVAL;
}
static inline int
@@ -458,9 +437,9 @@ do_unimap_ioctl(int cmd, struct unimapdesc *user_ud,int perm)
case PIO_UNIMAP:
if (!perm)
return -EPERM;
- return con_set_unimap(tmp.entry_ct, tmp.entries);
+ return con_set_unimap(fg_console, tmp.entry_ct, tmp.entries);
case GIO_UNIMAP:
- return con_get_unimap(tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+ return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
}
return 0;
}
@@ -803,7 +782,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (arg == 0 || arg > MAX_NR_CONSOLES)
return -ENXIO;
arg--;
- i = vc_allocate(arg);
+ i = vc_allocate(arg, 0);
if (i)
return i;
set_console(arg);
@@ -855,7 +834,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
int newvt = vt_cons[console]->vt_newvt;
vt_cons[console]->vt_newvt = -1;
- i = vc_allocate(newvt);
+ i = vc_allocate(newvt, 0);
if (i)
return i;
/*
@@ -915,7 +894,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return i;
__get_user(ll, &vtsizes->v_rows);
__get_user(cc, &vtsizes->v_cols);
- i = vc_resize(ll, cc);
+ i = vc_resize_all(ll, cc);
return i ? i : kd_size_changed(ll, cc);
}
@@ -964,7 +943,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if ( clin )
video_font_height = clin;
- i = vc_resize(ll, cc);
+ i = vc_resize_all(ll, cc);
if (i)
return i;
@@ -972,30 +951,37 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return 0;
}
- case PIO_FONT:
+ case PIO_FONT: {
+ struct console_font_op op;
if (!perm)
return -EPERM;
- if (vt_cons[fg_console]->vc_mode != KD_TEXT)
- return -EINVAL;
- return con_set_font((char *)arg, 0);
- /* con_set_font() defined in console.c */
+ op.op = KD_FONT_OP_SET;
+ op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
+ op.width = 8;
+ op.height = 0;
+ op.charcount = 256;
+ op.data = (char *) arg;
+ return con_font_op(fg_console, &op);
+ }
- case GIO_FONT:
- if (vt_cons[fg_console]->vc_mode != KD_TEXT ||
- video_mode_512ch)
- return -EINVAL;
- return con_get_font((char *)arg);
- /* con_get_font() defined in console.c */
+ case GIO_FONT: {
+ struct console_font_op op;
+ op.op = KD_FONT_OP_GET;
+ op.flags = KD_FONT_FLAG_OLD;
+ op.width = 8;
+ op.height = 32;
+ op.charcount = 256;
+ op.data = (char *) arg;
+ return con_font_op(fg_console, &op);
+ }
case PIO_CMAP:
if (!perm)
return -EPERM;
return con_set_cmap((char *)arg);
- /* con_set_cmap() defined in console.c */
case GIO_CMAP:
return con_get_cmap((char *)arg);
- /* con_get_cmap() defined in console.c */
case PIO_FONTX:
case GIO_FONTX:
@@ -1005,26 +991,37 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
{
if (!perm)
return -EPERM;
- if (vt_cons[fg_console]->vc_mode != KD_TEXT)
- return -EINVAL;
#ifdef BROKEN_GRAPHICS_PROGRAMS
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
font is not saved. */
return -ENOSYS;
#else
-
- i = con_set_font(NULL, 0); /* Set font to default */
+ {
+ struct console_font_op op;
+ op.op = KD_FONT_OP_SET_DEFAULT;
+ op.data = NULL;
+ i = con_font_op(fg_console, &op);
if (i) return i;
-
- i = con_adjust_height(default_font_height);
- if ( i > 0 ) kd_size_changed(i, 0);
- con_set_default_unimap();
-
+ con_set_default_unimap(fg_console);
return 0;
+ }
#endif
}
+ case KDFONTOP: {
+ struct console_font_op op;
+ if (copy_from_user(&op, (void *) arg, sizeof(op)))
+ return -EFAULT;
+ if (!perm && op.op != KD_FONT_OP_GET)
+ return -EPERM;
+ i = con_font_op(console, &op);
+ if (i) return i;
+ if (copy_to_user((void *) arg, &op, sizeof(op)))
+ return -EFAULT;
+ return 0;
+ }
+
case PIO_SCRNMAP:
if (!perm)
return -EPERM;
@@ -1047,7 +1044,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return -EPERM;
i = copy_from_user(&ui, (void *)arg, sizeof(struct unimapinit));
if (i) return -EFAULT;
- con_clear_unimap(&ui);
+ con_clear_unimap(fg_console, &ui);
return 0;
}
@@ -1065,6 +1062,76 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return -EPERM;
vt_dont_switch = 0;
return 0;
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ case VC_GETMODE:
+ {
+ struct vc_mode mode;
+
+ i = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct vc_mode));
+ if (i == 0)
+ i = console_getmode(&mode);
+ if (i)
+ return i;
+ if (copy_to_user((void *) arg, &mode, sizeof(mode)))
+ return -EFAULT;
+ return 0;
+ }
+ case VC_SETMODE:
+ case VC_INQMODE:
+ {
+ struct vc_mode mode;
+
+ if (!perm)
+ return -EPERM;
+ i = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(struct vc_mode));
+ if (i)
+ return i;
+ if (copy_from_user(&mode, (void *) arg, sizeof(mode)))
+ return -EFAULT;
+ return console_setmode(&mode, cmd == VC_SETMODE);
+ }
+ case VC_SETCMAP:
+ {
+ unsigned char cmap[3][256], *p;
+ int n_entries, cmap_size, i, j;
+
+ if (!perm)
+ return -EPERM;
+ if (arg == (unsigned long) VC_POWERMODE_INQUIRY
+ || arg <= VESA_POWERDOWN) {
+ /* compatibility hack: VC_POWERMODE
+ was changed from 0x766a to 0x766c */
+ return console_powermode((int) arg);
+ }
+ i = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(int));
+ if (i)
+ return i;
+ if (get_user(cmap_size, (int *) arg))
+ return -EFAULT;
+ if (cmap_size % 3)
+ return -EINVAL;
+ n_entries = cmap_size / 3;
+ if ((unsigned) n_entries > 256)
+ return -EINVAL;
+ p = (unsigned char *) (arg + sizeof(int));
+ for (j = 0; j < n_entries; ++j)
+ for (i = 0; i < 3; ++i)
+ if (get_user(cmap[i][j], p++))
+ return -EFAULT;
+ return console_setcmap(n_entries, cmap[0],
+ cmap[1], cmap[2]);
+ }
+ case VC_GETCMAP:
+ /* not implemented yet */
+ return -ENOIOCTLCMD;
+ case VC_POWERMODE:
+ if (!perm)
+ return -EPERM;
+ return console_powermode((int) arg);
+#endif /* CONFIG_FB_COMPAT_XPMAC */
default:
return -ENOIOCTLCMD;
}
@@ -1127,10 +1194,6 @@ void complete_change_console(unsigned int new_console)
{
unsigned char old_vc_mode;
- if ((new_console == fg_console) || (vt_dont_switch))
- return;
- if (!vc_cons_allocated(new_console))
- return;
last_console = fg_console;
/*
@@ -1185,21 +1248,8 @@ void complete_change_console(unsigned int new_console)
/* Set the colour palette for this VT */
if (vt_cons[new_console]->vc_mode == KD_TEXT)
set_palette() ;
-
-#ifdef CONFIG_SUN_CONSOLE
- if (old_vc_mode != vt_cons[new_console]->vc_mode)
- {
- if (old_vc_mode == KD_GRAPHICS)
- {
- suncons_ops.clear_margin();
- suncons_ops.render_screen();
- suncons_ops.set_cursor(fg_console);
- }
- else
- suncons_ops.hide_cursor();
- }
-#endif
- /*
+
+ /*
* Wake anyone waiting for their VT to activate
*/
vt_wake_waitactive();
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index e48f22a0f..86ce29744 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -184,7 +184,7 @@ static ssize_t wdt_write(struct file *file, const char *buf, size_t count, loff_
}
/*
- * Read reports the temperature in farenheit
+ * Read reports the temperature in degrees Fahrenheit.
*/
static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *ptr)